Leptonica  1.82.0
Image processing and image analysis suite
colorfill.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 
58 #ifdef HAVE_CONFIG_H
59 #include <config_auto.h>
60 #endif /* HAVE_CONFIG_H */
61 
62 #include "allheaders.h"
63 
64 struct ColorEl {
65  l_int32 x;
66  l_int32 y;
67  l_uint32 color;
68 };
69 typedef struct ColorEl COLOREL;
70 
71  /* Ignore pixels with smaller max component */
72 static l_int32 DefaultMinMax = 70;
73 
74  /* Static helpers */
75 static COLOREL *colorelCreate(l_int32 x, l_int32 y, l_uint32 color);
76 static void pixColorFillFromSeed(PIX *pixs, PIX *pixv, PTA **ppta,
77  l_int32 x, l_int32 y, L_QUEUE *lq,
78  l_int32 maxdiff, l_int32 minarea,
79  l_int32 debug);
80 static void pixGetVisitedNeighbors(PIX *pixs, l_int32 x, l_int32 y,
81  l_uint32 *visited);
82 static l_int32 findNextUnvisited(PIX *pixv, l_int32 *px, l_int32 *py);
83 static l_int32 colorsAreSimilarForFill(l_uint32 val1, l_uint32 val2,
84  l_int32 maxdiff);
85 static l_int32 pixelColorIsValid(l_uint32 val, l_int32 minmax);
86 static l_int32 pixelIsOnColorBoundary(PIX *pixs, l_int32 x, l_int32 y);
87 static l_int32 evalColorfillData(L_COLORFILL *cf, l_int32 debug);
88 
89 
90 /*---------------------------------------------------------------------*
91  * Colorfill creation and destruction *
92  *---------------------------------------------------------------------*/
106 L_COLORFILL *
108  l_int32 nx,
109  l_int32 ny)
110 {
111 l_int32 i, j, w, h, tw, th, ntiles;
112 BOX *box;
113 BOXA *boxas;
114 L_COLORFILL *cf;
115 
116  PROCNAME("l_colorfillCreate");
117 
118  if (!pixs)
119  return (L_COLORFILL *)ERROR_PTR("pixs not defined", procName, NULL);
120  if (pixGetDepth(pixs) != 32)
121  return (L_COLORFILL *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
122 
123  pixGetDimensions(pixs, &w, &h, NULL);
124  tw = w / nx;
125  th = h / ny;
126  if (tw < 10 || th < 10)
127  return (L_COLORFILL *)ERROR_PTR("tile size too small", procName, NULL);
128  boxas = boxaCreate(nx * ny);
129  for (i = 0; i < ny; i++) {
130  for (j = 0; j < nx; j++) {
131  box = boxCreate(j * tw, i * th, tw, th);
132  boxaAddBox(boxas, box, L_INSERT);
133  }
134  }
135  ntiles = nx * ny;
136 
137  cf = (L_COLORFILL *)LEPT_CALLOC(1, sizeof(L_COLORFILL));
138  cf->pixs = pixClone(pixs);
139  cf->nx = nx;
140  cf->ny = ny;
141  cf->tw = tw;
142  cf->th = th;
143  cf->boxas = boxas;
144  cf->naa = numaaCreate(ntiles);
145  cf->dnaa = l_dnaaCreate(ntiles);
146  cf->pixadb = pixaCreate(0);
147  return cf;
148 }
149 
150 
157 void
159 {
160 L_COLORFILL *cf;
161 
162  PROCNAME("l_colorfillDestroy");
163 
164  if (pcf == NULL) {
165  L_WARNING("ptr address is null!\n", procName);
166  return;
167  }
168 
169  if ((cf = *pcf) == NULL)
170  return;
171 
172  pixDestroy(&cf->pixs);
173  pixDestroy(&cf->pixst);
174  boxaDestroy(&cf->boxas);
175  pixaDestroy(&cf->pixas);
176  pixaDestroy(&cf->pixam);
177  numaaDestroy(&cf->naa);
178  l_dnaaDestroy(&cf->dnaa);
179  pixaDestroy(&cf->pixadb);
180  LEPT_FREE(cf);
181  *pcf = NULL;
182 }
183 
184 
185 /* ----------------------------------------------------------------------- *
186  * Determine color content using proximity. What do we get when *
187  * growing regions with nearly the same color? *
188  * ----------------------------------------------------------------------- */
225 l_ok
227  l_int32 rref,
228  l_int32 gref,
229  l_int32 bref,
230  l_int32 minmax,
231  l_int32 maxdiff,
232  l_int32 minarea,
233  l_int32 smooth,
234  l_int32 debug)
235 {
236 l_int32 i, n;
237 PIX *pix1, *pix2, *pix3;
238 PIXA *pixas, *pixam;
239 
240  PROCNAME("pixColorContentByLocation");
241 
242  if (!cf)
243  return ERROR_INT("cf not defined", procName, 1);
244  if (minmax <= 0) minmax = DefaultMinMax;
245  if (minmax > 200)
246  return ERROR_INT("minmax > 200; unreasonably large", procName, 1);
247 
248  /* Do the optional linear color map; this checks the ref vals
249  * and uses them if valid. Use {0,0,0} to skip this operation. */
250  if ((pix1 = pixColorShiftWhitePoint(cf->pixs, rref, gref, bref)) == NULL)
251  return ERROR_INT("pix1 not returned", procName, 1);
252  cf->pixst = pix1;
253 
254  /* Break the image up into small tiles */
255  pixas = pixaCreateFromBoxa(pix1, cf->boxas, 0, 0, NULL);
256  cf->pixas = pixas;
257 
258  /* Find regions of similar color in each tile */
259  n = pixaGetCount(pixas);
260  pixam = pixaCreate(n);
261  cf->pixam = pixam;
262  for (i = 0; i < n; i++) {
263  pix2 = pixaGetPix(pixas, i, L_COPY);
264  pix3 = pixColorFill(pix2, minmax, maxdiff, smooth, minarea, 0);
265  pixDestroy(&pix2);
266  pixaAddPix(pixam, pix3, L_INSERT);
267  }
268 
269  /* Evaluate color components. Find the average color in each
270  * component and determine if there is more than one color in
271  * each of the tiles. */
272  evalColorfillData(cf, debug);
273 
274  return 0;
275 }
276 
277 
298 PIX *
300  l_int32 minmax,
301  l_int32 maxdiff,
302  l_int32 smooth,
303  l_int32 minarea,
304  l_int32 debug)
305 {
306 l_int32 x, y, w, h, empty;
307 l_uint32 val;
308 L_KERNEL *kel;
309 PIX *pixm, *pixm1, *pixv, *pixnc, *pixncd, *pixss, *pixf;
310 PTA *pta1;
311 L_QUEUE *lq;
312 
313  PROCNAME("pixColorFill");
314 
315  if (!pixs || pixGetDepth(pixs) != 32)
316  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
317 
318  /* Set the non-color pixels to 0; generate a mask representing them */
319  pixGetDimensions(pixs, &w, &h, NULL);
320  pixnc = pixCreate(w, h, 1); /* mask for no color */
321  for (y = 0; y < h; y++) {
322  for (x = 0; x < w; x++) {
323  pixGetPixel(pixs, x, y, &val);
324  if (!pixelColorIsValid(val, minmax)) {
325  pixSetPixel(pixnc, x, y, 1);
326  pixSetPixel(pixs, x, y, 0x0);
327  }
328  }
329  }
330 
331  /* Optionally, dilate the no-color mask */
332  pixncd = pixDilateBrick(NULL, pixnc, smooth, smooth);
333  pixDestroy(&pixnc);
334 
335  /* Do a low-pass filter on pixs. This will make bad pixels
336  * near the zeroed non-color pixels, but any components made
337  * from these pixels will be removed at the end by the
338  * (optionally dilated) no-color mask. */
339  if (smooth > 1) {
340  kel = makeFlatKernel(smooth, smooth, smooth / 2, smooth / 2);
341  pixss = pixConvolveRGBSep(pixs, kel, kel);
342  kernelDestroy(&kel);
343  } else {
344  pixss = pixCopy(NULL, pixs);
345  }
346 
347  /* Paint through everything under pixncd */
348  pixPaintThroughMask(pixss, pixncd, 0, 0, 0);
349 
350  /* Find the color components */
351  pixv = pixCreate(w, h, 1); /* visited pixels */
352  pixOr(pixv, pixv, pixncd); /* consider non-color as visited */
353  pixSetBorderRingVal(pixv, 1, 1);
354  pixm = pixCreate(w, h, 1); /* color components */
355  lq = lqueueCreate(0);
356  x = y = 1; /* first row and column have been marked as visited */
357  while (findNextUnvisited(pixv, &x, &y) == 1) {
358  /* Flood fill this component, starting from (x,y) */
359  if (debug) lept_stderr("Start: x = %d, y = %d\n", x, y);
360  pixColorFillFromSeed(pixss, pixv, &pta1, x, y, lq, maxdiff,
361  minarea, debug);
362  if (pta1) { /* erode and add the pixels to pixm */
363  pixm1 = pixGenerateFromPta(pta1, w, h);
364  pixErodeBrick(pixm1, pixm1, 3, 3);
365  pixOr(pixm, pixm, pixm1);
366  pixDestroy(&pixm1);
367  ptaDestroy(&pta1);
368  }
369  }
370  pixDestroy(&pixv);
371 
372  /* Remove everything under pixncd */
373  pixSubtract(pixm, pixm, pixncd);
374 
375  /* Remove remaining small stuff */
376  pixf = pixSelectByArea(pixm, minarea, 4, L_SELECT_IF_GTE, NULL);
377 
378  lqueueDestroy(&lq, 1);
379  pixDestroy(&pixncd);
380  pixDestroy(&pixss);
381  pixDestroy(&pixm);
382  return pixf;
383 }
384 
385 
386 /* ----------------------------------------------------------------------- *
387  * Generate data for testing *
388  * ----------------------------------------------------------------------- */
411 PIXA *
413  l_int32 h,
414  l_int32 nseeds,
415  l_int32 range)
416 {
417 l_int32 i, j, x, y, rval, gval, bval, start, end;
418 l_uint32 color;
419 l_float64 dval;
420 L_DNA *da;
421 PIX *pix1, *pix2, *pix3, *pix4;
422 PIXA *pixa;
423 PTA *pta;
424 PIXCMAP *cmap;
425 
426  /* Generate data for seeds */
427  pta = ptaCreate(nseeds); /* for seed locations */
428  da = l_dnaCreate(nseeds); /* for colors */
429  srand(4);
430  start = 128 - range / 2;
431  end = 128 + (range - 1) / 2;
432  for (i = 0; i < nseeds; i++) {
433  genRandomIntOnInterval(0, w - 1, 0, &x);
434  genRandomIntOnInterval(0, h - 1, 0, &y);
435  ptaAddPt(pta, x, y);
436  genRandomIntOnInterval(start, end, 0, &rval);
437  genRandomIntOnInterval(start, end, 0, &gval);
438  genRandomIntOnInterval(start, end, 0, &bval);
439  composeRGBPixel(rval, gval, bval, &color);
440  l_dnaAddNumber(da, color);
441  }
442 
443  /* Generate the 8 bpp seed image */
444  pix1 = pixCreate(w, h, 8);
445  for (i = 0; i < nseeds; i++) {
446  ptaGetIPt(pta, i, &x, &y);
447  pixSetPixel(pix1, x, y, i + 1); /* all seeds have non-zero values */
448  }
449 
450  /* Spread seed values to all pixels that are nearest to
451  * the seed pixel from which they take their value. */
452  pix2 = pixSeedspread(pix1, 4);
453 
454  /* Add a colormap for the random colors, using 0 for black */
455  cmap = pixcmapCreate(8);
456  pixcmapAddColor(cmap, 0, 0, 0);
457  for (i = 0; i < nseeds; i++) {
458  l_dnaGetDValue(da, i, &dval);
459  extractRGBValues(dval, &rval, &gval, &bval);
460  pixcmapAddColor(cmap, rval, gval, bval);
461  }
462  pixSetColormap(pix2, cmap);
463  pixDestroy(&pix1);
464  ptaDestroy(&pta);
465  l_dnaDestroy(&da);
466 
467  /* Add to output; no black boundaries */
468  pixa = pixaCreate(0);
469  pixaAddPix(pixa, pix2, L_COPY);
470 
471  /* Make pixels on the color boundaries black */
472  pix3 = pixCopy(NULL, pix2);
473  for (i = 0; i < h; i++) {
474  for (j = 0; j < w; j++) {
475  if (pixelIsOnColorBoundary(pix2, j, i))
476  pixSetPixel(pix3, j, i, 0); /* black */
477  }
478  }
479  pixaAddPix(pixa, pix3, L_INSERT);
480  pixDestroy(&pix2);
481 
482  /* Have all the non-black regions be the same color */
483  cmap = pixcmapCreate(8);
484  pixcmapAddColor(cmap, 0, 0, 0);
485  for (i = 0; i < nseeds; i++)
486  pixcmapAddColor(cmap, rval, gval, bval);
487  pix4 = pixCopy(NULL, pix3);
488  pixSetColormap(pix4, cmap);
489  pixaAddPix(pixa, pix4, L_INSERT);
490 
491  return pixa;
492 }
493 
494 
495 /* ----------------------------------------------------------------------- *
496  * Static helpers *
497  * ----------------------------------------------------------------------- */
498 static COLOREL *
499 colorelCreate(l_int32 x,
500  l_int32 y,
501  l_uint32 color)
502 {
503 COLOREL *el;
504 
505  el = (COLOREL *)LEPT_CALLOC(1, sizeof(COLOREL));
506  el->x = x;
507  el->y = y;
508  el->color = color;
509  return el;
510 }
511 
536 static void
538  PIX *pixv,
539  PTA **ppta,
540  l_int32 x,
541  l_int32 y,
542  L_QUEUE *lq,
543  l_int32 maxdiff,
544  l_int32 minarea,
545  l_int32 debug)
546 {
547 l_int32 w, h, np;
548 l_uint32 visited[8]; /* W, N, E, S, NW, NE, SW, SE */
549 l_uint32 color, val;
550 COLOREL *el;
551 PTA *pta;
552 
553  /* Prime the queue with this pixel */
554  pixGetPixel(pixs, x, y, &val);
555  el = colorelCreate(x, y, val);
556  lqueueAdd(lq, el);
557  pixSetPixel(pixv, x, y, 1); /* visited */
558  pta = ptaCreate(0);
559  *ppta = pta;
560  ptaAddPt(pta, x, y);
561 
562  /* Trace out the color component. Each pixel on the queue has
563  * a color. Pop from the queue and for each of its 8 neighbors,
564  * for those that have color:
565  * - If the pixel has a similar color, add to the pta array for
566  * the component, using the color of its parent.
567  * - Mark visited so that it will not be included in another
568  * component -- this effectively separates the growing component
569  * from all others. */
570  pixGetDimensions(pixs, &w, &h, NULL);
571  while (lqueueGetCount(lq) > 0) {
572  el = (COLOREL *)lqueueRemove(lq);
573  x = el->x;
574  y = el->y;
575  color = el->color;
576  LEPT_FREE(el);
577  pixGetVisitedNeighbors(pixv, x, y, visited);
578  if (!visited[0]) { /* check W */
579  pixGetPixel(pixs, x - 1, y, &val);
580  if (colorsAreSimilarForFill(color, val, maxdiff)) {
581  el = colorelCreate(x - 1, y, color);
582  lqueueAdd(lq, el);
583  ptaAddPt(pta, x - 1, y); /* added to component */
584  pixSetPixel(pixv, x - 1, y, 1); /* visited */
585  }
586  }
587  if (!visited[1]) { /* check N */
588  pixGetPixel(pixs, x, y - 1, &val);
589  if (colorsAreSimilarForFill(color, val, maxdiff)) {
590  el = colorelCreate(x, y - 1, color);
591  lqueueAdd(lq, el);
592  ptaAddPt(pta, x, y - 1);
593  pixSetPixel(pixv, x, y - 1, 1);
594  }
595  }
596  if (!visited[2]) { /* check E */
597  pixGetPixel(pixs, x + 1, y, &val);
598  if (colorsAreSimilarForFill(color, val, maxdiff)) {
599  el = colorelCreate(x + 1, y, color);
600  lqueueAdd(lq, el);
601  ptaAddPt(pta, x + 1, y);
602  pixSetPixel(pixv, x + 1, y, 1);
603  }
604  }
605  if (!visited[3]) { /* check S */
606  pixGetPixel(pixs, x, y + 1, &val);
607  if (colorsAreSimilarForFill(color, val, maxdiff)) {
608  el = colorelCreate(x, y + 1, color);
609  lqueueAdd(lq, el);
610  ptaAddPt(pta, x, y + 1);
611  pixSetPixel(pixv, x, y + 1, 1);
612  }
613  }
614  if (!visited[4]) { /* check NW */
615  pixGetPixel(pixs, x - 1, y - 1, &val);
616  if (colorsAreSimilarForFill(color, val, maxdiff)) {
617  el = colorelCreate(x - 1, y - 1, color);
618  lqueueAdd(lq, el);
619  ptaAddPt(pta, x - 1, y - 1);
620  pixSetPixel(pixv, x - 1, y - 1, 1);
621  }
622  }
623  if (!visited[5]) { /* check NE */
624  pixGetPixel(pixs, x + 1, y - 1, &val);
625  if (colorsAreSimilarForFill(color, val, maxdiff)) {
626  el = colorelCreate(x + 1, y - 1, color);
627  lqueueAdd(lq, el);
628  ptaAddPt(pta, x + 1, y - 1);
629  pixSetPixel(pixv, x + 1, y - 1, 1);
630  }
631  }
632  if (!visited[6]) { /* check SW */
633  pixGetPixel(pixs, x - 1, y + 1, &val);
634  if (colorsAreSimilarForFill(color, val, maxdiff)) {
635  el = colorelCreate(x - 1, y + 1, color);
636  lqueueAdd(lq, el);
637  ptaAddPt(pta, x - 1, y + 1);
638  pixSetPixel(pixv, x - 1, y + 1, 1);
639  }
640  }
641  if (!visited[7]) { /* check SE */
642  pixGetPixel(pixs, x + 1, y + 1, &val);
643  if (colorsAreSimilarForFill(color, val, maxdiff)) {
644  el = colorelCreate(x + 1, y + 1, color);
645  lqueueAdd(lq, el);
646  ptaAddPt(pta, x + 1, y + 1);
647  pixSetPixel(pixv, x + 1, y + 1, 1);
648  }
649  }
650  }
651 
652  /* If there are not enough pixels, do not return the pta.
653  * Otherwise, if a pta is returned, the caller will generate
654  * a component and put it in the mask. */
655  np = ptaGetCount(pta);
656  if (np < minarea) {
657  if (debug) lept_stderr(" Too small. End: x = %d, y = %d, np = %d\n",
658  x, y, np);
659  ptaDestroy(ppta);
660  } else {
661  if (debug) lept_stderr(" Keep. End: x = %d, y = %d, np = %d\n",
662  x, y, np);
663  }
664 }
665 
666 
686 static void
688  l_int32 x,
689  l_int32 y,
690  l_uint32 *visited)
691 {
692  pixGetPixel(pixs, x - 1, y, visited); /* W */
693  pixGetPixel(pixs, x, y - 1, visited + 1); /* N */
694  pixGetPixel(pixs, x + 1, y, visited + 2); /* E */
695  pixGetPixel(pixs, x, y + 1, visited + 3); /* S */
696  pixGetPixel(pixs, x - 1, y - 1, visited + 4); /* NW */
697  pixGetPixel(pixs, x + 1, y - 1, visited + 5); /* NE */
698  pixGetPixel(pixs, x - 1, y + 1, visited + 6); /* SW */
699  pixGetPixel(pixs, x + 1, y + 1, visited + 7); /* SE */
700 }
701 
702 
717 static l_int32
719  l_int32 *px,
720  l_int32 *py)
721 {
722 l_int32 ret;
723 PIX *pix1;
724 
725  pix1 = pixCopy(NULL, pixv);
726  pixInvert(pix1, pix1); /* After inversion, ON pixels are unvisited */
727  ret = nextOnPixelInRaster(pix1, 1, *py, px, py);
728  pixDestroy(&pix1);
729  return ret;
730 }
731 
732 
757 static l_int32
759  l_uint32 val2,
760  l_int32 maxdiff)
761 {
762 l_int32 rdiff, gdiff, bdiff, maxindex, del1, del2, del3, maxdel;
763 l_int32 v1[3], v2[3];
764 
765  extractRGBValues(val1, v1, v1 + 1, v1 + 2);
766  extractRGBValues(val2, v2, v2 + 1, v2 + 2);
767  rdiff = v1[0] - v2[0];
768  gdiff = v1[1] - v2[1];
769  bdiff = v1[2] - v2[2];
770  maxindex = 0;
771  if (L_ABS(gdiff) > L_ABS(rdiff))
772  maxindex = 1;
773  if (L_ABS(bdiff) > L_ABS(rdiff) && L_ABS(bdiff) > L_ABS(gdiff))
774  maxindex = 2;
775  del1 = v1[maxindex] - v2[maxindex];
776  del2 = v1[(maxindex + 1) % 3] - v2[(maxindex + 1) % 3];
777  del3 = v1[(maxindex + 2) % 3] - v2[(maxindex + 2) % 3];
778  maxdel = L_MAX(L_ABS(del1 - del2), L_ABS(del1 - del3));
779  return (maxdel <= maxdiff) ? 1 : 0;
780 }
781 
782 
790 static l_int32
791 pixelColorIsValid(l_uint32 val,
792  l_int32 minmax)
793 {
794 l_int32 rval, gval, bval;
795 
796  extractRGBValues(val, &rval, &gval, &bval);
797  if (rval < minmax && gval < minmax && bval < minmax)
798  return 0; /* maximum component is less than threshold */
799  else
800  return 1;
801 }
802 
803 
812 static l_int32
814  l_int32 x,
815  l_int32 y)
816 {
817 l_int32 w, h;
818 l_uint32 val, neigh;
819 
820  pixGetDimensions(pixs, &w, &h, NULL);
821  pixGetPixel(pixs, x, y, &val);
822  if (x > 0) {
823  pixGetPixel(pixs, x - 1, y, &neigh); /* W */
824  if (neigh != val) return TRUE;
825  }
826  if (x < w - 1) {
827  pixGetPixel(pixs, x + 1, y, &neigh); /* E */
828  if (neigh != val) return TRUE;
829  }
830  if (y > 0) {
831  pixGetPixel(pixs, x, y - 1, &neigh); /* N */
832  if (neigh != val) return TRUE;
833  }
834  if (y < h - 1) {
835  pixGetPixel(pixs, x, y + 1, &neigh); /* S */
836  if (neigh != val) return TRUE;
837  }
838  return FALSE;
839 }
840 
841 
849 static l_int32
851  l_int32 debug)
852 {
853 l_int32 i, j, n, nc, w, h, x, y, count;
854 l_float32 rval, gval, bval;
855 l_uint32 pixel;
856 l_int32 *tab;
857 BOX *box1;
858 BOXA *boxa1;
859 L_DNA *da;
860 NUMA *na;
861 PIX *pixm, *pix1, *pix2, *pixdb;
862 PIXA *pixa1;
863 
864  PROCNAME("evalColorfillData");
865 
866  if (!cf)
867  return ERROR_INT("cf not defind", procName, 1);
868 
869  tab = makePixelSumTab8();
870  n = cf->nx * cf->ny;
871  for (i = 0; i < n; i++) {
872  pix1 = pixaGetPix(cf->pixas, i, L_CLONE);
873  pixm = pixaGetPix(cf->pixam, i, L_CLONE);
874  pixGetDimensions(pix1, &w, &h, NULL);
875  boxa1 = pixConnComp(pixm, &pixa1, 4);
876  boxaDestroy(&boxa1);
877  nc = pixaGetCount(pixa1);
878  na = numaCreate(0);
879  da = l_dnaCreate(0);
880  pixdb = (debug) ? pixCreate(w, h, 32) : NULL;
881  for (j = 0; j < nc; j++) {
882  pix2 = pixaGetPix(pixa1, j, L_COPY);
883  box1 = pixaGetBox(pixa1, j, L_COPY);
884  boxGetGeometry(box1, &x, &y, NULL, NULL);
885  pixGetRankValueMaskedRGB(pix1, pix2, x, y, 1, 0.5,
886  &rval, &gval, &bval);
887  composeRGBPixel(rval, gval, bval, &pixel);
888 
889  l_dnaAddNumber(da, pixel);
890  pixCountPixels(pix2, &count, tab);
891  numaAddNumber(na, count);
892  if (debug)
893  pixPaintThroughMask(pixdb, pix2, x, y, pixel);
894  boxDestroy(&box1);
895  pixDestroy(&pix2);
896  }
897  pixaAddPix(cf->pixadb, pixdb, L_INSERT);
898  numaaAddNuma(cf->naa, na, L_INSERT);
899  l_dnaaAddDna(cf->dnaa, da, L_INSERT);
900  pixDestroy(&pix1);
901  pixDestroy(&pixm);
902  pixaDestroy(&pixa1);
903  }
904 
905  if (debug) { /* first tile */
906  na = numaaGetNuma(cf->naa, 0, L_CLONE);
907  lept_stderr("Size of components in tile 0:");
908  numaWriteStderr(na);
909  numaDestroy(&na);
910  }
911  LEPT_FREE(tab);
912  return 0;
913 }
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:313
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:620
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:172
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:502
PIX * pixColorShiftWhitePoint(PIX *pixs, l_int32 rref, l_int32 gref, l_int32 bref)
pixColorShiftWhitePoint()
Definition: colorcontent.c:583
PIX * pixColorFill(PIX *pixs, l_int32 minmax, l_int32 maxdiff, l_int32 smooth, l_int32 minarea, l_int32 debug)
pixColorFill()
Definition: colorfill.c:299
PIXA * makeColorfillTestData(l_int32 w, l_int32 h, l_int32 nseeds, l_int32 range)
makeColorfillTestData()
Definition: colorfill.c:412
static l_int32 pixelColorIsValid(l_uint32 val, l_int32 minmax)
pixelColorIsValid()
Definition: colorfill.c:791
l_ok pixColorContentByLocation(L_COLORFILL *cf, l_int32 rref, l_int32 gref, l_int32 bref, l_int32 minmax, l_int32 maxdiff, l_int32 minarea, l_int32 smooth, l_int32 debug)
pixColorContentByLocation()
Definition: colorfill.c:226
static void pixColorFillFromSeed(PIX *pixs, PIX *pixv, PTA **ppta, l_int32 x, l_int32 y, L_QUEUE *lq, l_int32 maxdiff, l_int32 minarea, l_int32 debug)
pixColorFillFromSeed()
Definition: colorfill.c:537
void l_colorfillDestroy(L_COLORFILL **pcf)
l_colorfillDestroy()
Definition: colorfill.c:158
L_COLORFILL * l_colorfillCreate(PIX *pixs, l_int32 nx, l_int32 ny)
l_colorfillCreate()
Definition: colorfill.c:107
static l_int32 colorsAreSimilarForFill(l_uint32 val1, l_uint32 val2, l_int32 maxdiff)
colorsAreSimilarForFill()
Definition: colorfill.c:758
static l_int32 pixelIsOnColorBoundary(PIX *pixs, l_int32 x, l_int32 y)
pixelIsOnColorBoundary()
Definition: colorfill.c:813
static l_int32 evalColorfillData(L_COLORFILL *cf, l_int32 debug)
evalColorfillData()
Definition: colorfill.c:850
static void pixGetVisitedNeighbors(PIX *pixs, l_int32 x, l_int32 y, l_uint32 *visited)
pixGetVisitedNeighbors()
Definition: colorfill.c:687
static l_int32 findNextUnvisited(PIX *pixv, l_int32 *px, l_int32 *py)
findNextUnvisited()
Definition: colorfill.c:718
PIXCMAP * pixcmapCreate(l_int32 depth)
pixcmapCreate()
Definition: colormap.c:125
l_ok pixcmapAddColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval)
pixcmapAddColor()
Definition: colormap.c:414
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:151
l_int32 nextOnPixelInRaster(PIX *pixs, l_int32 xstart, l_int32 ystart, l_int32 *px, l_int32 *py)
nextOnPixelInRaster()
Definition: conncomp.c:457
PIX * pixConvolveRGBSep(PIX *pixs, L_KERNEL *kelx, L_KERNEL *kely)
pixConvolveRGBSep()
Definition: convolve.c:2141
L_DNA * l_dnaCreate(l_int32 n)
l_dnaCreate()
Definition: dnabasic.c:180
l_ok l_dnaAddNumber(L_DNA *da, l_float64 val)
l_dnaAddNumber()
Definition: dnabasic.c:448
L_DNAA * l_dnaaCreate(l_int32 n)
l_dnaaCreate()
Definition: dnabasic.c:1285
l_ok l_dnaGetDValue(L_DNA *da, l_int32 index, l_float64 *pval)
l_dnaGetDValue()
Definition: dnabasic.c:692
l_ok l_dnaaAddDna(L_DNAA *daa, L_DNA *da, l_int32 copyflag)
l_dnaaAddDna()
Definition: dnabasic.c:1421
void l_dnaDestroy(L_DNA **pda)
l_dnaDestroy()
Definition: dnabasic.c:332
void l_dnaaDestroy(L_DNAA **pdaa)
l_dnaaDestroy()
Definition: dnabasic.c:1386
L_KERNEL * makeFlatKernel(l_int32 height, l_int32 width, l_int32 cy, l_int32 cx)
makeFlatKernel()
Definition: kernel.c:1107
void kernelDestroy(L_KERNEL **pkel)
kernelDestroy()
Definition: kernel.c:150
PIX * pixErodeBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeBrick()
Definition: morph.c:758
PIX * pixDilateBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateBrick()
Definition: morph.c:688
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
l_ok numaWriteStderr(NUMA *na)
numaWriteStderr()
Definition: numabasic.c:1313
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1740
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
NUMAA * numaaCreate(l_int32 n)
numaaCreate()
Definition: numabasic.c:1407
l_ok numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1546
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1510
l_ok pixSetColormap(PIX *pix, PIXCMAP *colormap)
pixSetColormap()
Definition: pix1.c:1699
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
l_ok pixSetBorderRingVal(PIX *pixs, l_int32 dist, l_uint32 val)
pixSetBorderRingVal()
Definition: pix2.c:1667
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:263
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:190
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2751
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2820
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1509
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:626
l_ok pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1937
PIX * pixOr(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixOr()
Definition: pix3.c:1560
l_int32 * makePixelSumTab8(void)
makePixelSumTab8()
Definition: pix3.c:2411
PIX * pixSubtract(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixSubtract()
Definition: pix3.c:1753
l_ok pixGetRankValueMaskedRGB(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 factor, l_float32 rank, l_float32 *prval, l_float32 *pgval, l_float32 *pbval)
pixGetRankValueMaskedRGB()
Definition: pix4.c:1076
@ L_SELECT_IF_GTE
Definition: pix.h:785
@ L_COPY
Definition: pix.h:712
@ L_CLONE
Definition: pix.h:713
@ L_INSERT
Definition: pix.h:711
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
BOX * pixaGetBox(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetBox()
Definition: pixabasic.c:816
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:650
PIXA * pixaCreateFromBoxa(PIX *pixs, BOXA *boxa, l_int32 start, l_int32 num, l_int32 *pcropwarn)
pixaCreateFromBoxa()
Definition: pixabasic.c:272
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
PIX * pixSelectByArea(PIX *pixs, l_float32 thresh, l_int32 connectivity, l_int32 type, l_int32 *pchanged)
pixSelectByArea()
Definition: pixafunc1.c:848
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:578
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:343
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:527
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:120
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:195
PIX * pixGenerateFromPta(PTA *pta, l_int32 w, l_int32 h)
pixGenerateFromPta()
Definition: ptafunc1.c:2023
l_int32 lqueueGetCount(L_QUEUE *lq)
lqueueGetCount()
Definition: queue.c:286
void lqueueDestroy(L_QUEUE **plq, l_int32 freeflag)
lqueueDestroy()
Definition: queue.c:134
void * lqueueRemove(L_QUEUE *lq)
lqueueRemove()
Definition: queue.c:257
l_ok lqueueAdd(L_QUEUE *lq, void *item)
lqueueAdd()
Definition: queue.c:188
L_QUEUE * lqueueCreate(l_int32 nalloc)
lqueueCreate()
Definition: queue.c:93
PIX * pixSeedspread(PIX *pixs, l_int32 connectivity)
pixSeedspread()
Definition: seedfill.c:2792
Definition: pix.h:481
Definition: pix.h:492
struct Pix * pixst
Definition: colorfill.h:50
l_int32 tw
Definition: colorfill.h:53
struct Boxa * boxas
Definition: colorfill.h:56
l_int32 th
Definition: colorfill.h:54
struct Pix * pixs
Definition: colorfill.h:49
struct Pixa * pixadb
Definition: colorfill.h:62
l_int32 nx
Definition: colorfill.h:51
struct Numaa * naa
Definition: colorfill.h:60
struct Pixa * pixas
Definition: colorfill.h:57
struct Pixa * pixam
Definition: colorfill.h:58
struct L_Dnaa * dnaa
Definition: colorfill.h:61
l_int32 ny
Definition: colorfill.h:52
Definition: array.h:95
Definition: morph.h:89
Definition: queue.h:65
Definition: array.h:71
Definition: pix.h:139
Definition: pix.h:456
Definition: pix.h:517
l_ok genRandomIntOnInterval(l_int32 start, l_int32 end, l_int32 seed, l_int32 *pval)
genRandomIntOnInterval()
Definition: utils1.c:659
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306