Leptonica  1.83.1
Image processing and image analysis suite
colorcontent.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
151 #ifdef HAVE_CONFIG_H
152 #include <config_auto.h>
153 #endif /* HAVE_CONFIG_H */
154 
155 #include "allheaders.h"
156 
157 /* ----------------------------------------------------------------------- *
158  * Build an image of the color content, on a per-pixel basis, *
159  * as a measure of the amount of divergence of each color *
160  * component (R,G,B) from gray. *
161  * ----------------------------------------------------------------------- */
201 l_ok
203  l_int32 rref,
204  l_int32 gref,
205  l_int32 bref,
206  l_int32 mingray,
207  PIX **ppixr,
208  PIX **ppixg,
209  PIX **ppixb)
210 {
211 l_int32 w, h, i, j, wpl1, wplr, wplg, wplb;
212 l_int32 rval, gval, bval, rgdiff, rbdiff, gbdiff, maxval, colorval;
213 l_uint32 pixel;
214 l_uint32 *data1, *datar, *datag, *datab, *line1, *liner, *lineg, *lineb;
215 PIX *pix1, *pixr, *pixg, *pixb;
216 
217  if (!ppixr && !ppixg && !ppixb)
218  return ERROR_INT("no return val requested", __func__, 1);
219  if (ppixr) *ppixr = NULL;
220  if (ppixg) *ppixg = NULL;
221  if (ppixb) *ppixb = NULL;
222  if (!pixs)
223  return ERROR_INT("pixs not defined", __func__, 1);
224  if (mingray < 0) mingray = 0;
225  if (mingray > 255)
226  return ERROR_INT("mingray > 255", __func__, 1);
227 
228  /* Do the optional linear color map; this checks the ref vals */
229  if ((pix1 = pixColorShiftWhitePoint(pixs, rref, gref, bref)) == NULL)
230  return ERROR_INT("pix1 not returned", __func__, 1);
231 
232  pixr = pixg = pixb = NULL;
233  pixGetDimensions(pix1, &w, &h, NULL);
234  if (ppixr) {
235  pixr = pixCreate(w, h, 8);
236  datar = pixGetData(pixr);
237  wplr = pixGetWpl(pixr);
238  *ppixr = pixr;
239  }
240  if (ppixg) {
241  pixg = pixCreate(w, h, 8);
242  datag = pixGetData(pixg);
243  wplg = pixGetWpl(pixg);
244  *ppixg = pixg;
245  }
246  if (ppixb) {
247  pixb = pixCreate(w, h, 8);
248  datab = pixGetData(pixb);
249  wplb = pixGetWpl(pixb);
250  *ppixb = pixb;
251  }
252 
253  data1 = pixGetData(pix1);
254  wpl1 = pixGetWpl(pix1);
255  for (i = 0; i < h; i++) {
256  line1 = data1 + i * wpl1;
257  if (pixr)
258  liner = datar + i * wplr;
259  if (pixg)
260  lineg = datag + i * wplg;
261  if (pixb)
262  lineb = datab + i * wplb;
263  for (j = 0; j < w; j++) {
264  pixel = line1[j];
265  extractRGBValues(pixel, &rval, &gval, &bval);
266  if (mingray > 0) { /* dark pixels have no color value */
267  maxval = L_MAX(rval, gval);
268  maxval = L_MAX(maxval, bval);
269  if (maxval < mingray)
270  continue; /* colorval = 0 for each component */
271  }
272  rgdiff = L_ABS(rval - gval);
273  rbdiff = L_ABS(rval - bval);
274  gbdiff = L_ABS(gval - bval);
275  if (pixr) {
276  colorval = (rgdiff + rbdiff) / 2;
277  SET_DATA_BYTE(liner, j, colorval);
278  }
279  if (pixg) {
280  colorval = (rgdiff + gbdiff) / 2;
281  SET_DATA_BYTE(lineg, j, colorval);
282  }
283  if (pixb) {
284  colorval = (rbdiff + gbdiff) / 2;
285  SET_DATA_BYTE(lineb, j, colorval);
286  }
287  }
288  }
289 
290  pixDestroy(&pix1);
291  return 0;
292 }
293 
294 
295 /* ----------------------------------------------------------------------- *
296  * Find the 'amount' of color in an image, on a per-pixel basis, *
297  * as a measure of the difference of the pixel color from gray. *
298  * ----------------------------------------------------------------------- */
359 PIX *
361  l_int32 rref,
362  l_int32 gref,
363  l_int32 bref,
364  l_int32 type)
365 {
366 l_int32 w, h, i, j, wpl1, wpld;
367 l_int32 rval, gval, bval, rdist, gdist, bdist, colorval;
368 l_int32 rgdist, rbdist, gbdist, mindist, maxdist, minval, maxval;
369 l_uint32 pixel;
370 l_uint32 *data1, *datad, *line1, *lined;
371 PIX *pix1, *pixd;
372 
373  if (!pixs)
374  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
375  if (type != L_INTERMED_DIFF && type != L_AVE_MAX_DIFF_2 &&
376  type != L_MAX_DIFF)
377  return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
378 
379  /* Do the optional linear color map; this checks the ref vals */
380  if ((pix1 = pixColorShiftWhitePoint(pixs, rref, gref, bref)) == NULL)
381  return (PIX *)ERROR_PTR("pix1 not returned", __func__, NULL);
382 
383  pixGetDimensions(pix1, &w, &h, NULL);
384  pixd = pixCreate(w, h, 8);
385  datad = pixGetData(pixd);
386  wpld = pixGetWpl(pixd);
387  data1 = pixGetData(pix1);
388  wpl1 = pixGetWpl(pix1);
389  for (i = 0; i < h; i++) {
390  line1 = data1 + i * wpl1;
391  lined = datad + i * wpld;
392  for (j = 0; j < w; j++) {
393  pixel = line1[j];
394  extractRGBValues(pixel, &rval, &gval, &bval);
395  if (type == L_INTERMED_DIFF) {
396  rgdist = L_ABS(rval - gval);
397  rbdist = L_ABS(rval - bval);
398  gbdist = L_ABS(gval - bval);
399  maxdist = L_MAX(rgdist, rbdist);
400  if (gbdist >= maxdist) {
401  colorval = maxdist;
402  } else { /* gbdist is smallest or intermediate */
403  mindist = L_MIN(rgdist, rbdist);
404  colorval = L_MAX(mindist, gbdist);
405  }
406  } else if (type == L_AVE_MAX_DIFF_2) {
407  rdist = ((gval + bval ) / 2 - rval);
408  rdist = L_ABS(rdist);
409  gdist = ((rval + bval ) / 2 - gval);
410  gdist = L_ABS(gdist);
411  bdist = ((rval + gval ) / 2 - bval);
412  bdist = L_ABS(bdist);
413  colorval = L_MAX(rdist, gdist);
414  colorval = L_MAX(colorval, bdist);
415  } else { /* type == L_MAX_DIFF */
416  minval = L_MIN(rval, gval);
417  minval = L_MIN(minval, bval);
418  maxval = L_MAX(rval, gval);
419  maxval = L_MAX(maxval, bval);
420  colorval = maxval - minval;
421  }
422  SET_DATA_BYTE(lined, j, colorval);
423  }
424  }
425 
426  pixDestroy(&pix1);
427  return pixd;
428 }
429 
430 
431 /* ----------------------------------------------------------------------- *
432  * Find the fraction of pixels with "color" that are not close to black *
433  * ----------------------------------------------------------------------- */
489 l_ok
491  l_int32 darkthresh,
492  l_int32 lightthresh,
493  l_int32 diffthresh,
494  l_int32 factor,
495  l_float32 *ppixfract,
496  l_float32 *pcolorfract)
497 {
498 l_int32 i, j, w, h, wpl, rval, gval, bval, minval, maxval;
499 l_int32 total, npix, ncolor;
500 l_uint32 pixel;
501 l_uint32 *data, *line;
502 
503  if (ppixfract) *ppixfract = 0.0;
504  if (pcolorfract) *pcolorfract = 0.0;
505  if (!ppixfract || !pcolorfract)
506  return ERROR_INT("&pixfract and &colorfract not defined",
507  __func__, 1);
508  if (!pixs || pixGetDepth(pixs) != 32)
509  return ERROR_INT("pixs not defined or not 32 bpp", __func__, 1);
510 
511  pixGetDimensions(pixs, &w, &h, NULL);
512  data = pixGetData(pixs);
513  wpl = pixGetWpl(pixs);
514  npix = ncolor = total = 0;
515  for (i = 0; i < h; i += factor) {
516  line = data + i * wpl;
517  for (j = 0; j < w; j += factor) {
518  total++;
519  pixel = line[j];
520  extractRGBValues(pixel, &rval, &gval, &bval);
521  minval = L_MIN(rval, gval);
522  minval = L_MIN(minval, bval);
523  if (minval > lightthresh) /* near white */
524  continue;
525  maxval = L_MAX(rval, gval);
526  maxval = L_MAX(maxval, bval);
527  if (maxval < darkthresh) /* near black */
528  continue;
529 
530  npix++;
531  if (maxval - minval >= diffthresh)
532  ncolor++;
533  }
534  }
535 
536  if (npix == 0) {
537  L_WARNING("No pixels found for consideration\n", __func__);
538  return 0;
539  }
540  *ppixfract = (l_float32)npix / (l_float32)total;
541  *pcolorfract = (l_float32)ncolor / (l_float32)npix;
542  return 0;
543 }
544 
545 
546 /* ----------------------------------------------------------------------- *
547  * Do a linear TRC to map colors so that the three input reference *
548  * values go to white. These three numbers are typically the median *
549  * or average background values. *
550  * ----------------------------------------------------------------------- */
576 PIX *
578  l_int32 rref,
579  l_int32 gref,
580  l_int32 bref)
581 {
582 l_int32 w, h, i, j, wpl1, wpl2, rval, gval, bval;
583 l_int32 *rtab, *gtab, *btab;
584 l_uint32 pixel;
585 l_uint32 *data1, *data2, *line1, *line2;
586 NUMA *nar, *nag, *nab;
587 PIX *pix1, *pix2;
588 PIXCMAP *cmap;
589 
590  if (!pixs)
591  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
592 
593  cmap = pixGetColormap(pixs);
594  if (!cmap && pixGetDepth(pixs) != 32)
595  return (PIX *)ERROR_PTR("pixs neither cmapped nor 32 bpp",
596  __func__, NULL);
597  if (cmap)
599  else
600  pix1 = pixClone(pixs);
601 
602  if (!rref && !gref && !bref) /* all 0; no transform requested */
603  return pix1;
604 
605  /* Some ref values are < 0, or some (but not all) are 0 */
606  if ((rref < 0 || gref < 0 || bref < 0) || (rref * gref * bref == 0)) {
607  L_WARNING("invalid set of ref values\n", __func__);
608  return pix1;
609  }
610 
611  /* All white point ref values > 0; do transformation */
612  pixGetDimensions(pix1, &w, &h, NULL);
613  pix2 = pixCreate(w, h, 32);
614  data1 = pixGetData(pix1);
615  wpl1 = pixGetWpl(pix1);
616  data2 = pixGetData(pix2);
617  wpl2 = pixGetWpl(pix2);
618  nar = numaGammaTRC(1.0, 0, rref);
619  rtab = numaGetIArray(nar);
620  nag = numaGammaTRC(1.0, 0, gref);
621  gtab = numaGetIArray(nag);
622  nab = numaGammaTRC(1.0, 0, bref);
623  btab = numaGetIArray(nab);
624  for (i = 0; i < h; i++) {
625  line1 = data1 + i * wpl1;
626  line2 = data2 + i * wpl2;
627  for (j = 0; j < w; j++) {
628  pixel = line1[j];
629  extractRGBValues(pixel, &rval, &gval, &bval);
630  rval = rtab[rval];
631  gval = gtab[gval];
632  bval = btab[bval];
633  composeRGBPixel(rval, gval, bval, line2 + j);
634  }
635  }
636  numaDestroy(&nar);
637  numaDestroy(&nag);
638  numaDestroy(&nab);
639  LEPT_FREE(rtab);
640  LEPT_FREE(gtab);
641  LEPT_FREE(btab);
642  pixDestroy(&pix1);
643  return pix2;
644 }
645 
646 
647 /* ----------------------------------------------------------------------- *
648  * Generate a mask over pixels that have sufficient color and *
649  * are not too close to gray pixels. *
650  * ----------------------------------------------------------------------- */
679 PIX *
681  l_int32 threshdiff,
682  l_int32 mindist)
683 {
684 l_int32 w, h, d, i, j, wpls, wpld, size;
685 l_int32 rval, gval, bval, minval, maxval;
686 l_uint32 *datas, *datad, *lines, *lined;
687 PIX *pixc, *pixd;
688 PIXCMAP *cmap;
689 
690  if (!pixs)
691  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
692  pixGetDimensions(pixs, &w, &h, &d);
693 
694  cmap = pixGetColormap(pixs);
695  if (!cmap && d != 32)
696  return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", __func__, NULL);
697  if (cmap)
699  else
700  pixc = pixClone(pixs);
701  if (!pixc || pixGetDepth(pixc) != 32) {
702  pixDestroy(&pixc);
703  return (PIX *)ERROR_PTR("rgb pix not made", __func__, NULL);
704  }
705 
706  pixd = pixCreate(w, h, 1);
707  datad = pixGetData(pixd);
708  wpld = pixGetWpl(pixd);
709  datas = pixGetData(pixc);
710  wpls = pixGetWpl(pixc);
711  for (i = 0; i < h; i++) {
712  lines = datas + i * wpls;
713  lined = datad + i * wpld;
714  for (j = 0; j < w; j++) {
715  extractRGBValues(lines[j], &rval, &gval, &bval);
716  minval = L_MIN(rval, gval);
717  minval = L_MIN(minval, bval);
718  maxval = L_MAX(rval, gval);
719  maxval = L_MAX(maxval, bval);
720  if (maxval - minval >= threshdiff)
721  SET_DATA_BIT(lined, j);
722  }
723  }
724 
725  if (mindist > 1) {
726  size = 2 * (mindist - 1) + 1;
727  pixErodeBrick(pixd, pixd, size, size);
728  }
729 
730  pixDestroy(&pixc);
731  return pixd;
732 }
733 
734 
735 /* ----------------------------------------------------------------------- *
736  * Generate a mask over dark pixels with little color *
737  * ----------------------------------------------------------------------- */
759 PIX *
761  l_int32 maxlimit,
762  l_int32 satlimit)
763 {
764 l_int32 w, h, i, j, wpls, wpld;
765 l_int32 rval, gval, bval, minrg, min, maxrg, max, sat;
766 l_uint32 *datas, *datad, *lines, *lined;
767 PIX *pixd;
768 
769  if (!pixs || pixGetDepth(pixs) != 32)
770  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
771  if (maxlimit < 0 || maxlimit > 255)
772  return (PIX *)ERROR_PTR("invalid maxlimit", __func__, NULL);
773  if (satlimit < 1)
774  return (PIX *)ERROR_PTR("invalid satlimit", __func__, NULL);
775 
776  pixGetDimensions(pixs, &w, &h, NULL);
777  datas = pixGetData(pixs);
778  wpls = pixGetWpl(pixs);
779  if ((pixd = pixCreate(w, h, 1)) == NULL)
780  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
781  datad = pixGetData(pixd);
782  wpld = pixGetWpl(pixd);
783 
784  for (i = 0; i < h; i++) {
785  lines = datas + i * wpls;
786  lined = datad + i * wpld;
787  for (j = 0; j < w; j++) {
788  extractRGBValues(lines[j], &rval, &gval, &bval);
789  minrg = L_MIN(rval, gval);
790  min = L_MIN(minrg, bval);
791  maxrg = L_MAX(rval, gval);
792  max = L_MAX(maxrg, bval);
793  sat = max - min;
794  if (max <= maxlimit && sat <= satlimit)
795  SET_DATA_BIT(lined, j);
796  }
797  }
798  return pixd;
799 }
800 
801 
802 /* ----------------------------------------------------------------------- *
803  * Generate a mask over pixels that have RGB color components *
804  * within the prescribed range (a cube in RGB color space) *
805  * ----------------------------------------------------------------------- */
815 PIX *
817  l_int32 rmin,
818  l_int32 rmax,
819  l_int32 gmin,
820  l_int32 gmax,
821  l_int32 bmin,
822  l_int32 bmax)
823 {
824 l_int32 w, h, d, i, j, wpls, wpld;
825 l_int32 rval, gval, bval;
826 l_uint32 *datas, *datad, *lines, *lined;
827 PIX *pixc, *pixd;
828 PIXCMAP *cmap;
829 
830  if (!pixs)
831  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
832  pixGetDimensions(pixs, &w, &h, &d);
833 
834  cmap = pixGetColormap(pixs);
835  if (!cmap && d != 32)
836  return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", __func__, NULL);
837  if (cmap)
839  else
840  pixc = pixClone(pixs);
841 
842  pixd = pixCreate(w, h, 1);
843  datad = pixGetData(pixd);
844  wpld = pixGetWpl(pixd);
845  datas = pixGetData(pixc);
846  wpls = pixGetWpl(pixc);
847  for (i = 0; i < h; i++) {
848  lines = datas + i * wpls;
849  lined = datad + i * wpld;
850  for (j = 0; j < w; j++) {
851  extractRGBValues(lines[j], &rval, &gval, &bval);
852  if (rval < rmin || rval > rmax) continue;
853  if (gval < gmin || gval > gmax) continue;
854  if (bval < bmin || bval > bmax) continue;
855  SET_DATA_BIT(lined, j);
856  }
857  }
858 
859  pixDestroy(&pixc);
860  return pixd;
861 }
862 
863 
864 /* ----------------------------------------------------------------------- *
865  * Determine if there are significant color regions in a page image *
866  * ----------------------------------------------------------------------- */
932 l_ok
934  PIX *pixm,
935  l_int32 factor,
936  l_int32 lightthresh,
937  l_int32 darkthresh,
938  l_int32 mindiff,
939  l_int32 colordiff,
940  l_float32 edgefract,
941  l_float32 *pcolorfract,
942  PIX **pcolormask1,
943  PIX **pcolormask2,
944  PIXA *pixadb)
945 {
946 l_int32 w, h, count, rval, gval, bval, aveval, proceed;
947 l_float32 ratio;
948 l_uint32 *carray;
949 BOXA *boxa1, *boxa2;
950 PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pixm1, *pixm2, *pixm3;
951 
952  if (pcolormask1) *pcolormask1 = NULL;
953  if (pcolormask2) *pcolormask2 = NULL;
954  if (!pcolorfract)
955  return ERROR_INT("&colorfract not defined", __func__, 1);
956  *pcolorfract = 0.0;
957  if (!pixs || pixGetDepth(pixs) != 32)
958  return ERROR_INT("pixs not defined or not 32 bpp", __func__, 1);
959  if (factor < 1) factor = 1;
960  if (lightthresh < 0) lightthresh = 210; /* defaults */
961  if (darkthresh < 0) darkthresh = 70;
962  if (mindiff < 0) mindiff = 10;
963  if (colordiff < 0) colordiff = 90;
964  if (edgefract < 0.0 || edgefract > 1.0) edgefract = 0.05;
965 
966  /* Check if pixm covers most of the image. If so, just return. */
967  if (pixm) {
968  pixForegroundFraction(pixm, &ratio);
969  if (ratio > 0.7) {
970  if (pixadb) L_INFO("pixm has big fg: %f5.2\n", __func__, ratio);
971  return 0;
972  }
973  }
974 
975  /* Get the light background color. Use the average component value
976  * and select the lightest of 10 buckets. Require that it is
977  * reddish and, using lightthresh, not too dark. */
978  pixGetRankColorArray(pixs, 10, L_SELECT_AVERAGE, factor, &carray, NULL, 0);
979  if (!carray)
980  return ERROR_INT("rank color array not made", __func__, 1);
981  extractRGBValues(carray[9], &rval, &gval, &bval);
982  if (pixadb) L_INFO("lightest background color: (r,g,b) = (%d,%d,%d)\n",
983  __func__, rval, gval, bval);
984  proceed = TRUE;
985  if ((rval < bval - 2) || (rval < gval - 2)) {
986  if (pixadb) L_INFO("background not reddish\n", __func__);
987  proceed = FALSE;
988  }
989  aveval = (rval + gval + bval) / 3;
990  if (aveval < lightthresh) {
991  if (pixadb) L_INFO("background too dark\n", __func__);
992  proceed = FALSE;
993  }
994  if (pixadb) {
995  pix1 = pixDisplayColorArray(carray, 10, 120, 3, 6);
996  pixaAddPix(pixadb, pix1, L_INSERT);
997  }
998  LEPT_FREE(carray);
999  if (proceed == FALSE) return 0;
1000 
1001  /* Make a mask pixm1 over the dark pixels in the image:
1002  * convert to gray using the average of the components;
1003  * threshold using darkthresh; do a small dilation;
1004  * combine with pixm. */
1005  pix1 = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33);
1006  if (pixadb) pixaAddPix(pixadb, pix1, L_COPY);
1007  pixm1 = pixThresholdToBinary(pix1, darkthresh);
1008  pixDilateBrick(pixm1, pixm1, 7, 7);
1009  if (pixadb) pixaAddPix(pixadb, pixm1, L_COPY);
1010  if (pixm) {
1011  pixOr(pixm1, pixm1, pixm);
1012  if (pixadb) pixaAddPix(pixadb, pixm1, L_COPY);
1013  }
1014  pixDestroy(&pix1);
1015 
1016  /* Make masks over pixels that are bluish, or greenish, or
1017  have a very large color saturation (max - min) value. */
1018  pixm2 = pixConvertRGBToBinaryArb(pixs, -1.0, 0.0, 1.0, mindiff,
1019  L_SELECT_IF_GTE); /* b - r */
1020  if (pixadb) pixaAddPix(pixadb, pixm2, L_COPY);
1021  pix1 = pixConvertRGBToBinaryArb(pixs, -1.0, 1.0, 0.0, mindiff,
1022  L_SELECT_IF_GTE); /* g - r */
1023  if (pixadb) pixaAddPix(pixadb, pix1, L_COPY);
1024  pixOr(pixm2, pixm2, pix1);
1025  pixDestroy(&pix1);
1026  pix1 = pixConvertRGBToGrayMinMax(pixs, L_CHOOSE_MAXDIFF);
1027  pix2 = pixThresholdToBinary(pix1, colordiff);
1028  pixInvert(pix2, pix2);
1029  if (pixadb) pixaAddPix(pixadb, pix2, L_COPY);
1030  pixOr(pixm2, pixm2, pix2);
1031  if (pixadb) pixaAddPix(pixadb, pixm2, L_COPY);
1032  pixDestroy(&pix1);
1033  pixDestroy(&pix2);
1034 
1035  /* Subtract the dark pixels represented by pixm1.
1036  * pixm2 now holds all the color pixels of interest */
1037  pixSubtract(pixm2, pixm2, pixm1);
1038  pixDestroy(&pixm1);
1039  if (pixadb) pixaAddPix(pixadb, pixm2, L_COPY);
1040 
1041  /* But we're not quite finished. Remove pixels from any component
1042  * that is touching the image border. False color pixels can
1043  * sometimes be found there if the image is much darker near
1044  * the border, due to oxidation or reduced illumination. Also
1045  * remove any pixels within the normalized fraction %distfract
1046  * of the image border. */
1047  pixm3 = pixRemoveBorderConnComps(pixm2, 8);
1048  pixGetDimensions(pixm3, &w, &h, NULL);
1049  pixDestroy(&pixm2);
1050  if (edgefract > 0.0) {
1051  pix2 = pixMakeSymmetricMask(w, h, edgefract, edgefract, L_USE_INNER);
1052  pixAnd(pixm3, pixm3, pix2);
1053  pixDestroy(&pix2);
1054  }
1055  if (pixadb) pixaAddPix(pixadb, pixm3, L_COPY);
1056 
1057  /* Get the fraction of light color pixels */
1058  pixCountPixels(pixm3, &count, NULL);
1059  *pcolorfract = (l_float32)count / ((l_float32)(w) * h);
1060  if (pixadb) {
1061  if (count == 0)
1062  L_INFO("no light color pixels found\n", __func__);
1063  else
1064  L_INFO("fraction of light color pixels = %5.3f\n", __func__,
1065  *pcolorfract);
1066  }
1067 
1068  /* Debug: extract the color pixels from pixs */
1069  if (pixadb && count > 0) {
1070  /* Use pixm3 to extract the color pixels */
1071  pix3 = pixCreateTemplate(pixs);
1072  pixSetAll(pix3);
1073  pixCombineMasked(pix3, pixs, pixm3);
1074  pixaAddPix(pixadb, pix3, L_INSERT);
1075 
1076  /* Use additional filtering to extract the color pixels */
1077  pix3 = pixCloseSafeBrick(NULL, pixm3, 15, 15);
1078  pixaAddPix(pixadb, pix3, L_INSERT);
1079  pix5 = pixCreateTemplate(pixs);
1080  pixSetAll(pix5);
1081  pixCombineMasked(pix5, pixs, pix3);
1082  pixaAddPix(pixadb, pix5, L_INSERT);
1083 
1084  /* Get the combined bounding boxes of the mask components
1085  * in pix3, and extract those pixels from pixs. */
1086  boxa1 = pixConnCompBB(pix3, 8);
1087  boxa2 = boxaCombineOverlaps(boxa1, NULL);
1088  pix4 = pixCreateTemplate(pix3);
1089  pixMaskBoxa(pix4, pix4, boxa2, L_SET_PIXELS);
1090  pixaAddPix(pixadb, pix4, L_INSERT);
1091  pix5 = pixCreateTemplate(pixs);
1092  pixSetAll(pix5);
1093  pixCombineMasked(pix5, pixs, pix4);
1094  pixaAddPix(pixadb, pix5, L_INSERT);
1095  boxaDestroy(&boxa1);
1096  boxaDestroy(&boxa2);
1097  }
1098  pixaAddPix(pixadb, pixs, L_COPY);
1099 
1100  /* Optional colormask returns */
1101  if (pcolormask2 && count > 0)
1102  *pcolormask2 = pixCloseSafeBrick(NULL, pixm3, 15, 15);
1103  if (pcolormask1 && count > 0)
1104  *pcolormask1 = pixm3;
1105  else
1106  pixDestroy(&pixm3);
1107  return 0;
1108 }
1109 
1110 
1111 /* ----------------------------------------------------------------------- *
1112  * Find the number of perceptually significant gray intensities *
1113  * in a grayscale image. *
1114  * ----------------------------------------------------------------------- */
1146 l_ok
1148  l_int32 darkthresh,
1149  l_int32 lightthresh,
1150  l_float32 minfract,
1151  l_int32 factor,
1152  l_int32 *pncolors)
1153 {
1154 l_int32 i, w, h, count, mincount, ncolors;
1155 NUMA *na;
1156 
1157  if (!pncolors)
1158  return ERROR_INT("&ncolors not defined", __func__, 1);
1159  *pncolors = 0;
1160  if (!pixs || pixGetDepth(pixs) != 8)
1161  return ERROR_INT("pixs not defined or not 8 bpp", __func__, 1);
1162  if (darkthresh < 0) darkthresh = 20; /* defaults */
1163  if (lightthresh < 0) lightthresh = 236;
1164  if (minfract < 0.0) minfract = 0.0001;
1165  if (minfract > 1.0)
1166  return ERROR_INT("minfract > 1.0", __func__, 1);
1167  if (minfract >= 0.001)
1168  L_WARNING("minfract too big; likely to underestimate ncolors\n",
1169  __func__);
1170  if (lightthresh > 255 || darkthresh >= lightthresh)
1171  return ERROR_INT("invalid thresholds", __func__, 1);
1172  if (factor < 1) factor = 1;
1173 
1174  pixGetDimensions(pixs, &w, &h, NULL);
1175  mincount = (l_int32)(minfract * w * h * factor * factor);
1176  if ((na = pixGetGrayHistogram(pixs, factor)) == NULL)
1177  return ERROR_INT("na not made", __func__, 1);
1178  ncolors = 2; /* add in black and white */
1179  for (i = darkthresh; i <= lightthresh; i++) {
1180  numaGetIValue(na, i, &count);
1181  if (count >= mincount)
1182  ncolors++;
1183  }
1184 
1185  *pncolors = ncolors;
1186  numaDestroy(&na);
1187  return 0;
1188 }
1189 
1190 
1191 /* ----------------------------------------------------------------------- *
1192  * Identifies images where color quantization will cause posterization *
1193  * due to the existence of many colors in low-gradient regions. *
1194  * ----------------------------------------------------------------------- */
1267 l_ok
1269  l_int32 thresh,
1270  l_int32 *pncolors,
1271  l_int32 *piscolor,
1272  l_int32 debug)
1273 {
1274 l_int32 w, h, d, minside, factor;
1275 l_float32 pixfract, colorfract;
1276 PIX *pixt, *pixsc, *pixg, *pixe, *pixb, *pixm;
1277 PIXCMAP *cmap;
1278 
1279  if (piscolor) *piscolor = 0;
1280  if (!pncolors)
1281  return ERROR_INT("&ncolors not defined", __func__, 1);
1282  *pncolors = 0;
1283  if (!pixs)
1284  return ERROR_INT("pixs not defined", __func__, 1);
1285  if ((cmap = pixGetColormap(pixs)) != NULL) {
1286  *pncolors = pixcmapGetCount(cmap);
1287  if (piscolor)
1288  pixcmapHasColor(cmap, piscolor);
1289  return 0;
1290  }
1291 
1292  pixGetDimensions(pixs, &w, &h, &d);
1293  if (d != 8 && d != 32)
1294  return ERROR_INT("pixs not 8 or 32 bpp", __func__, 1);
1295  if (thresh <= 0)
1296  thresh = 15;
1297 
1298  /* First test if 32 bpp has any significant color; if not,
1299  * convert it to gray. Colors whose average values are within
1300  * 20 of black or 8 of white are ignored because they're not
1301  * very 'colorful'. If less than 2.5/10000 of the pixels have
1302  * significant color, consider the image to be gray. */
1303  minside = L_MIN(w, h);
1304  if (d == 8) {
1305  pixt = pixClone(pixs);
1306  } else { /* d == 32 */
1307  factor = L_MAX(1, minside / 400);
1308  pixColorFraction(pixs, 20, 248, 30, factor, &pixfract, &colorfract);
1309  if (pixfract * colorfract < 0.00025) {
1310  pixt = pixGetRGBComponent(pixs, COLOR_RED);
1311  d = 8;
1312  } else { /* d == 32 */
1313  pixt = pixClone(pixs);
1314  if (piscolor)
1315  *piscolor = 1;
1316  }
1317  }
1318 
1319  /* If the smallest side is less than 1000, do not downscale.
1320  * If it is in [1000 ... 2000), downscale by 2x. If it is >= 2000,
1321  * downscale by 4x. Factors of 2 are chosen for speed. The
1322  * actual resolution at which subsequent calculations take place
1323  * is not strongly dependent on downscaling. */
1324  factor = L_MAX(1, minside / 500);
1325  if (factor == 1)
1326  pixsc = pixCopy(NULL, pixt); /* to be sure pixs is unchanged */
1327  else if (factor == 2 || factor == 3)
1328  pixsc = pixScaleAreaMap2(pixt);
1329  else
1330  pixsc = pixScaleAreaMap(pixt, 0.25, 0.25);
1331 
1332  /* Basic edge mask generation procedure:
1333  * ~ work on a grayscale image
1334  * ~ get a 1 bpp edge mask by using an edge filter and
1335  * thresholding to get fg pixels at the edges
1336  * ~ for gray, dilate with a 3x3 brick Sel to get mask over
1337  * all pixels within a distance of 1 pixel from the nearest
1338  * edge pixel
1339  * ~ for color, dilate with a 7x7 brick Sel to get mask over
1340  * all pixels within a distance of 3 pixels from the nearest
1341  * edge pixel */
1342  if (d == 8)
1343  pixg = pixClone(pixsc);
1344  else /* d == 32 */
1345  pixg = pixConvertRGBToLuminance(pixsc);
1346  pixe = pixSobelEdgeFilter(pixg, L_ALL_EDGES);
1347  pixb = pixThresholdToBinary(pixe, thresh);
1348  pixInvert(pixb, pixb);
1349  if (d == 8)
1350  pixm = pixMorphSequence(pixb, "d3.3", 0);
1351  else
1352  pixm = pixMorphSequence(pixb, "d7.7", 0);
1353 
1354  /* Mask the near-edge pixels to white, and count the colors.
1355  * If grayscale, don't count colors within 20 levels of
1356  * black or white, and only count colors with a fraction
1357  * of at least 1/10000 of the image pixels.
1358  * If color, count the number of level 4 octcubes that
1359  * contain at least 20 pixels. These magic numbers are guesses
1360  * as to what might work, based on a small data set. Results
1361  * should not be overly sensitive to their actual values. */
1362  if (d == 8) {
1363  pixSetMasked(pixg, pixm, 0xff);
1364  if (debug) pixWrite("junkpix8.png", pixg, IFF_PNG);
1365  pixNumSignificantGrayColors(pixg, 20, 236, 0.0001, 1, pncolors);
1366  } else { /* d == 32 */
1367  pixSetMasked(pixsc, pixm, 0xffffffff);
1368  if (debug) pixWrite("junkpix32.png", pixsc, IFF_PNG);
1369  pixNumberOccupiedOctcubes(pixsc, 4, 20, -1, pncolors);
1370  }
1371 
1372  pixDestroy(&pixt);
1373  pixDestroy(&pixsc);
1374  pixDestroy(&pixg);
1375  pixDestroy(&pixe);
1376  pixDestroy(&pixb);
1377  pixDestroy(&pixm);
1378  return 0;
1379 }
1380 
1381 
1382 /* ----------------------------------------------------------------------- *
1383  * Find the number of unique colors in an image *
1384  * ----------------------------------------------------------------------- */
1407 l_ok
1409  l_int32 factor,
1410  l_int32 *pncolors)
1411 {
1412 l_int32 w, h, d, i, j, wpl, hashsize, sum, count, manycolors;
1413 l_int32 rval, gval, bval, val;
1414 l_int32 *inta;
1415 l_uint32 pixel;
1416 l_uint32 *data, *line;
1417 PIXCMAP *cmap;
1418 
1419  if (!pncolors)
1420  return ERROR_INT("&ncolors not defined", __func__, 1);
1421  *pncolors = 0;
1422  if (!pixs)
1423  return ERROR_INT("pixs not defined", __func__, 1);
1424  pixGetDimensions(pixs, &w, &h, &d);
1425  if (d != 2 && d != 4 && d != 8 && d != 32)
1426  return ERROR_INT("d not in {2, 4, 8, 32}", __func__, 1);
1427  if (factor < 1) factor = 1;
1428 
1429  data = pixGetData(pixs);
1430  wpl = pixGetWpl(pixs);
1431  sum = 0;
1432  if (d != 32) { /* grayscale */
1433  inta = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
1434  for (i = 0; i < h; i += factor) {
1435  line = data + i * wpl;
1436  for (j = 0; j < w; j += factor) {
1437  if (d == 8)
1438  val = GET_DATA_BYTE(line, j);
1439  else if (d == 4)
1440  val = GET_DATA_QBIT(line, j);
1441  else /* d == 2 */
1442  val = GET_DATA_DIBIT(line, j);
1443  inta[val] = 1;
1444  }
1445  }
1446  for (i = 0; i < 256; i++)
1447  if (inta[i]) sum++;
1448  *pncolors = sum;
1449  LEPT_FREE(inta);
1450 
1451  cmap = pixGetColormap(pixs);
1452  if (cmap && factor == 1) {
1453  count = pixcmapGetCount(cmap);
1454  if (sum != count)
1455  L_WARNING("colormap size %d differs from actual colors\n",
1456  __func__, count);
1457  }
1458  return 0;
1459  }
1460 
1461  /* 32 bpp rgb; quit if we get above 256 colors */
1462  hashsize = 5507; /* big and prime; collisions are not likely */
1463  inta = (l_int32 *)LEPT_CALLOC(hashsize, sizeof(l_int32));
1464  manycolors = 0;
1465  for (i = 0; i < h && manycolors == 0; i += factor) {
1466  line = data + i * wpl;
1467  for (j = 0; j < w; j += factor) {
1468  pixel = line[j];
1469  extractRGBValues(pixel, &rval, &gval, &bval);
1470  val = (137 * rval + 269 * gval + 353 * bval) % hashsize;
1471  if (inta[val] == 0) {
1472  inta[val] = 1;
1473  sum++;
1474  if (sum > 256) {
1475  manycolors = 1;
1476  break;
1477  }
1478  }
1479  }
1480  }
1481  LEPT_FREE(inta);
1482 
1483  if (manycolors == 0) {
1484  *pncolors = sum;
1485  return 0;
1486  }
1487 
1488  /* More than 256 colors in RGB image; count all the pixels */
1489  return pixCountRGBColorsByHash(pixs, pncolors);
1490 }
1491 
1492 
1493 /* ----------------------------------------------------------------------- *
1494  * Lossless conversion of RGB image to colormapped *
1495  * ----------------------------------------------------------------------- */
1508 PIX *
1510 {
1511 l_int32 w, h, d, i, j, wpls, wpld, hashsize, hashval, ncolors, index;
1512 l_int32 rval, gval, bval, val;
1513 l_int32 *hasha1, *hasha2;
1514 l_uint32 pixel;
1515 l_uint32 *datas, *lines, *datad, *lined;
1516 PIX *pixd;
1517 PIXCMAP *cmap;
1518 
1519  if (!pixs || pixGetDepth(pixs) != 32)
1520  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
1521 
1522  pixNumColors(pixs, 1, &ncolors);
1523  if (ncolors > 256) {
1524  L_ERROR("too many colors found: %d\n", __func__, ncolors);
1525  return NULL;
1526  }
1527 
1528  pixGetDimensions(pixs, &w, &h, NULL);
1529  if (ncolors <= 2)
1530  d = 1;
1531  else if (ncolors <= 4)
1532  d = 2;
1533  else if (ncolors <= 16)
1534  d = 4;
1535  else /* ncolors <= 256 */
1536  d = 8;
1537 
1538  if ((pixd = pixCreate(w, h, d)) == NULL)
1539  return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1540  cmap = pixcmapCreate(d);
1541  datas = pixGetData(pixs);
1542  wpls = pixGetWpl(pixs);
1543  datad = pixGetData(pixd);
1544  wpld = pixGetWpl(pixd);
1545 
1546  /* hasha1 is a 1/0 indicator array for colors seen.
1547  hasha2 holds the index into the colormap that will be
1548  generated from the colors in the order seen. This is
1549  the value inserted into pixd. */
1550  hashsize = 5507; /* big and prime; collisions are not likely */
1551  hasha1 = (l_int32 *)LEPT_CALLOC(hashsize, sizeof(l_int32));
1552  hasha2 = (l_int32 *)LEPT_CALLOC(hashsize, sizeof(l_int32));
1553  index = -1;
1554  for (i = 0; i < h; i++) {
1555  lines = datas + i * wpls;
1556  lined = datad + i * wpld;
1557  for (j = 0; j < w; j++) {
1558  pixel = lines[j];
1559  extractRGBValues(pixel, &rval, &gval, &bval);
1560  hashval = (137 * rval + 269 * gval + 353 * bval) % hashsize;
1561  if (hasha1[hashval] == 0) { /* new color */
1562  hasha1[hashval] = 1;
1563  index++;
1564  hasha2[hashval] = index;
1565  pixcmapAddColor(cmap, rval, gval, bval);
1566  }
1567  val = hasha2[hashval];
1568  setLineDataVal(lined, j, d, val);
1569  }
1570  }
1571  pixSetColormap(pixd, cmap);
1572 
1573  LEPT_FREE(hasha1);
1574  LEPT_FREE(hasha2);
1575  return pixd;
1576 }
1577 
1578 
1579 /* ----------------------------------------------------------------------- *
1580  * Find the most "populated" colors in the image (and quantize) *
1581  * ----------------------------------------------------------------------- */
1603 l_ok
1605  l_int32 sigbits,
1606  l_int32 factor,
1607  l_int32 ncolors,
1608  l_uint32 **parray,
1609  PIXCMAP **pcmap)
1610 {
1611 l_int32 n, i, rgbindex, rval, gval, bval;
1612 NUMA *nahisto, *naindex;
1613 
1614  if (!parray && !pcmap)
1615  return ERROR_INT("no return val requested", __func__, 1);
1616  if (parray) *parray = NULL;
1617  if (pcmap) *pcmap = NULL;
1618  if (!pixs || pixGetDepth(pixs) != 32)
1619  return ERROR_INT("pixs not defined", __func__, 1);
1620  if (sigbits < 2 || sigbits > 6)
1621  return ERROR_INT("sigbits not in [2 ... 6]", __func__, 1);
1622  if (factor < 1 || ncolors < 1)
1623  return ERROR_INT("factor < 1 or ncolors < 1", __func__, 1);
1624 
1625  if ((nahisto = pixGetRGBHistogram(pixs, sigbits, factor)) == NULL)
1626  return ERROR_INT("nahisto not made", __func__, 1);
1627 
1628  /* naindex contains the index into nahisto, which is the rgbindex */
1629  naindex = numaSortIndexAutoSelect(nahisto, L_SORT_DECREASING);
1630  numaDestroy(&nahisto);
1631  if (!naindex)
1632  return ERROR_INT("naindex not made", __func__, 1);
1633 
1634  n = numaGetCount(naindex);
1635  ncolors = L_MIN(n, ncolors);
1636  if (parray) *parray = (l_uint32 *)LEPT_CALLOC(ncolors, sizeof(l_uint32));
1637  if (pcmap) *pcmap = pixcmapCreate(8);
1638  for (i = 0; i < ncolors; i++) {
1639  numaGetIValue(naindex, i, &rgbindex); /* rgb index */
1640  getRGBFromIndex(rgbindex, sigbits, &rval, &gval, &bval);
1641  if (parray) composeRGBPixel(rval, gval, bval, *parray + i);
1642  if (pcmap) pixcmapAddColor(*pcmap, rval, gval, bval);
1643  }
1644 
1645  numaDestroy(&naindex);
1646  return 0;
1647 }
1648 
1649 
1678 PIX *
1680  l_int32 sigbits,
1681  l_int32 factor,
1682  l_int32 ncolors)
1683 {
1684 l_int32 w, h;
1685 PIX *pixd;
1686 PIXCMAP *cmap;
1687 
1688  if (!pixs || pixGetDepth(pixs) != 32)
1689  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1690  if (sigbits < 2 || sigbits > 4)
1691  return (PIX *)ERROR_PTR("sigbits not in {2,3,4}", __func__, NULL);
1692 
1693  pixGetMostPopulatedColors(pixs, sigbits, factor, ncolors, NULL, &cmap);
1694  pixGetDimensions(pixs, &w, &h, NULL);
1695  pixd = pixCreate(w, h, 8);
1696  pixSetColormap(pixd, cmap);
1697  pixAssignToNearestColor(pixd, pixs, NULL, 4, NULL);
1698  return pixd;
1699 }
1700 
1701 
1702 /* ----------------------------------------------------------------------- *
1703  * Constructs a color histogram based on rgb indices *
1704  * ----------------------------------------------------------------------- */
1722 NUMA *
1724  l_int32 sigbits,
1725  l_int32 factor)
1726 {
1727 l_int32 w, h, i, j, size, wpl, rval, gval, bval, npts;
1728 l_uint32 val32, rgbindex;
1729 l_float32 *array;
1730 l_uint32 *data, *line, *rtab, *gtab, *btab;
1731 NUMA *na;
1732 
1733  if (!pixs || pixGetDepth(pixs) != 32)
1734  return (NUMA *)ERROR_PTR("pixs not defined", __func__, NULL);
1735  if (sigbits < 2 || sigbits > 6)
1736  return (NUMA *)ERROR_PTR("sigbits not in [2 ... 6]", __func__, NULL);
1737  if (factor < 1)
1738  return (NUMA *)ERROR_PTR("factor < 1", __func__, NULL);
1739 
1740  /* Get histogram size: 2^(3 * sigbits) */
1741  size = 1 << (3 * sigbits); /* 64, 512, 4096, 32768, 262144 */
1742  na = numaMakeConstant(0, size); /* init to all 0 */
1743  array = numaGetFArray(na, L_NOCOPY);
1744 
1745  makeRGBIndexTables(&rtab, &gtab, &btab, sigbits);
1746 
1747  /* Check the number of sampled pixels */
1748  pixGetDimensions(pixs, &w, &h, NULL);
1749  npts = ((w + factor - 1) / factor) * ((h + factor - 1) / factor);
1750  if (npts < 1000)
1751  L_WARNING("only sampling %d pixels\n", __func__, npts);
1752  wpl = pixGetWpl(pixs);
1753  data = pixGetData(pixs);
1754  for (i = 0; i < h; i += factor) {
1755  line = data + i * wpl;
1756  for (j = 0; j < w; j += factor) {
1757  val32 = *(line + j);
1758  extractRGBValues(val32, &rval, &gval, &bval);
1759  rgbindex = rtab[rval] | gtab[gval] | btab[bval];
1760  array[rgbindex]++;
1761  }
1762  }
1763 
1764  LEPT_FREE(rtab);
1765  LEPT_FREE(gtab);
1766  LEPT_FREE(btab);
1767  return na;
1768 }
1769 
1770 
1788 l_ok
1789 makeRGBIndexTables(l_uint32 **prtab,
1790  l_uint32 **pgtab,
1791  l_uint32 **pbtab,
1792  l_int32 sigbits)
1793 {
1794 l_int32 i;
1795 l_uint32 *rtab, *gtab, *btab;
1796 
1797  if (prtab) *prtab = NULL;
1798  if (pgtab) *pgtab = NULL;
1799  if (pbtab) *pbtab = NULL;
1800  if (!prtab || !pgtab || !pbtab)
1801  return ERROR_INT("not all table ptrs defined", __func__, 1);
1802  if (sigbits < 2 || sigbits > 6)
1803  return ERROR_INT("sigbits not in [2 ... 6]", __func__, 1);
1804 
1805  rtab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1806  gtab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1807  btab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1808  if (!rtab || !gtab || !btab) {
1809  LEPT_FREE(rtab);
1810  LEPT_FREE(gtab);
1811  LEPT_FREE(btab);
1812  return ERROR_INT("calloc fail for tab", __func__, 1);
1813  }
1814  *prtab = rtab;
1815  *pgtab = gtab;
1816  *pbtab = btab;
1817  switch (sigbits) {
1818  case 2:
1819  for (i = 0; i < 256; i++) {
1820  rtab[i] = (i & 0xc0) >> 2;
1821  gtab[i] = (i & 0xc0) >> 4;
1822  btab[i] = (i & 0xc0) >> 6;
1823  }
1824  break;
1825  case 3:
1826  for (i = 0; i < 256; i++) {
1827  rtab[i] = (i & 0xe0) << 1;
1828  gtab[i] = (i & 0xe0) >> 2;
1829  btab[i] = (i & 0xe0) >> 5;
1830  }
1831  break;
1832  case 4:
1833  for (i = 0; i < 256; i++) {
1834  rtab[i] = (i & 0xf0) << 4;
1835  gtab[i] = (i & 0xf0);
1836  btab[i] = (i & 0xf0) >> 4;
1837  }
1838  break;
1839  case 5:
1840  for (i = 0; i < 256; i++) {
1841  rtab[i] = (i & 0xf8) << 7;
1842  gtab[i] = (i & 0xf8) << 2;
1843  btab[i] = (i & 0xf8) >> 3;
1844  }
1845  break;
1846  case 6:
1847  for (i = 0; i < 256; i++) {
1848  rtab[i] = (i & 0xfc) << 10;
1849  gtab[i] = (i & 0xfc) << 4;
1850  btab[i] = (i & 0xfc) >> 2;
1851  }
1852  break;
1853  default:
1854  L_ERROR("Illegal sigbits = %d\n", __func__, sigbits);
1855  return ERROR_INT("sigbits not in [2 ... 6]", __func__, 1);
1856  }
1857 
1858  return 0;
1859 }
1860 
1861 
1880 l_ok
1881 getRGBFromIndex(l_uint32 index,
1882  l_int32 sigbits,
1883  l_int32 *prval,
1884  l_int32 *pgval,
1885  l_int32 *pbval)
1886 {
1887  if (prval) *prval = 0;
1888  if (pgval) *pgval = 0;
1889  if (pbval) *pbval = 0;
1890  if (!prval || !pgval || !pbval)
1891  return ERROR_INT("not all component ptrs defined", __func__, 1);
1892  if (sigbits < 2 || sigbits > 6)
1893  return ERROR_INT("sigbits not in [2 ... 6]", __func__, 1);
1894 
1895  switch (sigbits) {
1896  case 2:
1897  *prval = ((index << 2) & 0xc0) | 0x20;
1898  *pgval = ((index << 4) & 0xc0) | 0x20;
1899  *pbval = ((index << 6) & 0xc0) | 0x20;
1900  break;
1901  case 3:
1902  *prval = ((index >> 1) & 0xe0) | 0x10;
1903  *pgval = ((index << 2) & 0xe0) | 0x10;
1904  *pbval = ((index << 5) & 0xe0) | 0x10;
1905  break;
1906  case 4:
1907  *prval = ((index >> 4) & 0xf0) | 0x08;
1908  *pgval = (index & 0xf0) | 0x08;
1909  *pbval = ((index << 4) & 0xf0) | 0x08;
1910  break;
1911  case 5:
1912  *prval = ((index >> 7) & 0xf8) | 0x04;
1913  *pgval = ((index >> 2) & 0xf8) | 0x04;
1914  *pbval = ((index << 3) & 0xf8) | 0x04;
1915  break;
1916  case 6:
1917  *prval = ((index >> 10) & 0xfc) | 0x02;
1918  *pgval = ((index >> 4) & 0xfc) | 0x02;
1919  *pbval = ((index << 2) & 0xfc) | 0x02;
1920  break;
1921  default:
1922  L_ERROR("Illegal sigbits = %d\n", __func__, sigbits);
1923  return ERROR_INT("sigbits not in [2 ... 6]", __func__, 1);
1924  }
1925 
1926  return 0;
1927 }
1928 
1929 
1930 /* ----------------------------------------------------------------------- *
1931  * Identify images that have highlight (red) color *
1932  * ----------------------------------------------------------------------- */
1961 l_ok
1963  l_int32 factor,
1964  l_float32 minfract,
1965  l_float32 fthresh,
1966  l_int32 *phasred,
1967  l_float32 *pratio,
1968  PIX **ppixdb)
1969 {
1970 l_float32 fract, ratio;
1971 PIX *pix1, *pix2, *pix3, *pix4;
1972 FPIX *fpix;
1973 
1974  if (pratio) *pratio = 0.0;
1975  if (ppixdb) *ppixdb = NULL;
1976  if (phasred) *phasred = 0;
1977  if (!pratio && !ppixdb)
1978  return ERROR_INT("no return val requested", __func__, 1);
1979  if (!phasred)
1980  return ERROR_INT("&hasred not defined", __func__, 1);
1981  if (!pixs || pixGetDepth(pixs) != 32)
1982  return ERROR_INT("pixs not defined or not 32 bpp", __func__, 1);
1983  if (minfract <= 0.0)
1984  return ERROR_INT("minfract must be > 0.0", __func__, 1);
1985  if (fthresh < 1.5 || fthresh > 3.5)
1986  L_WARNING("fthresh = %f is out of normal bounds\n", __func__, fthresh);
1987 
1988  if (factor > 1)
1989  pix1 = pixScaleByIntSampling(pixs, factor);
1990  else
1991  pix1 = pixClone(pixs);
1992 
1993  /* Identify pixels that are either red or dark foreground */
1994  fpix = pixComponentFunction(pix1, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0);
1995  pix2 = fpixThresholdToPix(fpix, fthresh);
1996  pixInvert(pix2, pix2);
1997 
1998  /* Identify pixels that are either red or light background */
1999  pix3 = pixGetRGBComponent(pix1, COLOR_RED);
2000  pix4 = pixThresholdToBinary(pix3, 130);
2001  pixInvert(pix4, pix4);
2002 
2003  pixAnd(pix4, pix4, pix2);
2004  pixForegroundFraction(pix4, &fract);
2005  ratio = fract / minfract;
2006  L_INFO("fract = %7.5f, ratio = %7.3f\n", __func__, fract, ratio);
2007  if (pratio) *pratio = ratio;
2008  if (ratio >= 1.0)
2009  *phasred = 1;
2010  if (ppixdb)
2011  *ppixdb = pix4;
2012  else
2013  pixDestroy(&pix4);
2014  pixDestroy(&pix1);
2015  pixDestroy(&pix2);
2016  pixDestroy(&pix3);
2017  fpixDestroy(&fpix);
2018  return 0;
2019 }
#define GET_DATA_QBIT(pdata, n)
Definition: arrayaccess.h:164
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:127
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define GET_DATA_DIBIT(pdata, n)
Definition: arrayaccess.h:145
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:519
BOXA * boxaCombineOverlaps(BOXA *boxas, PIXA *pixadb)
boxaCombineOverlaps()
Definition: boxfunc1.c:463
PIX * pixMaskBoxa(PIX *pixd, PIX *pixs, BOXA *boxa, l_int32 op)
pixMaskBoxa()
Definition: boxfunc3.c:149
PIX * pixConvertRGBToCmapLossless(PIX *pixs)
pixConvertRGBToCmapLossless()
l_ok pixNumSignificantGrayColors(PIX *pixs, l_int32 darkthresh, l_int32 lightthresh, l_float32 minfract, l_int32 factor, l_int32 *pncolors)
pixNumSignificantGrayColors()
NUMA * pixGetRGBHistogram(PIX *pixs, l_int32 sigbits, l_int32 factor)
pixGetRGBHistogram()
PIX * pixSimpleColorQuantize(PIX *pixs, l_int32 sigbits, l_int32 factor, l_int32 ncolors)
pixSimpleColorQuantize()
PIX * pixColorMagnitude(PIX *pixs, l_int32 rref, l_int32 gref, l_int32 bref, l_int32 type)
pixColorMagnitude()
Definition: colorcontent.c:360
PIX * pixColorShiftWhitePoint(PIX *pixs, l_int32 rref, l_int32 gref, l_int32 bref)
pixColorShiftWhitePoint()
Definition: colorcontent.c:577
l_ok pixColorsForQuantization(PIX *pixs, l_int32 thresh, l_int32 *pncolors, l_int32 *piscolor, l_int32 debug)
pixColorsForQuantization()
l_ok pixColorFraction(PIX *pixs, l_int32 darkthresh, l_int32 lightthresh, l_int32 diffthresh, l_int32 factor, l_float32 *ppixfract, l_float32 *pcolorfract)
pixColorFraction()
Definition: colorcontent.c:490
l_ok pixHasHighlightRed(PIX *pixs, l_int32 factor, l_float32 minfract, l_float32 fthresh, l_int32 *phasred, l_float32 *pratio, PIX **ppixdb)
pixHasHighlightRed()
l_ok pixColorContent(PIX *pixs, l_int32 rref, l_int32 gref, l_int32 bref, l_int32 mingray, PIX **ppixr, PIX **ppixg, PIX **ppixb)
pixColorContent()
Definition: colorcontent.c:202
PIX * pixMaskOverColorPixels(PIX *pixs, l_int32 threshdiff, l_int32 mindist)
pixMaskOverColorPixels()
Definition: colorcontent.c:680
l_ok pixGetMostPopulatedColors(PIX *pixs, l_int32 sigbits, l_int32 factor, l_int32 ncolors, l_uint32 **parray, PIXCMAP **pcmap)
pixGetMostPopulatedColors()
PIX * pixMaskOverColorRange(PIX *pixs, l_int32 rmin, l_int32 rmax, l_int32 gmin, l_int32 gmax, l_int32 bmin, l_int32 bmax)
pixMaskOverColorRange()
Definition: colorcontent.c:816
l_ok getRGBFromIndex(l_uint32 index, l_int32 sigbits, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
getRGBFromIndex()
l_ok pixFindColorRegions(PIX *pixs, PIX *pixm, l_int32 factor, l_int32 lightthresh, l_int32 darkthresh, l_int32 mindiff, l_int32 colordiff, l_float32 edgefract, l_float32 *pcolorfract, PIX **pcolormask1, PIX **pcolormask2, PIXA *pixadb)
pixFindColorRegions()
Definition: colorcontent.c:933
l_ok makeRGBIndexTables(l_uint32 **prtab, l_uint32 **pgtab, l_uint32 **pbtab, l_int32 sigbits)
makeRGBIndexTables()
l_ok pixNumColors(PIX *pixs, l_int32 factor, l_int32 *pncolors)
pixNumColors()
PIX * pixMaskOverGrayPixels(PIX *pixs, l_int32 maxlimit, l_int32 satlimit)
pixMaskOverGrayPixels()
Definition: colorcontent.c:760
l_ok pixcmapHasColor(PIXCMAP *cmap, l_int32 *pcolor)
pixcmapHasColor()
Definition: colormap.c:1026
l_int32 pixcmapGetCount(const PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:683
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:126
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:403
l_ok pixNumberOccupiedOctcubes(PIX *pix, l_int32 level, l_int32 mincount, l_float32 minfract, l_int32 *pncolors)
pixNumberOccupiedOctcubes()
Definition: colorquant1.c:4035
l_ok pixAssignToNearestColor(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 level, l_int32 *countarray)
pixAssignToNearestColor()
Definition: colorseg.c:407
BOXA * pixConnCompBB(PIX *pixs, l_int32 connectivity)
pixConnCompBB()
Definition: conncomp.c:307
PIX * pixSobelEdgeFilter(PIX *pixs, l_int32 orientflag)
pixSobelEdgeFilter()
Definition: edge.c:94
NUMA * numaGammaTRC(l_float32 gamma, l_int32 minval, l_int32 maxval)
numaGammaTRC()
Definition: enhance.c:363
void fpixDestroy(FPIX **pfpix)
fpixDestroy()
Definition: fpix1.c:280
FPIX * pixComponentFunction(PIX *pix, l_float32 rnum, l_float32 gnum, l_float32 bnum, l_float32 rdenom, l_float32 gdenom, l_float32 bdenom)
pixComponentFunction()
Definition: fpix2.c:2295
PIX * fpixThresholdToPix(FPIX *fpix, l_float32 thresh)
fpixThresholdToPix()
Definition: fpix2.c:2239
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
PIX * pixCloseSafeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseSafeBrick()
Definition: morph.c:953
PIX * pixErodeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeBrick()
Definition: morph.c:740
PIX * pixDilateBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateBrick()
Definition: morph.c:672
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:137
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:807
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:850
NUMA * numaSortIndexAutoSelect(NUMA *nas, l_int32 sortorder)
numaSortIndexAutoSelect()
Definition: numafunc1.c:2483
NUMA * numaMakeConstant(l_float32 val, l_int32 size)
numaMakeConstant()
Definition: numafunc1.c:820
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1582
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:380
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2464
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:799
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2728
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2793
l_ok setLineDataVal(l_uint32 *line, l_int32 j, l_int32 d, l_uint32 val)
setLineDataVal()
Definition: pix2.c:2923
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1481
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1893
PIX * pixOr(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixOr()
Definition: pix3.c:1530
PIX * pixAnd(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixAnd()
Definition: pix3.c:1592
l_ok pixSetMasked(PIX *pixd, PIX *pixm, l_uint32 val)
pixSetMasked()
Definition: pix3.c:163
l_ok pixForegroundFraction(PIX *pix, l_float32 *pfract)
pixForegroundFraction()
Definition: pix3.c:1825
l_ok pixCombineMasked(PIX *pixd, PIX *pixs, PIX *pixm)
pixCombineMasked()
Definition: pix3.c:378
PIX * pixSubtract(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixSubtract()
Definition: pix3.c:1717
l_ok pixCountRGBColorsByHash(PIX *pixs, l_int32 *pncolors)
pixCountRGBColorsByHash()
Definition: pix4.c:826
PIX * pixDisplayColorArray(l_uint32 *carray, l_int32 ncolors, l_int32 side, l_int32 ncols, l_int32 fontsize)
pixDisplayColorArray()
Definition: pix4.c:2813
NUMA * pixGetGrayHistogram(PIX *pixs, l_int32 factor)
pixGetGrayHistogram()
Definition: pix4.c:115
l_ok pixGetRankColorArray(PIX *pixs, l_int32 nbins, l_int32 type, l_int32 factor, l_uint32 **pcarray, PIXA *pixadb, l_int32 fontsize)
pixGetRankColorArray()
Definition: pix4.c:2542
PIX * pixMakeSymmetricMask(l_int32 w, l_int32 h, l_float32 hf, l_float32 vf, l_int32 type)
pixSelectComponentBySize()
Definition: pix5.c:1484
@ COLOR_RED
Definition: pix.h:328
@ L_SELECT_AVERAGE
Definition: pix.h:620
@ L_SET_PIXELS
Definition: pix.h:565
@ L_MAX_DIFF
Definition: pix.h:633
@ L_INTERMED_DIFF
Definition: pix.h:631
@ L_AVE_MAX_DIFF_2
Definition: pix.h:632
@ L_SELECT_IF_GTE
Definition: pix.h:578
@ L_USE_INNER
Definition: pix.h:1030
@ REMOVE_CMAP_TO_FULL_COLOR
Definition: pix.h:382
@ L_COPY
Definition: pix.h:505
@ L_NOCOPY
Definition: pix.h:503
@ L_INSERT
Definition: pix.h:504
@ L_SORT_DECREASING
Definition: pix.h:523
@ L_ALL_EDGES
Definition: pix.h:798
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
PIX * pixConvertRGBToGrayMinMax(PIX *pixs, l_int32 type)
pixConvertRGBToGrayMinMax()
Definition: pixconv.c:947
PIX * pixConvertRGBToGray(PIX *pixs, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixConvertRGBToGray()
Definition: pixconv.c:815
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:324
PIX * pixConvertRGBToLuminance(PIX *pixs)
pixConvertRGBToLuminance()
Definition: pixconv.c:732
PIX * pixConvertRGBToBinaryArb(PIX *pixs, l_float32 rc, l_float32 gc, l_float32 bc, l_int32 thresh, l_int32 relation)
pixConvertRGBToBinaryArb()
Definition: pixconv.c:1168
PIX * pixScaleAreaMap(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleAreaMap()
Definition: scale1.c:1864
PIX * pixScaleAreaMap2(PIX *pix)
pixScaleAreaMap2()
Definition: scale1.c:1995
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition: scale1.c:1408
PIX * pixRemoveBorderConnComps(PIX *pixs, l_int32 connectivity)
pixRemoveBorderConnComps()
Definition: seedfill.c:725