Leptonica  1.77.0
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 
139 #include "allheaders.h"
140 
141 /* ----------------------------------------------------------------------- *
142  * Builds an image of the color content, on a per-pixel basis, *
143  * as a measure of the amount of divergence of each color *
144  * component (R,G,B) from gray. *
145  * ----------------------------------------------------------------------- */
178 l_ok
180  l_int32 rwhite,
181  l_int32 gwhite,
182  l_int32 bwhite,
183  l_int32 mingray,
184  PIX **ppixr,
185  PIX **ppixg,
186  PIX **ppixb)
187 {
188 l_int32 w, h, d, i, j, wplc, wplr, wplg, wplb;
189 l_int32 rval, gval, bval, rgdiff, rbdiff, gbdiff, maxval, colorval;
190 l_int32 *rtab, *gtab, *btab;
191 l_uint32 pixel;
192 l_uint32 *datac, *datar, *datag, *datab, *linec, *liner, *lineg, *lineb;
193 NUMA *nar, *nag, *nab;
194 PIX *pixc; /* rgb */
195 PIX *pixr, *pixg, *pixb; /* 8 bpp grayscale */
196 PIXCMAP *cmap;
197 
198  PROCNAME("pixColorContent");
199 
200  if (!ppixr && !ppixg && !ppixb)
201  return ERROR_INT("no return val requested", procName, 1);
202  if (ppixr) *ppixr = NULL;
203  if (ppixg) *ppixg = NULL;
204  if (ppixb) *ppixb = NULL;
205  if (!pixs)
206  return ERROR_INT("pixs not defined", procName, 1);
207  if (mingray < 0) mingray = 0;
208  pixGetDimensions(pixs, &w, &h, &d);
209  if (mingray > 255)
210  return ERROR_INT("mingray > 255", procName, 1);
211  if (rwhite < 0 || gwhite < 0 || bwhite < 0)
212  return ERROR_INT("some white vals are negative", procName, 1);
213  if ((rwhite || gwhite || bwhite) && (rwhite * gwhite * bwhite == 0))
214  return ERROR_INT("white vals not all zero or all nonzero", procName, 1);
215 
216  cmap = pixGetColormap(pixs);
217  if (!cmap && d != 32)
218  return ERROR_INT("pixs neither cmapped nor 32 bpp", procName, 1);
219  if (cmap)
221  else
222  pixc = pixClone(pixs);
223 
224  pixr = pixg = pixb = NULL;
225  pixGetDimensions(pixc, &w, &h, NULL);
226  if (ppixr) {
227  pixr = pixCreate(w, h, 8);
228  datar = pixGetData(pixr);
229  wplr = pixGetWpl(pixr);
230  *ppixr = pixr;
231  }
232  if (ppixg) {
233  pixg = pixCreate(w, h, 8);
234  datag = pixGetData(pixg);
235  wplg = pixGetWpl(pixg);
236  *ppixg = pixg;
237  }
238  if (ppixb) {
239  pixb = pixCreate(w, h, 8);
240  datab = pixGetData(pixb);
241  wplb = pixGetWpl(pixb);
242  *ppixb = pixb;
243  }
244 
245  datac = pixGetData(pixc);
246  wplc = pixGetWpl(pixc);
247  if (rwhite) { /* all white pt vals are nonzero */
248  nar = numaGammaTRC(1.0, 0, rwhite);
249  rtab = numaGetIArray(nar);
250  nag = numaGammaTRC(1.0, 0, gwhite);
251  gtab = numaGetIArray(nag);
252  nab = numaGammaTRC(1.0, 0, bwhite);
253  btab = numaGetIArray(nab);
254  }
255  for (i = 0; i < h; i++) {
256  linec = datac + i * wplc;
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 = linec[j];
265  extractRGBValues(pixel, &rval, &gval, &bval);
266  if (rwhite) { /* color correct for white point */
267  rval = rtab[rval];
268  gval = gtab[gval];
269  bval = btab[bval];
270  }
271  if (mingray > 0) { /* dark pixels have no color value */
272  maxval = L_MAX(rval, gval);
273  maxval = L_MAX(maxval, bval);
274  if (maxval < mingray)
275  continue; /* colorval = 0 for each component */
276  }
277  rgdiff = L_ABS(rval - gval);
278  rbdiff = L_ABS(rval - bval);
279  gbdiff = L_ABS(gval - bval);
280  if (pixr) {
281  colorval = (rgdiff + rbdiff) / 2;
282  SET_DATA_BYTE(liner, j, colorval);
283  }
284  if (pixg) {
285  colorval = (rgdiff + gbdiff) / 2;
286  SET_DATA_BYTE(lineg, j, colorval);
287  }
288  if (pixb) {
289  colorval = (rbdiff + gbdiff) / 2;
290  SET_DATA_BYTE(lineb, j, colorval);
291  }
292  }
293  }
294 
295  if (rwhite) {
296  numaDestroy(&nar);
297  numaDestroy(&nag);
298  numaDestroy(&nab);
299  LEPT_FREE(rtab);
300  LEPT_FREE(gtab);
301  LEPT_FREE(btab);
302  }
303  pixDestroy(&pixc);
304  return 0;
305 }
306 
307 
308 /* ----------------------------------------------------------------------- *
309  * Finds the 'amount' of color in an image, on a per-pixel basis, *
310  * as a measure of the difference of the pixel color from gray. *
311  * ----------------------------------------------------------------------- */
362 PIX *
364  l_int32 rwhite,
365  l_int32 gwhite,
366  l_int32 bwhite,
367  l_int32 type)
368 {
369 l_int32 w, h, d, i, j, wplc, wpld;
370 l_int32 rval, gval, bval, rdist, gdist, bdist, colorval;
371 l_int32 rgdist, rbdist, gbdist, mindist, maxdist, minval, maxval;
372 l_int32 *rtab, *gtab, *btab;
373 l_uint32 pixel;
374 l_uint32 *datac, *datad, *linec, *lined;
375 NUMA *nar, *nag, *nab;
376 PIX *pixc, *pixd;
377 PIXCMAP *cmap;
378 
379  PROCNAME("pixColorMagnitude");
380 
381  if (!pixs)
382  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
383  pixGetDimensions(pixs, &w, &h, &d);
384  if (type != L_MAX_DIFF_FROM_AVERAGE_2 && type != L_MAX_MIN_DIFF_FROM_2 &&
385  type != L_MAX_DIFF)
386  return (PIX *)ERROR_PTR("invalid type", procName, NULL);
387  if (rwhite < 0 || gwhite < 0 || bwhite < 0)
388  return (PIX *)ERROR_PTR("some white vals are negative", procName, NULL);
389  if ((rwhite || gwhite || bwhite) && (rwhite * gwhite * bwhite == 0))
390  return (PIX *)ERROR_PTR("white vals not all zero or all nonzero",
391  procName, NULL);
392 
393  cmap = pixGetColormap(pixs);
394  if (!cmap && d != 32)
395  return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
396  if (cmap)
398  else
399  pixc = pixClone(pixs);
400 
401  pixd = pixCreate(w, h, 8);
402  datad = pixGetData(pixd);
403  wpld = pixGetWpl(pixd);
404  datac = pixGetData(pixc);
405  wplc = pixGetWpl(pixc);
406  if (rwhite) { /* all white pt vals are nonzero */
407  nar = numaGammaTRC(1.0, 0, rwhite);
408  rtab = numaGetIArray(nar);
409  nag = numaGammaTRC(1.0, 0, gwhite);
410  gtab = numaGetIArray(nag);
411  nab = numaGammaTRC(1.0, 0, bwhite);
412  btab = numaGetIArray(nab);
413  }
414  for (i = 0; i < h; i++) {
415  linec = datac + i * wplc;
416  lined = datad + i * wpld;
417  for (j = 0; j < w; j++) {
418  pixel = linec[j];
419  extractRGBValues(pixel, &rval, &gval, &bval);
420  if (rwhite) { /* color correct for white point */
421  rval = rtab[rval];
422  gval = gtab[gval];
423  bval = btab[bval];
424  }
425  if (type == L_MAX_DIFF_FROM_AVERAGE_2) {
426  rdist = ((gval + bval ) / 2 - rval);
427  rdist = L_ABS(rdist);
428  gdist = ((rval + bval ) / 2 - gval);
429  gdist = L_ABS(gdist);
430  bdist = ((rval + gval ) / 2 - bval);
431  bdist = L_ABS(bdist);
432  colorval = L_MAX(rdist, gdist);
433  colorval = L_MAX(colorval, bdist);
434  } else if (type == L_MAX_MIN_DIFF_FROM_2) { /* intermediate dist */
435  rgdist = L_ABS(rval - gval);
436  rbdist = L_ABS(rval - bval);
437  gbdist = L_ABS(gval - bval);
438  maxdist = L_MAX(rgdist, rbdist);
439  if (gbdist >= maxdist) {
440  colorval = maxdist;
441  } else { /* gbdist is smallest or intermediate */
442  mindist = L_MIN(rgdist, rbdist);
443  colorval = L_MAX(mindist, gbdist);
444  }
445  } else { /* type == L_MAX_DIFF */
446  minval = L_MIN(rval, gval);
447  minval = L_MIN(minval, bval);
448  maxval = L_MAX(rval, gval);
449  maxval = L_MAX(maxval, bval);
450  colorval = maxval - minval;
451  }
452  SET_DATA_BYTE(lined, j, colorval);
453  }
454  }
455 
456  if (rwhite) {
457  numaDestroy(&nar);
458  numaDestroy(&nag);
459  numaDestroy(&nab);
460  LEPT_FREE(rtab);
461  LEPT_FREE(gtab);
462  LEPT_FREE(btab);
463  }
464  pixDestroy(&pixc);
465  return pixd;
466 }
467 
468 
469 /* ----------------------------------------------------------------------- *
470  * Generates a mask over pixels that have sufficient color and *
471  * are not too close to gray pixels. *
472  * ----------------------------------------------------------------------- */
501 PIX *
503  l_int32 threshdiff,
504  l_int32 mindist)
505 {
506 l_int32 w, h, d, i, j, wpls, wpld, size;
507 l_int32 rval, gval, bval, minval, maxval;
508 l_uint32 *datas, *datad, *lines, *lined;
509 PIX *pixc, *pixd;
510 PIXCMAP *cmap;
511 
512  PROCNAME("pixMaskOverColorPixels");
513 
514  if (!pixs)
515  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
516  pixGetDimensions(pixs, &w, &h, &d);
517 
518  cmap = pixGetColormap(pixs);
519  if (!cmap && d != 32)
520  return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
521  if (cmap)
523  else
524  pixc = pixClone(pixs);
525 
526  pixd = pixCreate(w, h, 1);
527  datad = pixGetData(pixd);
528  wpld = pixGetWpl(pixd);
529  datas = pixGetData(pixc);
530  wpls = pixGetWpl(pixc);
531  for (i = 0; i < h; i++) {
532  lines = datas + i * wpls;
533  lined = datad + i * wpld;
534  for (j = 0; j < w; j++) {
535  extractRGBValues(lines[j], &rval, &gval, &bval);
536  minval = L_MIN(rval, gval);
537  minval = L_MIN(minval, bval);
538  maxval = L_MAX(rval, gval);
539  maxval = L_MAX(maxval, bval);
540  if (maxval - minval >= threshdiff)
541  SET_DATA_BIT(lined, j);
542  }
543  }
544 
545  if (mindist > 1) {
546  size = 2 * (mindist - 1) + 1;
547  pixErodeBrick(pixd, pixd, size, size);
548  }
549 
550  pixDestroy(&pixc);
551  return pixd;
552 }
553 
554 
555 /* ----------------------------------------------------------------------- *
556  * Generates a mask over pixels that have RGB color components *
557  * within the prescribed range (a cube in RGB color space) *
558  * ----------------------------------------------------------------------- */
568 PIX *
570  l_int32 rmin,
571  l_int32 rmax,
572  l_int32 gmin,
573  l_int32 gmax,
574  l_int32 bmin,
575  l_int32 bmax)
576 {
577 l_int32 w, h, d, i, j, wpls, wpld;
578 l_int32 rval, gval, bval;
579 l_uint32 *datas, *datad, *lines, *lined;
580 PIX *pixc, *pixd;
581 PIXCMAP *cmap;
582 
583  PROCNAME("pixMaskOverColorRange");
584 
585  if (!pixs)
586  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
587  pixGetDimensions(pixs, &w, &h, &d);
588 
589  cmap = pixGetColormap(pixs);
590  if (!cmap && d != 32)
591  return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
592  if (cmap)
594  else
595  pixc = pixClone(pixs);
596 
597  pixd = pixCreate(w, h, 1);
598  datad = pixGetData(pixd);
599  wpld = pixGetWpl(pixd);
600  datas = pixGetData(pixc);
601  wpls = pixGetWpl(pixc);
602  for (i = 0; i < h; i++) {
603  lines = datas + i * wpls;
604  lined = datad + i * wpld;
605  for (j = 0; j < w; j++) {
606  extractRGBValues(lines[j], &rval, &gval, &bval);
607  if (rval < rmin || rval > rmax) continue;
608  if (gval < gmin || gval > gmax) continue;
609  if (bval < bmin || bval > bmax) continue;
610  SET_DATA_BIT(lined, j);
611  }
612  }
613 
614  pixDestroy(&pixc);
615  return pixd;
616 }
617 
618 
619 /* ----------------------------------------------------------------------- *
620  * Finds the fraction of pixels with "color" that are not close to black *
621  * ----------------------------------------------------------------------- */
677 l_ok
679  l_int32 darkthresh,
680  l_int32 lightthresh,
681  l_int32 diffthresh,
682  l_int32 factor,
683  l_float32 *ppixfract,
684  l_float32 *pcolorfract)
685 {
686 l_int32 i, j, w, h, wpl, rval, gval, bval, minval, maxval;
687 l_int32 total, npix, ncolor;
688 l_uint32 pixel;
689 l_uint32 *data, *line;
690 
691  PROCNAME("pixColorFraction");
692 
693  if (ppixfract) *ppixfract = 0.0;
694  if (pcolorfract) *pcolorfract = 0.0;
695  if (!ppixfract || !pcolorfract)
696  return ERROR_INT("&pixfract and &colorfract not defined",
697  procName, 1);
698  if (!pixs || pixGetDepth(pixs) != 32)
699  return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
700 
701  pixGetDimensions(pixs, &w, &h, NULL);
702  data = pixGetData(pixs);
703  wpl = pixGetWpl(pixs);
704  npix = ncolor = total = 0;
705  for (i = 0; i < h; i += factor) {
706  line = data + i * wpl;
707  for (j = 0; j < w; j += factor) {
708  total++;
709  pixel = line[j];
710  extractRGBValues(pixel, &rval, &gval, &bval);
711  minval = L_MIN(rval, gval);
712  minval = L_MIN(minval, bval);
713  if (minval > lightthresh) /* near white */
714  continue;
715  maxval = L_MAX(rval, gval);
716  maxval = L_MAX(maxval, bval);
717  if (maxval < darkthresh) /* near black */
718  continue;
719 
720  npix++;
721  if (maxval - minval >= diffthresh)
722  ncolor++;
723  }
724  }
725 
726  if (npix == 0) {
727  L_WARNING("No pixels found for consideration\n", procName);
728  return 0;
729  }
730  *ppixfract = (l_float32)npix / (l_float32)total;
731  *pcolorfract = (l_float32)ncolor / (l_float32)npix;
732  return 0;
733 }
734 
735 
736 /* ----------------------------------------------------------------------- *
737  * Determine if there are significant color regions in a page image *
738  * ----------------------------------------------------------------------- */
804 l_ok
806  PIX *pixm,
807  l_int32 factor,
808  l_int32 lightthresh,
809  l_int32 darkthresh,
810  l_int32 mindiff,
811  l_int32 colordiff,
812  l_float32 edgefract,
813  l_float32 *pcolorfract,
814  PIX **pcolormask1,
815  PIX **pcolormask2,
816  PIXA *pixadb)
817 {
818 l_int32 w, h, count, rval, gval, bval, aveval, proceed;
819 l_float32 ratio;
820 l_uint32 *carray;
821 BOXA *boxa1, *boxa2;
822 PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pixm1, *pixm2, *pixm3;
823 
824  PROCNAME("pixFindColorRegions");
825 
826  if (pcolormask1) *pcolormask1 = NULL;
827  if (pcolormask2) *pcolormask2 = NULL;
828  if (!pcolorfract)
829  return ERROR_INT("&colorfract not defined", procName, 1);
830  *pcolorfract = 0.0;
831  if (!pixs || pixGetDepth(pixs) != 32)
832  return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
833  if (factor < 1) factor = 1;
834  if (lightthresh < 0) lightthresh = 210; /* defaults */
835  if (darkthresh < 0) darkthresh = 70;
836  if (mindiff < 0) mindiff = 10;
837  if (colordiff < 0) colordiff = 90;
838  if (edgefract < 0.0 || edgefract > 1.0) edgefract = 0.05;
839 
840  /* Check if pixm covers most of the image. If so, just return. */
841  pixGetDimensions(pixs, &w, &h, NULL);
842  if (pixm) {
843  pixCountPixels(pixm, &count, NULL);
844  ratio = (l_float32)count / ((l_float32)(w) * h);
845  if (ratio > 0.7) {
846  if (pixadb) L_INFO("pixm has big fg: %f5.2\n", procName, ratio);
847  return 0;
848  }
849  }
850 
851  /* Get the light background color. Use the average component value
852  * and select the lightest of 10 buckets. Require that it is
853  * reddish and, using lightthresh, not too dark. */
854  pixGetRankColorArray(pixs, 10, L_SELECT_AVERAGE, factor, &carray, 0, 0);
855  if (!carray)
856  return ERROR_INT("rank color array not made", procName, 1);
857  extractRGBValues(carray[9], &rval, &gval, &bval);
858  if (pixadb) L_INFO("lightest background color: (r,g,b) = (%d,%d,%d)\n",
859  procName, rval, gval, bval);
860  proceed = TRUE;
861  if ((rval < bval - 2) || (rval < gval - 2)) {
862  if (pixadb) L_INFO("background not reddish\n", procName);
863  proceed = FALSE;
864  }
865  aveval = (rval + gval + bval) / 3;
866  if (aveval < lightthresh) {
867  if (pixadb) L_INFO("background too dark\n", procName);
868  proceed = FALSE;
869  }
870  if (pixadb) {
871  pix1 = pixDisplayColorArray(carray, 10, 120, 3, 6);
872  pixaAddPix(pixadb, pix1, L_INSERT);
873  }
874  LEPT_FREE(carray);
875  if (proceed == FALSE) return 0;
876 
877  /* Make a mask pixm1 over the dark pixels in the image:
878  * convert to gray using the average of the components;
879  * threshold using darkthresh; do a small dilation;
880  * combine with pixm. */
881  pix1 = pixConvertRGBToGray(pixs, 0.33, 0.34, 0.33);
882  if (pixadb) pixaAddPix(pixadb, pix1, L_COPY);
883  pixm1 = pixThresholdToBinary(pix1, darkthresh);
884  pixDilateBrick(pixm1, pixm1, 7, 7);
885  if (pixadb) pixaAddPix(pixadb, pixm1, L_COPY);
886  if (pixm) {
887  pixOr(pixm1, pixm1, pixm);
888  if (pixadb) pixaAddPix(pixadb, pixm1, L_COPY);
889  }
890  pixDestroy(&pix1);
891 
892  /* Make masks over pixels that are bluish, or greenish, or
893  have a very large color saturation (max - min) value. */
894  pixm2 = pixConvertRGBToBinaryArb(pixs, -1.0, 0.0, 1.0, mindiff,
895  L_SELECT_IF_GTE); /* b - r */
896  if (pixadb) pixaAddPix(pixadb, pixm2, L_COPY);
897  pix1 = pixConvertRGBToBinaryArb(pixs, -1.0, 1.0, 0.0, mindiff,
898  L_SELECT_IF_GTE); /* g - r */
899  if (pixadb) pixaAddPix(pixadb, pix1, L_COPY);
900  pixOr(pixm2, pixm2, pix1);
901  pixDestroy(&pix1);
902  pix1 = pixConvertRGBToGrayMinMax(pixs, L_CHOOSE_MAXDIFF);
903  pix2 = pixThresholdToBinary(pix1, colordiff);
904  pixInvert(pix2, pix2);
905  if (pixadb) pixaAddPix(pixadb, pix2, L_COPY);
906  pixOr(pixm2, pixm2, pix2);
907  if (pixadb) pixaAddPix(pixadb, pixm2, L_COPY);
908  pixDestroy(&pix1);
909  pixDestroy(&pix2);
910 
911  /* Subtract the dark pixels represented by pixm1.
912  * pixm2 now holds all the color pixels of interest */
913  pixSubtract(pixm2, pixm2, pixm1);
914  pixDestroy(&pixm1);
915  if (pixadb) pixaAddPix(pixadb, pixm2, L_COPY);
916 
917  /* But we're not quite finished. Remove pixels from any component
918  * that is touching the image border. False color pixels can
919  * sometimes be found there if the image is much darker near
920  * the border, due to oxidation or reduced illumination. Also
921  * remove any pixels within the normalized fraction %distfract
922  * of the image border. */
923  pixm3 = pixRemoveBorderConnComps(pixm2, 8);
924  pixDestroy(&pixm2);
925  if (edgefract > 0.0) {
926  pix2 = pixMakeFrameMask(w, h, edgefract, 1.0, edgefract, 1.0);
927  pixAnd(pixm3, pixm3, pix2);
928  pixDestroy(&pix2);
929  }
930  if (pixadb) pixaAddPix(pixadb, pixm3, L_COPY);
931 
932  /* Get the fraction of light color pixels */
933  pixCountPixels(pixm3, &count, NULL);
934  *pcolorfract = (l_float32)count / ((l_float32)(w) * h);
935  if (pixadb) {
936  if (count == 0)
937  L_INFO("no light color pixels found\n", procName);
938  else
939  L_INFO("fraction of light color pixels = %5.3f\n", procName,
940  *pcolorfract);
941  }
942 
943  /* Debug: extract the color pixels from pixs */
944  if (pixadb && count > 0) {
945  /* Use pixm3 to extract the color pixels */
946  pix3 = pixCreateTemplate(pixs);
947  pixSetAll(pix3);
948  pixCombineMasked(pix3, pixs, pixm3);
949  pixaAddPix(pixadb, pix3, L_INSERT);
950 
951  /* Use additional filtering to extract the color pixels */
952  pix3 = pixCloseSafeBrick(NULL, pixm3, 15, 15);
953  pixaAddPix(pixadb, pix3, L_INSERT);
954  pix5 = pixCreateTemplate(pixs);
955  pixSetAll(pix5);
956  pixCombineMasked(pix5, pixs, pix3);
957  pixaAddPix(pixadb, pix5, L_INSERT);
958 
959  /* Get the combined bounding boxes of the mask components
960  * in pix3, and extract those pixels from pixs. */
961  boxa1 = pixConnCompBB(pix3, 8);
962  boxa2 = boxaCombineOverlaps(boxa1, NULL);
963  pix4 = pixCreateTemplate(pix3);
964  pixMaskBoxa(pix4, pix4, boxa2, L_SET_PIXELS);
965  pixaAddPix(pixadb, pix4, L_INSERT);
966  pix5 = pixCreateTemplate(pixs);
967  pixSetAll(pix5);
968  pixCombineMasked(pix5, pixs, pix4);
969  pixaAddPix(pixadb, pix5, L_INSERT);
970  boxaDestroy(&boxa1);
971  boxaDestroy(&boxa2);
972  }
973  pixaAddPix(pixadb, pixs, L_COPY);
974 
975  /* Optional colormask returns */
976  if (pcolormask2 && count > 0)
977  *pcolormask2 = pixCloseSafeBrick(NULL, pixm3, 15, 15);
978  if (pcolormask1 && count > 0)
979  *pcolormask1 = pixm3;
980  else
981  pixDestroy(&pixm3);
982  return 0;
983 }
984 
985 
986 /* ----------------------------------------------------------------------- *
987  * Finds the number of perceptually significant gray intensities *
988  * in a grayscale image. *
989  * ----------------------------------------------------------------------- */
1021 l_ok
1023  l_int32 darkthresh,
1024  l_int32 lightthresh,
1025  l_float32 minfract,
1026  l_int32 factor,
1027  l_int32 *pncolors)
1028 {
1029 l_int32 i, w, h, count, mincount, ncolors;
1030 NUMA *na;
1031 
1032  PROCNAME("pixNumSignificantGrayColors");
1033 
1034  if (!pncolors)
1035  return ERROR_INT("&ncolors not defined", procName, 1);
1036  *pncolors = 0;
1037  if (!pixs || pixGetDepth(pixs) != 8)
1038  return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
1039  if (darkthresh < 0) darkthresh = 20; /* defaults */
1040  if (lightthresh < 0) lightthresh = 236;
1041  if (minfract < 0.0) minfract = 0.0001;
1042  if (minfract > 1.0)
1043  return ERROR_INT("minfract > 1.0", procName, 1);
1044  if (minfract >= 0.001)
1045  L_WARNING("minfract too big; likely to underestimate ncolors\n",
1046  procName);
1047  if (lightthresh > 255 || darkthresh >= lightthresh)
1048  return ERROR_INT("invalid thresholds", procName, 1);
1049  if (factor < 1) factor = 1;
1050 
1051  pixGetDimensions(pixs, &w, &h, NULL);
1052  mincount = (l_int32)(minfract * w * h * factor * factor);
1053  if ((na = pixGetGrayHistogram(pixs, factor)) == NULL)
1054  return ERROR_INT("na not made", procName, 1);
1055  ncolors = 2; /* add in black and white */
1056  for (i = darkthresh; i <= lightthresh; i++) {
1057  numaGetIValue(na, i, &count);
1058  if (count >= mincount)
1059  ncolors++;
1060  }
1061 
1062  *pncolors = ncolors;
1063  numaDestroy(&na);
1064  return 0;
1065 }
1066 
1067 
1068 /* ----------------------------------------------------------------------- *
1069  * Identifies images where color quantization will cause posterization *
1070  * due to the existence of many colors in low-gradient regions. *
1071  * ----------------------------------------------------------------------- */
1144 l_ok
1146  l_int32 thresh,
1147  l_int32 *pncolors,
1148  l_int32 *piscolor,
1149  l_int32 debug)
1150 {
1151 l_int32 w, h, d, minside, factor;
1152 l_float32 pixfract, colorfract;
1153 PIX *pixt, *pixsc, *pixg, *pixe, *pixb, *pixm;
1154 PIXCMAP *cmap;
1155 
1156  PROCNAME("pixColorsForQuantization");
1157 
1158  if (piscolor) *piscolor = 0;
1159  if (!pncolors)
1160  return ERROR_INT("&ncolors not defined", procName, 1);
1161  *pncolors = 0;
1162  if (!pixs)
1163  return ERROR_INT("pixs not defined", procName, 1);
1164  if ((cmap = pixGetColormap(pixs)) != NULL) {
1165  *pncolors = pixcmapGetCount(cmap);
1166  if (piscolor)
1167  pixcmapHasColor(cmap, piscolor);
1168  return 0;
1169  }
1170 
1171  pixGetDimensions(pixs, &w, &h, &d);
1172  if (d != 8 && d != 32)
1173  return ERROR_INT("pixs not 8 or 32 bpp", procName, 1);
1174  if (thresh <= 0)
1175  thresh = 15;
1176 
1177  /* First test if 32 bpp has any significant color; if not,
1178  * convert it to gray. Colors whose average values are within
1179  * 20 of black or 8 of white are ignored because they're not
1180  * very 'colorful'. If less than 2.5/10000 of the pixels have
1181  * significant color, consider the image to be gray. */
1182  minside = L_MIN(w, h);
1183  if (d == 8) {
1184  pixt = pixClone(pixs);
1185  } else { /* d == 32 */
1186  factor = L_MAX(1, minside / 400);
1187  pixColorFraction(pixs, 20, 248, 30, factor, &pixfract, &colorfract);
1188  if (pixfract * colorfract < 0.00025) {
1189  pixt = pixGetRGBComponent(pixs, COLOR_RED);
1190  d = 8;
1191  } else { /* d == 32 */
1192  pixt = pixClone(pixs);
1193  if (piscolor)
1194  *piscolor = 1;
1195  }
1196  }
1197 
1198  /* If the smallest side is less than 1000, do not downscale.
1199  * If it is in [1000 ... 2000), downscale by 2x. If it is >= 2000,
1200  * downscale by 4x. Factors of 2 are chosen for speed. The
1201  * actual resolution at which subsequent calculations take place
1202  * is not strongly dependent on downscaling. */
1203  factor = L_MAX(1, minside / 500);
1204  if (factor == 1)
1205  pixsc = pixCopy(NULL, pixt); /* to be sure pixs is unchanged */
1206  else if (factor == 2 || factor == 3)
1207  pixsc = pixScaleAreaMap2(pixt);
1208  else
1209  pixsc = pixScaleAreaMap(pixt, 0.25, 0.25);
1210 
1211  /* Basic edge mask generation procedure:
1212  * ~ work on a grayscale image
1213  * ~ get a 1 bpp edge mask by using an edge filter and
1214  * thresholding to get fg pixels at the edges
1215  * ~ for gray, dilate with a 3x3 brick Sel to get mask over
1216  * all pixels within a distance of 1 pixel from the nearest
1217  * edge pixel
1218  * ~ for color, dilate with a 7x7 brick Sel to get mask over
1219  * all pixels within a distance of 3 pixels from the nearest
1220  * edge pixel */
1221  if (d == 8)
1222  pixg = pixClone(pixsc);
1223  else /* d == 32 */
1224  pixg = pixConvertRGBToLuminance(pixsc);
1225  pixe = pixSobelEdgeFilter(pixg, L_ALL_EDGES);
1226  pixb = pixThresholdToBinary(pixe, thresh);
1227  pixInvert(pixb, pixb);
1228  if (d == 8)
1229  pixm = pixMorphSequence(pixb, "d3.3", 0);
1230  else
1231  pixm = pixMorphSequence(pixb, "d7.7", 0);
1232 
1233  /* Mask the near-edge pixels to white, and count the colors.
1234  * If grayscale, don't count colors within 20 levels of
1235  * black or white, and only count colors with a fraction
1236  * of at least 1/10000 of the image pixels.
1237  * If color, count the number of level 4 octcubes that
1238  * contain at least 20 pixels. These magic numbers are guesses
1239  * as to what might work, based on a small data set. Results
1240  * should not be overly sensitive to their actual values. */
1241  if (d == 8) {
1242  pixSetMasked(pixg, pixm, 0xff);
1243  if (debug) pixWrite("junkpix8.png", pixg, IFF_PNG);
1244  pixNumSignificantGrayColors(pixg, 20, 236, 0.0001, 1, pncolors);
1245  } else { /* d == 32 */
1246  pixSetMasked(pixsc, pixm, 0xffffffff);
1247  if (debug) pixWrite("junkpix32.png", pixsc, IFF_PNG);
1248  pixNumberOccupiedOctcubes(pixsc, 4, 20, -1, pncolors);
1249  }
1250 
1251  pixDestroy(&pixt);
1252  pixDestroy(&pixsc);
1253  pixDestroy(&pixg);
1254  pixDestroy(&pixe);
1255  pixDestroy(&pixb);
1256  pixDestroy(&pixm);
1257  return 0;
1258 }
1259 
1260 
1261 /* ----------------------------------------------------------------------- *
1262  * Finds the number of unique colors in an image *
1263  * ----------------------------------------------------------------------- */
1286 l_ok
1288  l_int32 factor,
1289  l_int32 *pncolors)
1290 {
1291 l_int32 w, h, d, i, j, wpl, hashsize, sum, count;
1292 l_int32 rval, gval, bval, val;
1293 l_int32 *inta;
1294 l_uint32 pixel;
1295 l_uint32 *data, *line;
1296 PIXCMAP *cmap;
1297 
1298  PROCNAME("pixNumColors");
1299 
1300  if (!pncolors)
1301  return ERROR_INT("&ncolors not defined", procName, 1);
1302  *pncolors = 0;
1303  if (!pixs)
1304  return ERROR_INT("pixs not defined", procName, 1);
1305  pixGetDimensions(pixs, &w, &h, &d);
1306  if (d != 2 && d != 4 && d != 8 && d != 32)
1307  return ERROR_INT("d not in {2, 4, 8, 32}", procName, 1);
1308  if (factor < 1) factor = 1;
1309 
1310  data = pixGetData(pixs);
1311  wpl = pixGetWpl(pixs);
1312  sum = 0;
1313  if (d != 32) { /* grayscale */
1314  if ((inta = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32))) == NULL)
1315  return ERROR_INT("calloc failure for inta", procName, 1);
1316  for (i = 0; i < h; i += factor) {
1317  line = data + i * wpl;
1318  for (j = 0; j < w; j += factor) {
1319  if (d == 8)
1320  val = GET_DATA_BYTE(line, j);
1321  else if (d == 4)
1322  val = GET_DATA_QBIT(line, j);
1323  else /* d == 2 */
1324  val = GET_DATA_DIBIT(line, j);
1325  inta[val] = 1;
1326  }
1327  }
1328  for (i = 0; i < 256; i++)
1329  if (inta[i]) sum++;
1330  *pncolors = sum;
1331  LEPT_FREE(inta);
1332 
1333  cmap = pixGetColormap(pixs);
1334  if (cmap && factor == 1) {
1335  count = pixcmapGetCount(cmap);
1336  if (sum != count)
1337  L_WARNING("colormap size %d differs from actual colors\n",
1338  procName, count);
1339  }
1340  return 0;
1341  }
1342 
1343  /* 32 bpp rgb; quit if we get above 256 colors */
1344  hashsize = 5507; /* big and prime; collisions are not likely */
1345  if ((inta = (l_int32 *)LEPT_CALLOC(hashsize, sizeof(l_int32))) == NULL)
1346  return ERROR_INT("calloc failure with hashsize", procName, 1);
1347  for (i = 0; i < h; i += factor) {
1348  line = data + i * wpl;
1349  for (j = 0; j < w; j += factor) {
1350  pixel = line[j];
1351  extractRGBValues(pixel, &rval, &gval, &bval);
1352  val = (137 * rval + 269 * gval + 353 * bval) % hashsize;
1353  if (inta[val] == 0) {
1354  inta[val] = 1;
1355  sum++;
1356  if (sum > 256) {
1357  LEPT_FREE(inta);
1358  return 0;
1359  }
1360  }
1361  }
1362  }
1363 
1364  *pncolors = sum;
1365  LEPT_FREE(inta);
1366  return 0;
1367 }
1368 
1369 
1370 /* ----------------------------------------------------------------------- *
1371  * Find the most "populated" colors in the image (and quantize) *
1372  * ----------------------------------------------------------------------- */
1394 l_ok
1396  l_int32 sigbits,
1397  l_int32 factor,
1398  l_int32 ncolors,
1399  l_uint32 **parray,
1400  PIXCMAP **pcmap)
1401 {
1402 l_int32 n, i, rgbindex, rval, gval, bval;
1403 NUMA *nahisto, *naindex;
1404 
1405  PROCNAME("pixGetMostPopulatedColors");
1406 
1407  if (!parray && !pcmap)
1408  return ERROR_INT("no return val requested", procName, 1);
1409  if (parray) *parray = NULL;
1410  if (pcmap) *pcmap = NULL;
1411  if (!pixs || pixGetDepth(pixs) != 32)
1412  return ERROR_INT("pixs not defined", procName, 1);
1413  if (sigbits < 2 || sigbits > 6)
1414  return ERROR_INT("sigbits not in [2 ... 6]", procName, 1);
1415  if (factor < 1 || ncolors < 1)
1416  return ERROR_INT("factor < 1 or ncolors < 1", procName, 1);
1417 
1418  if ((nahisto = pixGetRGBHistogram(pixs, sigbits, factor)) == NULL)
1419  return ERROR_INT("nahisto not made", procName, 1);
1420 
1421  /* naindex contains the index into nahisto, which is the rgbindex */
1422  naindex = numaSortIndexAutoSelect(nahisto, L_SORT_DECREASING);
1423  numaDestroy(&nahisto);
1424  if (!naindex)
1425  return ERROR_INT("naindex not made", procName, 1);
1426 
1427  n = numaGetCount(naindex);
1428  ncolors = L_MIN(n, ncolors);
1429  if (parray) *parray = (l_uint32 *)LEPT_CALLOC(ncolors, sizeof(l_uint32));
1430  if (pcmap) *pcmap = pixcmapCreate(8);
1431  for (i = 0; i < ncolors; i++) {
1432  numaGetIValue(naindex, i, &rgbindex); /* rgb index */
1433  getRGBFromIndex(rgbindex, sigbits, &rval, &gval, &bval);
1434  if (parray) composeRGBPixel(rval, gval, bval, *parray + i);
1435  if (pcmap) pixcmapAddColor(*pcmap, rval, gval, bval);
1436  }
1437 
1438  numaDestroy(&naindex);
1439  return 0;
1440 }
1441 
1442 
1469 PIX *
1471  l_int32 sigbits,
1472  l_int32 factor,
1473  l_int32 ncolors)
1474 {
1475 l_int32 w, h;
1476 PIX *pixd;
1477 PIXCMAP *cmap;
1478 
1479  PROCNAME("pixSimpleColorQuantize");
1480 
1481  if (!pixs || pixGetDepth(pixs) != 32)
1482  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1483  if (sigbits < 2 || sigbits > 4)
1484  return (PIX *)ERROR_PTR("sigbits not in {2,3,4}", procName, NULL);
1485 
1486  pixGetMostPopulatedColors(pixs, sigbits, factor, ncolors, NULL, &cmap);
1487  pixGetDimensions(pixs, &w, &h, NULL);
1488  pixd = pixCreate(w, h, 8);
1489  pixSetColormap(pixd, cmap);
1490  pixAssignToNearestColor(pixd, pixs, NULL, 4, NULL);
1491  return pixd;
1492 }
1493 
1494 
1495 /* ----------------------------------------------------------------------- *
1496  * Constructs a color histogram based on rgb indices *
1497  * ----------------------------------------------------------------------- */
1515 NUMA *
1517  l_int32 sigbits,
1518  l_int32 factor)
1519 {
1520 l_int32 w, h, i, j, size, wpl, rval, gval, bval, npts;
1521 l_uint32 val32, rgbindex;
1522 l_float32 *array;
1523 l_uint32 *data, *line, *rtab, *gtab, *btab;
1524 NUMA *na;
1525 
1526  PROCNAME("pixGetRGBHistogram");
1527 
1528  if (!pixs || pixGetDepth(pixs) != 32)
1529  return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
1530  if (sigbits < 2 || sigbits > 6)
1531  return (NUMA *)ERROR_PTR("sigbits not in [2 ... 6]", procName, NULL);
1532  if (factor < 1)
1533  return (NUMA *)ERROR_PTR("factor < 1", procName, NULL);
1534 
1535  /* Get histogram size: 2^(3 * sigbits) */
1536  size = 1 << (3 * sigbits); /* 64, 512, 4096, 32768, 262144 */
1537  na = numaMakeConstant(0, size); /* init to all 0 */
1538  array = numaGetFArray(na, L_NOCOPY);
1539 
1540  makeRGBIndexTables(&rtab, &gtab, &btab, sigbits);
1541 
1542  /* Check the number of sampled pixels */
1543  pixGetDimensions(pixs, &w, &h, NULL);
1544  npts = ((w + factor - 1) / factor) * ((h + factor - 1) / factor);
1545  if (npts < 1000)
1546  L_WARNING("only sampling %d pixels\n", procName, npts);
1547  wpl = pixGetWpl(pixs);
1548  data = pixGetData(pixs);
1549  for (i = 0; i < h; i += factor) {
1550  line = data + i * wpl;
1551  for (j = 0; j < w; j += factor) {
1552  val32 = *(line + j);
1553  extractRGBValues(val32, &rval, &gval, &bval);
1554  rgbindex = rtab[rval] | gtab[gval] | btab[bval];
1555  array[rgbindex]++;
1556  }
1557  }
1558 
1559  LEPT_FREE(rtab);
1560  LEPT_FREE(gtab);
1561  LEPT_FREE(btab);
1562  return na;
1563 }
1564 
1565 
1583 l_ok
1584 makeRGBIndexTables(l_uint32 **prtab,
1585  l_uint32 **pgtab,
1586  l_uint32 **pbtab,
1587  l_int32 sigbits)
1588 {
1589 l_int32 i;
1590 l_uint32 *rtab, *gtab, *btab;
1591 
1592  PROCNAME("makeRGBIndexTables");
1593 
1594  if (prtab) *prtab = NULL;
1595  if (pgtab) *pgtab = NULL;
1596  if (pbtab) *pbtab = NULL;
1597  if (!prtab || !pgtab || !pbtab)
1598  return ERROR_INT("not all table ptrs defined", procName, 1);
1599  if (sigbits < 2 || sigbits > 6)
1600  return ERROR_INT("sigbits not in [2 ... 6]", procName, 1);
1601 
1602  rtab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1603  gtab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1604  btab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1605  if (!rtab || !gtab || !btab)
1606  return ERROR_INT("calloc fail for tab", procName, 1);
1607  *prtab = rtab;
1608  *pgtab = gtab;
1609  *pbtab = btab;
1610  switch (sigbits) {
1611  case 2:
1612  for (i = 0; i < 256; i++) {
1613  rtab[i] = (i & 0xc0) >> 2;
1614  gtab[i] = (i & 0xc0) >> 4;
1615  btab[i] = (i & 0xc0) >> 6;
1616  }
1617  break;
1618  case 3:
1619  for (i = 0; i < 256; i++) {
1620  rtab[i] = (i & 0xe0) << 1;
1621  gtab[i] = (i & 0xe0) >> 2;
1622  btab[i] = (i & 0xe0) >> 5;
1623  }
1624  break;
1625  case 4:
1626  for (i = 0; i < 256; i++) {
1627  rtab[i] = (i & 0xf0) << 4;
1628  gtab[i] = (i & 0xf0);
1629  btab[i] = (i & 0xf0) >> 4;
1630  }
1631  break;
1632  case 5:
1633  for (i = 0; i < 256; i++) {
1634  rtab[i] = (i & 0xf8) << 7;
1635  gtab[i] = (i & 0xf8) << 2;
1636  btab[i] = (i & 0xf8) >> 3;
1637  }
1638  break;
1639  case 6:
1640  for (i = 0; i < 256; i++) {
1641  rtab[i] = (i & 0xfc) << 10;
1642  gtab[i] = (i & 0xfc) << 4;
1643  btab[i] = (i & 0xfc) >> 2;
1644  }
1645  break;
1646  default:
1647  L_ERROR("Illegal sigbits = %d\n", procName, sigbits);
1648  return ERROR_INT("sigbits not in [2 ... 6]", procName, 1);
1649  }
1650 
1651  return 0;
1652 }
1653 
1654 
1673 l_ok
1674 getRGBFromIndex(l_uint32 index,
1675  l_int32 sigbits,
1676  l_int32 *prval,
1677  l_int32 *pgval,
1678  l_int32 *pbval)
1679 {
1680  PROCNAME("getRGBFromIndex");
1681 
1682  if (prval) *prval = 0;
1683  if (pgval) *pgval = 0;
1684  if (pbval) *pbval = 0;
1685  if (!prval || !pgval || !pbval)
1686  return ERROR_INT("not all component ptrs defined", procName, 1);
1687  if (sigbits < 2 || sigbits > 6)
1688  return ERROR_INT("sigbits not in [2 ... 6]", procName, 1);
1689 
1690  switch (sigbits) {
1691  case 2:
1692  *prval = ((index << 2) & 0xc0) | 0x20;
1693  *pgval = ((index << 4) & 0xc0) | 0x20;
1694  *pbval = ((index << 6) & 0xc0) | 0x20;
1695  break;
1696  case 3:
1697  *prval = ((index >> 1) & 0xe0) | 0x10;
1698  *pgval = ((index << 2) & 0xe0) | 0x10;
1699  *pbval = ((index << 5) & 0xe0) | 0x10;
1700  break;
1701  case 4:
1702  *prval = ((index >> 4) & 0xf0) | 0x08;
1703  *pgval = (index & 0xf0) | 0x08;
1704  *pbval = ((index << 4) & 0xf0) | 0x08;
1705  break;
1706  case 5:
1707  *prval = ((index >> 7) & 0xf8) | 0x04;
1708  *pgval = ((index >> 2) & 0xf8) | 0x04;
1709  *pbval = ((index << 3) & 0xf8) | 0x04;
1710  break;
1711  case 6:
1712  *prval = ((index >> 10) & 0xfc) | 0x02;
1713  *pgval = ((index >> 4) & 0xfc) | 0x02;
1714  *pbval = ((index << 2) & 0xfc) | 0x02;
1715  break;
1716  default:
1717  L_ERROR("Illegal sigbits = %d\n", procName, sigbits);
1718  return ERROR_INT("sigbits not in [2 ... 6]", procName, 1);
1719  }
1720 
1721  return 0;
1722 }
1723 
1724 
1725 /* ----------------------------------------------------------------------- *
1726  * Identify images that have highlight (red) color *
1727  * ----------------------------------------------------------------------- */
1756 l_ok
1758  l_int32 factor,
1759  l_float32 fract,
1760  l_float32 fthresh,
1761  l_int32 *phasred,
1762  l_float32 *pratio,
1763  PIX **ppixdb)
1764 {
1765 l_int32 w, h, count;
1766 l_float32 ratio;
1767 PIX *pix1, *pix2, *pix3, *pix4;
1768 FPIX *fpix;
1769 
1770  PROCNAME("pixHasHighlightRed");
1771 
1772  if (pratio) *pratio = 0.0;
1773  if (ppixdb) *ppixdb = NULL;
1774  if (phasred) *phasred = 0;
1775  if (!pratio && !ppixdb)
1776  return ERROR_INT("no return val requested", procName, 1);
1777  if (!phasred)
1778  return ERROR_INT("&hasred not defined", procName, 1);
1779  if (!pixs || pixGetDepth(pixs) != 32)
1780  return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
1781  if (fthresh < 1.5 || fthresh > 3.5)
1782  L_WARNING("fthresh = %f is out of normal bounds\n", procName, fthresh);
1783 
1784  if (factor > 1)
1785  pix1 = pixScaleByIntSampling(pixs, factor);
1786  else
1787  pix1 = pixClone(pixs);
1788 
1789  /* Identify pixels that are either red or dark foreground */
1790  fpix = pixComponentFunction(pix1, 1.0, 0.0, -1.0, 0.0, 0.0, 1.0);
1791  pix2 = fpixThresholdToPix(fpix, fthresh);
1792  pixInvert(pix2, pix2);
1793 
1794  /* Identify pixels that are either red or light background */
1795  pix3 = pixGetRGBComponent(pix1, COLOR_RED);
1796  pix4 = pixThresholdToBinary(pix3, 130);
1797  pixInvert(pix4, pix4);
1798 
1799  pixAnd(pix4, pix4, pix2);
1800  pixCountPixels(pix4, &count, NULL);
1801  pixGetDimensions(pix4, &w, &h, NULL);
1802  L_INFO("count = %d, thresh = %d\n", procName, count,
1803  (l_int32)(fract * w * h));
1804  ratio = (l_float32)count / (fract * w * h);
1805  if (pratio) *pratio = ratio;
1806  if (ratio >= 1.0)
1807  *phasred = 1;
1808  if (ppixdb)
1809  *ppixdb = pix4;
1810  else
1811  pixDestroy(&pix4);
1812  pixDestroy(&pix1);
1813  pixDestroy(&pix2);
1814  pixDestroy(&pix3);
1815  fpixDestroy(&fpix);
1816  return 0;
1817 }
PIX * pixMaskOverColorPixels(PIX *pixs, l_int32 threshdiff, l_int32 mindist)
pixMaskOverColorPixels()
Definition: colorcontent.c:502
PIX * pixConvertRGBToLuminance(PIX *pixs)
pixConvertRGBToLuminance()
Definition: pixconv.c:733
NUMA * pixGetGrayHistogram(PIX *pixs, l_int32 factor)
pixGetGrayHistogram()
Definition: pix4.c:109
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:322
PIX * pixConvertRGBToBinaryArb(PIX *pixs, l_float32 rc, l_float32 gc, l_float32 bc, l_int32 thresh, l_int32 relation)
pixConvertRGBToBinaryArb()
Definition: pixconv.c:1114
Definition: pix.h:717
PIX * fpixThresholdToPix(FPIX *fpix, l_float32 thresh)
fpixThresholdToPix()
Definition: fpix2.c:2335
l_ok pixSetMasked(PIX *pixd, PIX *pixm, l_uint32 val)
pixSetMasked()
Definition: pix3.c:155
Definition: pix.h:716
l_int32 n
Definition: ccbord.h:111
NUMA * numaGammaTRC(l_float32 gamma, l_int32 minval, l_int32 maxval)
numaGammaTRC()
Definition: enhance.c:366
PIX * pixMakeFrameMask(l_int32 w, l_int32 h, l_float32 hf1, l_float32 hf2, l_float32 vf1, l_float32 vf2)
pixSelectComponentBySize()
Definition: pix5.c:1465
NUMA * numaMakeConstant(l_float32 val, l_int32 size)
numaMakeConstant()
Definition: numafunc1.c:781
PIX * pixDilateBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateBrick()
Definition: morph.c:684
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
l_ok pixNumberOccupiedOctcubes(PIX *pix, l_int32 level, l_int32 mincount, l_float32 minfract, l_int32 *pncolors)
pixNumberOccupiedOctcubes()
Definition: colorquant1.c:4090
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:741
PIX * pixScaleAreaMap(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleAreaMap()
Definition: scale1.c:1912
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1395
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:580
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
l_ok pixNumColors(PIX *pixs, l_int32 factor, l_int32 *pncolors)
pixNumColors()
PIX * pixCreateTemplate(PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:367
Definition: pix.h:492
l_ok pixAssignToNearestColor(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 level, l_int32 *countarray)
pixAssignToNearestColor()
Definition: colorseg.c:412
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1573
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2404
l_ok pixColorsForQuantization(PIX *pixs, l_int32 thresh, l_int32 *pncolors, l_int32 *piscolor, l_int32 debug)
pixColorsForQuantization()
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:111
l_ok pixCombineMasked(PIX *pixd, PIX *pixs, PIX *pixm)
pixCombineMasked()
Definition: pix3.c:374
l_int32 * numaGetIArray(NUMA *na)
numaGetIArray()
Definition: numabasic.c:820
NUMA * pixGetRGBHistogram(PIX *pixs, l_int32 sigbits, l_int32 factor)
pixGetRGBHistogram()
l_ok pixGetRankColorArray(PIX *pixs, l_int32 nbins, l_int32 type, l_int32 factor, l_uint32 **pcarray, l_int32 debugflag, l_int32 fontsize)
pixGetRankColorArray()
Definition: pix4.c:2467
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:2393
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:503
Definition: array.h:59
PIX * pixCloseSafeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseSafeBrick()
Definition: morph.c:949
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
BOXA * pixConnCompBB(PIX *pixs, l_int32 connectivity)
pixConnCompBB()
Definition: conncomp.c:306
PIX * pixAnd(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixAnd()
Definition: pix3.c:1510
PIX * pixMorphSequence(PIX *pixs, const char *sequence, l_int32 dispsep)
pixMorphSequence()
Definition: morphseq.c:133
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1823
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_QBIT(pdata, n)
Definition: arrayaccess.h:164
l_int32 h
Definition: ccbord.h:110
PIX * pixConvertRGBToGrayMinMax(PIX *pixs, l_int32 type)
pixConvertRGBToGrayMinMax()
Definition: pixconv.c:887
l_int32 w
Definition: ccbord.h:109
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
PIX * pixRemoveBorderConnComps(PIX *pixs, l_int32 connectivity)
pixRemoveBorderConnComps()
Definition: seedfill.c:733
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:515
PIX * pixSubtract(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixSubtract()
Definition: pix3.c:1639
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
PIX * pixMaskBoxa(PIX *pixd, PIX *pixs, BOXA *boxa, l_int32 op)
pixMaskBoxa()
Definition: boxfunc3.c:148
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition: scale1.c:1445
l_ok pixcmapHasColor(PIXCMAP *cmap, l_int32 *pcolor)
pixcmapHasColor()
Definition: colormap.c:1002
Definition: pix.h:454
PIX * pixScaleAreaMap2(PIX *pix)
pixScaleAreaMap2()
Definition: scale1.c:2032
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
l_ok pixColorContent(PIX *pixs, l_int32 rwhite, l_int32 gwhite, l_int32 bwhite, l_int32 mingray, PIX **ppixr, PIX **ppixg, PIX **ppixb)
pixColorContent()
Definition: colorcontent.c:179
l_ok pixNumSignificantGrayColors(PIX *pixs, l_int32 darkthresh, l_int32 lightthresh, l_float32 minfract, l_int32 factor, l_int32 *pncolors)
pixNumSignificantGrayColors()
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
PIX * pixConvertRGBToGray(PIX *pixs, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixConvertRGBToGray()
Definition: pixconv.c:753
PIX * pixOr(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixOr()
Definition: pix3.c:1446
l_ok makeRGBIndexTables(l_uint32 **prtab, l_uint32 **pgtab, l_uint32 **pbtab, l_int32 sigbits)
makeRGBIndexTables()
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:805
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:678
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:865
#define GET_DATA_DIBIT(pdata, n)
Definition: arrayaccess.h:145
Definition: pix.h:718
BOXA * boxaCombineOverlaps(BOXA *boxas, PIXA *pixadb)
boxaCombineOverlaps()
Definition: boxfunc1.c:441
PIX * pixSimpleColorQuantize(PIX *pixs, l_int32 sigbits, l_int32 factor, l_int32 ncolors)
pixSimpleColorQuantize()
l_int32 pixcmapGetCount(PIXCMAP *cmap)
pixcmapGetCount()
Definition: colormap.c:635
NUMA * numaSortIndexAutoSelect(NUMA *nas, l_int32 sortorder)
numaSortIndexAutoSelect()
Definition: numafunc1.c:2460
Definition: pix.h:134
PIX * pixColorMagnitude(PIX *pixs, l_int32 rwhite, l_int32 gwhite, l_int32 bwhite, l_int32 type)
pixColorMagnitude()
Definition: colorcontent.c:363
PIX * pixSobelEdgeFilter(PIX *pixs, l_int32 orientflag)
pixSobelEdgeFilter()
Definition: edge.c:91
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:628
Definition: pix.h:201
PIX * pixDisplayColorArray(l_uint32 *carray, l_int32 ncolors, l_int32 side, l_int32 ncols, l_int32 fontsize)
pixDisplayColorArray()
Definition: pix4.c:2759
PIX * pixErodeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeBrick()
Definition: morph.c:748
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2671
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:569
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:341
void fpixDestroy(FPIX **pfpix)
fpixDestroy()
Definition: fpix1.c:373
l_ok pixHasHighlightRed(PIX *pixs, l_int32 factor, l_float32 fract, l_float32 fthresh, l_int32 *phasred, l_float32 *pratio, PIX **ppixdb)
pixHasHighlightRed()
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2737
l_ok getRGBFromIndex(l_uint32 index, l_int32 sigbits, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
getRGBFromIndex()
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:127
Definition: pix.h:582