Leptonica  1.83.1
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  if (!pixs)
117  return (L_COLORFILL *)ERROR_PTR("pixs not defined", __func__, NULL);
118  if (pixGetDepth(pixs) != 32)
119  return (L_COLORFILL *)ERROR_PTR("pixs not 32 bpp", __func__, NULL);
120 
121  pixGetDimensions(pixs, &w, &h, NULL);
122  tw = w / nx;
123  th = h / ny;
124  if (tw < 10 || th < 10)
125  return (L_COLORFILL *)ERROR_PTR("tile size too small", __func__, NULL);
126  boxas = boxaCreate(nx * ny);
127  for (i = 0; i < ny; i++) {
128  for (j = 0; j < nx; j++) {
129  box = boxCreate(j * tw, i * th, tw, th);
130  boxaAddBox(boxas, box, L_INSERT);
131  }
132  }
133  ntiles = nx * ny;
134 
135  cf = (L_COLORFILL *)LEPT_CALLOC(1, sizeof(L_COLORFILL));
136  cf->pixs = pixClone(pixs);
137  cf->nx = nx;
138  cf->ny = ny;
139  cf->tw = tw;
140  cf->th = th;
141  cf->boxas = boxas;
142  cf->naa = numaaCreate(ntiles);
143  cf->dnaa = l_dnaaCreate(ntiles);
144  cf->pixadb = pixaCreate(0);
145  return cf;
146 }
147 
148 
155 void
157 {
158 L_COLORFILL *cf;
159 
160  if (pcf == NULL) {
161  L_WARNING("ptr address is null!\n", __func__);
162  return;
163  }
164 
165  if ((cf = *pcf) == NULL)
166  return;
167 
168  pixDestroy(&cf->pixs);
169  pixDestroy(&cf->pixst);
170  boxaDestroy(&cf->boxas);
171  pixaDestroy(&cf->pixas);
172  pixaDestroy(&cf->pixam);
173  numaaDestroy(&cf->naa);
174  l_dnaaDestroy(&cf->dnaa);
175  pixaDestroy(&cf->pixadb);
176  LEPT_FREE(cf);
177  *pcf = NULL;
178 }
179 
180 
181 /* ----------------------------------------------------------------------- *
182  * Determine color content using proximity. What do we get when *
183  * growing regions with nearly the same color? *
184  * ----------------------------------------------------------------------- */
221 l_ok
223  l_int32 rref,
224  l_int32 gref,
225  l_int32 bref,
226  l_int32 minmax,
227  l_int32 maxdiff,
228  l_int32 minarea,
229  l_int32 smooth,
230  l_int32 debug)
231 {
232 l_int32 i, n;
233 PIX *pix1, *pix2, *pix3;
234 PIXA *pixas, *pixam;
235 
236  if (!cf)
237  return ERROR_INT("cf not defined", __func__, 1);
238  if (minmax <= 0) minmax = DefaultMinMax;
239  if (minmax > 200)
240  return ERROR_INT("minmax > 200; unreasonably large", __func__, 1);
241 
242  /* Do the optional linear color map; this checks the ref vals
243  * and uses them if valid. Use {0,0,0} to skip this operation. */
244  if ((pix1 = pixColorShiftWhitePoint(cf->pixs, rref, gref, bref)) == NULL)
245  return ERROR_INT("pix1 not returned", __func__, 1);
246  cf->pixst = pix1;
247 
248  /* Break the image up into small tiles */
249  pixas = pixaCreateFromBoxa(pix1, cf->boxas, 0, 0, NULL);
250  cf->pixas = pixas;
251 
252  /* Find regions of similar color in each tile */
253  n = pixaGetCount(pixas);
254  pixam = pixaCreate(n);
255  cf->pixam = pixam;
256  for (i = 0; i < n; i++) {
257  pix2 = pixaGetPix(pixas, i, L_COPY);
258  pix3 = pixColorFill(pix2, minmax, maxdiff, smooth, minarea, 0);
259  pixDestroy(&pix2);
260  pixaAddPix(pixam, pix3, L_INSERT);
261  }
262 
263  /* Evaluate color components. Find the average color in each
264  * component and determine if there is more than one color in
265  * each of the tiles. */
266  evalColorfillData(cf, debug);
267 
268  return 0;
269 }
270 
271 
292 PIX *
294  l_int32 minmax,
295  l_int32 maxdiff,
296  l_int32 smooth,
297  l_int32 minarea,
298  l_int32 debug)
299 {
300 l_int32 x, y, w, h;
301 l_uint32 val;
302 L_KERNEL *kel;
303 PIX *pixm, *pixm1, *pixv, *pixnc, *pixncd, *pixss, *pixf;
304 PTA *pta1;
305 L_QUEUE *lq;
306 
307  if (!pixs || pixGetDepth(pixs) != 32)
308  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
309 
310  /* Set the non-color pixels to 0; generate a mask representing them */
311  pixGetDimensions(pixs, &w, &h, NULL);
312  pixnc = pixCreate(w, h, 1); /* mask for no color */
313  for (y = 0; y < h; y++) {
314  for (x = 0; x < w; x++) {
315  pixGetPixel(pixs, x, y, &val);
316  if (!pixelColorIsValid(val, minmax)) {
317  pixSetPixel(pixnc, x, y, 1);
318  pixSetPixel(pixs, x, y, 0x0);
319  }
320  }
321  }
322 
323  /* Optionally, dilate the no-color mask */
324  pixncd = pixDilateBrick(NULL, pixnc, smooth, smooth);
325  pixDestroy(&pixnc);
326 
327  /* Do a low-pass filter on pixs. This will make bad pixels
328  * near the zeroed non-color pixels, but any components made
329  * from these pixels will be removed at the end by the
330  * (optionally dilated) no-color mask. */
331  if (smooth > 1) {
332  kel = makeFlatKernel(smooth, smooth, smooth / 2, smooth / 2);
333  pixss = pixConvolveRGBSep(pixs, kel, kel);
334  kernelDestroy(&kel);
335  } else {
336  pixss = pixCopy(NULL, pixs);
337  }
338 
339  /* Paint through everything under pixncd */
340  pixPaintThroughMask(pixss, pixncd, 0, 0, 0);
341 
342  /* Find the color components */
343  pixv = pixCreate(w, h, 1); /* visited pixels */
344  pixOr(pixv, pixv, pixncd); /* consider non-color as visited */
345  pixSetBorderRingVal(pixv, 1, 1);
346  pixm = pixCreate(w, h, 1); /* color components */
347  lq = lqueueCreate(0);
348  x = y = 1; /* first row and column have been marked as visited */
349  while (findNextUnvisited(pixv, &x, &y) == 1) {
350  /* Flood fill this component, starting from (x,y) */
351  if (debug) lept_stderr("Start: x = %d, y = %d\n", x, y);
352  pixColorFillFromSeed(pixss, pixv, &pta1, x, y, lq, maxdiff,
353  minarea, debug);
354  if (pta1) { /* erode and add the pixels to pixm */
355  pixm1 = pixGenerateFromPta(pta1, w, h);
356  pixErodeBrick(pixm1, pixm1, 3, 3);
357  pixOr(pixm, pixm, pixm1);
358  pixDestroy(&pixm1);
359  ptaDestroy(&pta1);
360  }
361  }
362  pixDestroy(&pixv);
363 
364  /* Remove everything under pixncd */
365  pixSubtract(pixm, pixm, pixncd);
366 
367  /* Remove remaining small stuff */
368  pixf = pixSelectByArea(pixm, minarea, 4, L_SELECT_IF_GTE, NULL);
369 
370  lqueueDestroy(&lq, 1);
371  pixDestroy(&pixncd);
372  pixDestroy(&pixss);
373  pixDestroy(&pixm);
374  return pixf;
375 }
376 
377 
378 /* ----------------------------------------------------------------------- *
379  * Generate data for testing *
380  * ----------------------------------------------------------------------- */
403 PIXA *
405  l_int32 h,
406  l_int32 nseeds,
407  l_int32 range)
408 {
409 l_int32 i, j, x, y, rval, gval, bval, start, end;
410 l_uint32 color;
411 l_float64 dval;
412 L_DNA *da;
413 PIX *pix1, *pix2, *pix3, *pix4;
414 PIXA *pixa;
415 PTA *pta;
416 PIXCMAP *cmap;
417 
418  /* Generate data for seeds */
419  pta = ptaCreate(nseeds); /* for seed locations */
420  da = l_dnaCreate(nseeds); /* for colors */
421  srand(4);
422  start = 128 - range / 2;
423  end = 128 + (range - 1) / 2;
424  for (i = 0; i < nseeds; i++) {
425  genRandomIntOnInterval(0, w - 1, 0, &x);
426  genRandomIntOnInterval(0, h - 1, 0, &y);
427  ptaAddPt(pta, x, y);
428  genRandomIntOnInterval(start, end, 0, &rval);
429  genRandomIntOnInterval(start, end, 0, &gval);
430  genRandomIntOnInterval(start, end, 0, &bval);
431  composeRGBPixel(rval, gval, bval, &color);
432  l_dnaAddNumber(da, color);
433  }
434 
435  /* Generate the 8 bpp seed image */
436  pix1 = pixCreate(w, h, 8);
437  for (i = 0; i < nseeds; i++) {
438  ptaGetIPt(pta, i, &x, &y);
439  pixSetPixel(pix1, x, y, i + 1); /* all seeds have non-zero values */
440  }
441 
442  /* Spread seed values to all pixels that are nearest to
443  * the seed pixel from which they take their value. */
444  pix2 = pixSeedspread(pix1, 4);
445 
446  /* Add a colormap for the random colors, using 0 for black */
447  cmap = pixcmapCreate(8);
448  pixcmapAddColor(cmap, 0, 0, 0);
449  for (i = 0; i < nseeds; i++) {
450  l_dnaGetDValue(da, i, &dval);
451  extractRGBValues(dval, &rval, &gval, &bval);
452  pixcmapAddColor(cmap, rval, gval, bval);
453  }
454  pixSetColormap(pix2, cmap);
455  pixDestroy(&pix1);
456  ptaDestroy(&pta);
457  l_dnaDestroy(&da);
458 
459  /* Add to output; no black boundaries */
460  pixa = pixaCreate(0);
461  pixaAddPix(pixa, pix2, L_COPY);
462 
463  /* Make pixels on the color boundaries black */
464  pix3 = pixCopy(NULL, pix2);
465  for (i = 0; i < h; i++) {
466  for (j = 0; j < w; j++) {
467  if (pixelIsOnColorBoundary(pix2, j, i))
468  pixSetPixel(pix3, j, i, 0); /* black */
469  }
470  }
471  pixaAddPix(pixa, pix3, L_INSERT);
472  pixDestroy(&pix2);
473 
474  /* Have all the non-black regions be the same color */
475  cmap = pixcmapCreate(8);
476  pixcmapAddColor(cmap, 0, 0, 0);
477  for (i = 0; i < nseeds; i++)
478  pixcmapAddColor(cmap, rval, gval, bval);
479  pix4 = pixCopy(NULL, pix3);
480  pixSetColormap(pix4, cmap);
481  pixaAddPix(pixa, pix4, L_INSERT);
482 
483  return pixa;
484 }
485 
486 
487 /* ----------------------------------------------------------------------- *
488  * Static helpers *
489  * ----------------------------------------------------------------------- */
490 static COLOREL *
491 colorelCreate(l_int32 x,
492  l_int32 y,
493  l_uint32 color)
494 {
495 COLOREL *el;
496 
497  el = (COLOREL *)LEPT_CALLOC(1, sizeof(COLOREL));
498  el->x = x;
499  el->y = y;
500  el->color = color;
501  return el;
502 }
503 
528 static void
530  PIX *pixv,
531  PTA **ppta,
532  l_int32 x,
533  l_int32 y,
534  L_QUEUE *lq,
535  l_int32 maxdiff,
536  l_int32 minarea,
537  l_int32 debug)
538 {
539 l_int32 w, h, np;
540 l_uint32 visited[8]; /* W, N, E, S, NW, NE, SW, SE */
541 l_uint32 color, val;
542 COLOREL *el;
543 PTA *pta;
544 
545  /* Prime the queue with this pixel */
546  pixGetPixel(pixs, x, y, &val);
547  el = colorelCreate(x, y, val);
548  lqueueAdd(lq, el);
549  pixSetPixel(pixv, x, y, 1); /* visited */
550  pta = ptaCreate(0);
551  *ppta = pta;
552  ptaAddPt(pta, x, y);
553 
554  /* Trace out the color component. Each pixel on the queue has
555  * a color. Pop from the queue and for each of its 8 neighbors,
556  * for those that have color:
557  * - If the pixel has a similar color, add to the pta array for
558  * the component, using the color of its parent.
559  * - Mark visited so that it will not be included in another
560  * component -- this effectively separates the growing component
561  * from all others. */
562  pixGetDimensions(pixs, &w, &h, NULL);
563  while (lqueueGetCount(lq) > 0) {
564  el = (COLOREL *)lqueueRemove(lq);
565  x = el->x;
566  y = el->y;
567  color = el->color;
568  LEPT_FREE(el);
569  pixGetVisitedNeighbors(pixv, x, y, visited);
570  if (!visited[0]) { /* check W */
571  pixGetPixel(pixs, x - 1, y, &val);
572  if (colorsAreSimilarForFill(color, val, maxdiff)) {
573  el = colorelCreate(x - 1, y, color);
574  lqueueAdd(lq, el);
575  ptaAddPt(pta, x - 1, y); /* added to component */
576  pixSetPixel(pixv, x - 1, y, 1); /* visited */
577  }
578  }
579  if (!visited[1]) { /* check N */
580  pixGetPixel(pixs, x, y - 1, &val);
581  if (colorsAreSimilarForFill(color, val, maxdiff)) {
582  el = colorelCreate(x, y - 1, color);
583  lqueueAdd(lq, el);
584  ptaAddPt(pta, x, y - 1);
585  pixSetPixel(pixv, x, y - 1, 1);
586  }
587  }
588  if (!visited[2]) { /* check E */
589  pixGetPixel(pixs, x + 1, y, &val);
590  if (colorsAreSimilarForFill(color, val, maxdiff)) {
591  el = colorelCreate(x + 1, y, color);
592  lqueueAdd(lq, el);
593  ptaAddPt(pta, x + 1, y);
594  pixSetPixel(pixv, x + 1, y, 1);
595  }
596  }
597  if (!visited[3]) { /* check S */
598  pixGetPixel(pixs, x, y + 1, &val);
599  if (colorsAreSimilarForFill(color, val, maxdiff)) {
600  el = colorelCreate(x, y + 1, color);
601  lqueueAdd(lq, el);
602  ptaAddPt(pta, x, y + 1);
603  pixSetPixel(pixv, x, y + 1, 1);
604  }
605  }
606  if (!visited[4]) { /* check NW */
607  pixGetPixel(pixs, x - 1, y - 1, &val);
608  if (colorsAreSimilarForFill(color, val, maxdiff)) {
609  el = colorelCreate(x - 1, y - 1, color);
610  lqueueAdd(lq, el);
611  ptaAddPt(pta, x - 1, y - 1);
612  pixSetPixel(pixv, x - 1, y - 1, 1);
613  }
614  }
615  if (!visited[5]) { /* check NE */
616  pixGetPixel(pixs, x + 1, y - 1, &val);
617  if (colorsAreSimilarForFill(color, val, maxdiff)) {
618  el = colorelCreate(x + 1, y - 1, color);
619  lqueueAdd(lq, el);
620  ptaAddPt(pta, x + 1, y - 1);
621  pixSetPixel(pixv, x + 1, y - 1, 1);
622  }
623  }
624  if (!visited[6]) { /* check SW */
625  pixGetPixel(pixs, x - 1, y + 1, &val);
626  if (colorsAreSimilarForFill(color, val, maxdiff)) {
627  el = colorelCreate(x - 1, y + 1, color);
628  lqueueAdd(lq, el);
629  ptaAddPt(pta, x - 1, y + 1);
630  pixSetPixel(pixv, x - 1, y + 1, 1);
631  }
632  }
633  if (!visited[7]) { /* check SE */
634  pixGetPixel(pixs, x + 1, y + 1, &val);
635  if (colorsAreSimilarForFill(color, val, maxdiff)) {
636  el = colorelCreate(x + 1, y + 1, color);
637  lqueueAdd(lq, el);
638  ptaAddPt(pta, x + 1, y + 1);
639  pixSetPixel(pixv, x + 1, y + 1, 1);
640  }
641  }
642  }
643 
644  /* If there are not enough pixels, do not return the pta.
645  * Otherwise, if a pta is returned, the caller will generate
646  * a component and put it in the mask. */
647  np = ptaGetCount(pta);
648  if (np < minarea) {
649  if (debug) lept_stderr(" Too small. End: x = %d, y = %d, np = %d\n",
650  x, y, np);
651  ptaDestroy(ppta);
652  } else {
653  if (debug) lept_stderr(" Keep. End: x = %d, y = %d, np = %d\n",
654  x, y, np);
655  }
656 }
657 
658 
678 static void
680  l_int32 x,
681  l_int32 y,
682  l_uint32 *visited)
683 {
684  pixGetPixel(pixs, x - 1, y, visited); /* W */
685  pixGetPixel(pixs, x, y - 1, visited + 1); /* N */
686  pixGetPixel(pixs, x + 1, y, visited + 2); /* E */
687  pixGetPixel(pixs, x, y + 1, visited + 3); /* S */
688  pixGetPixel(pixs, x - 1, y - 1, visited + 4); /* NW */
689  pixGetPixel(pixs, x + 1, y - 1, visited + 5); /* NE */
690  pixGetPixel(pixs, x - 1, y + 1, visited + 6); /* SW */
691  pixGetPixel(pixs, x + 1, y + 1, visited + 7); /* SE */
692 }
693 
694 
709 static l_int32
711  l_int32 *px,
712  l_int32 *py)
713 {
714 l_int32 ret;
715 PIX *pix1;
716 
717  pix1 = pixCopy(NULL, pixv);
718  pixInvert(pix1, pix1); /* After inversion, ON pixels are unvisited */
719  ret = nextOnPixelInRaster(pix1, 1, *py, px, py);
720  pixDestroy(&pix1);
721  return ret;
722 }
723 
724 
749 static l_int32
751  l_uint32 val2,
752  l_int32 maxdiff)
753 {
754 l_int32 rdiff, gdiff, bdiff, maxindex, del1, del2, del3, maxdel;
755 l_int32 v1[3], v2[3];
756 
757  extractRGBValues(val1, v1, v1 + 1, v1 + 2);
758  extractRGBValues(val2, v2, v2 + 1, v2 + 2);
759  rdiff = v1[0] - v2[0];
760  gdiff = v1[1] - v2[1];
761  bdiff = v1[2] - v2[2];
762  maxindex = 0;
763  if (L_ABS(gdiff) > L_ABS(rdiff))
764  maxindex = 1;
765  if (L_ABS(bdiff) > L_ABS(rdiff) && L_ABS(bdiff) > L_ABS(gdiff))
766  maxindex = 2;
767  del1 = v1[maxindex] - v2[maxindex];
768  del2 = v1[(maxindex + 1) % 3] - v2[(maxindex + 1) % 3];
769  del3 = v1[(maxindex + 2) % 3] - v2[(maxindex + 2) % 3];
770  maxdel = L_MAX(L_ABS(del1 - del2), L_ABS(del1 - del3));
771  return (maxdel <= maxdiff) ? 1 : 0;
772 }
773 
774 
782 static l_int32
783 pixelColorIsValid(l_uint32 val,
784  l_int32 minmax)
785 {
786 l_int32 rval, gval, bval;
787 
788  extractRGBValues(val, &rval, &gval, &bval);
789  if (rval < minmax && gval < minmax && bval < minmax)
790  return 0; /* maximum component is less than threshold */
791  else
792  return 1;
793 }
794 
795 
804 static l_int32
806  l_int32 x,
807  l_int32 y)
808 {
809 l_int32 w, h;
810 l_uint32 val, neigh;
811 
812  pixGetDimensions(pixs, &w, &h, NULL);
813  pixGetPixel(pixs, x, y, &val);
814  if (x > 0) {
815  pixGetPixel(pixs, x - 1, y, &neigh); /* W */
816  if (neigh != val) return TRUE;
817  }
818  if (x < w - 1) {
819  pixGetPixel(pixs, x + 1, y, &neigh); /* E */
820  if (neigh != val) return TRUE;
821  }
822  if (y > 0) {
823  pixGetPixel(pixs, x, y - 1, &neigh); /* N */
824  if (neigh != val) return TRUE;
825  }
826  if (y < h - 1) {
827  pixGetPixel(pixs, x, y + 1, &neigh); /* S */
828  if (neigh != val) return TRUE;
829  }
830  return FALSE;
831 }
832 
833 
841 static l_int32
843  l_int32 debug)
844 {
845 l_int32 i, j, n, nc, w, h, x, y, count;
846 l_float32 rval, gval, bval;
847 l_uint32 pixel;
848 l_int32 *tab;
849 BOX *box1;
850 BOXA *boxa1;
851 L_DNA *da;
852 NUMA *na;
853 PIX *pixm, *pix1, *pix2, *pixdb;
854 PIXA *pixa1;
855 
856  if (!cf)
857  return ERROR_INT("cf not defind", __func__, 1);
858 
859  tab = makePixelSumTab8();
860  n = cf->nx * cf->ny;
861  for (i = 0; i < n; i++) {
862  pix1 = pixaGetPix(cf->pixas, i, L_CLONE);
863  pixm = pixaGetPix(cf->pixam, i, L_CLONE);
864  pixGetDimensions(pix1, &w, &h, NULL);
865  boxa1 = pixConnComp(pixm, &pixa1, 4);
866  boxaDestroy(&boxa1);
867  nc = pixaGetCount(pixa1);
868  na = numaCreate(0);
869  da = l_dnaCreate(0);
870  pixdb = (debug) ? pixCreate(w, h, 32) : NULL;
871  for (j = 0; j < nc; j++) {
872  pix2 = pixaGetPix(pixa1, j, L_COPY);
873  box1 = pixaGetBox(pixa1, j, L_COPY);
874  boxGetGeometry(box1, &x, &y, NULL, NULL);
875  pixGetRankValueMaskedRGB(pix1, pix2, x, y, 1, 0.5,
876  &rval, &gval, &bval);
877  composeRGBPixel(rval, gval, bval, &pixel);
878 
879  l_dnaAddNumber(da, pixel);
880  pixCountPixels(pix2, &count, tab);
881  numaAddNumber(na, count);
882  if (debug)
883  pixPaintThroughMask(pixdb, pix2, x, y, pixel);
884  boxDestroy(&box1);
885  pixDestroy(&pix2);
886  }
887  pixaAddPix(cf->pixadb, pixdb, L_INSERT);
888  numaaAddNuma(cf->naa, na, L_INSERT);
889  l_dnaaAddDna(cf->dnaa, da, L_INSERT);
890  pixDestroy(&pix1);
891  pixDestroy(&pixm);
892  pixaDestroy(&pixa1);
893  }
894 
895  if (debug) { /* first tile */
896  na = numaaGetNuma(cf->naa, 0, L_CLONE);
897  lept_stderr("Size of components in tile 0:");
898  numaWriteStderr(na);
899  numaDestroy(&na);
900  }
901  LEPT_FREE(tab);
902  return 0;
903 }
l_ok boxGetGeometry(const BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:301
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:273
l_ok boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:553
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:519
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:171
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:442
PIX * pixColorShiftWhitePoint(PIX *pixs, l_int32 rref, l_int32 gref, l_int32 bref)
pixColorShiftWhitePoint()
Definition: colorcontent.c:577
PIX * pixColorFill(PIX *pixs, l_int32 minmax, l_int32 maxdiff, l_int32 smooth, l_int32 minarea, l_int32 debug)
pixColorFill()
Definition: colorfill.c:293
PIXA * makeColorfillTestData(l_int32 w, l_int32 h, l_int32 nseeds, l_int32 range)
makeColorfillTestData()
Definition: colorfill.c:404
static l_int32 pixelColorIsValid(l_uint32 val, l_int32 minmax)
pixelColorIsValid()
Definition: colorfill.c:783
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:222
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:529
void l_colorfillDestroy(L_COLORFILL **pcf)
l_colorfillDestroy()
Definition: colorfill.c:156
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:750
static l_int32 pixelIsOnColorBoundary(PIX *pixs, l_int32 x, l_int32 y)
pixelIsOnColorBoundary()
Definition: colorfill.c:805
static l_int32 evalColorfillData(L_COLORFILL *cf, l_int32 debug)
evalColorfillData()
Definition: colorfill.c:842
static void pixGetVisitedNeighbors(PIX *pixs, l_int32 x, l_int32 y, l_uint32 *visited)
pixGetVisitedNeighbors()
Definition: colorfill.c:679
static l_int32 findNextUnvisited(PIX *pixv, l_int32 *px, l_int32 *py)
findNextUnvisited()
Definition: colorfill.c:710
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
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:152
l_int32 nextOnPixelInRaster(PIX *pixs, l_int32 xstart, l_int32 ystart, l_int32 *px, l_int32 *py)
nextOnPixelInRaster()
Definition: conncomp.c:450
PIX * pixConvolveRGBSep(PIX *pixs, L_KERNEL *kelx, L_KERNEL *kely)
pixConvolveRGBSep()
Definition: convolve.c:2100
L_DNA * l_dnaCreate(l_int32 n)
l_dnaCreate()
Definition: dnabasic.c:179
l_ok l_dnaAddNumber(L_DNA *da, l_float64 val)
l_dnaAddNumber()
Definition: dnabasic.c:430
L_DNAA * l_dnaaCreate(l_int32 n)
l_dnaaCreate()
Definition: dnabasic.c:1184
l_ok l_dnaGetDValue(L_DNA *da, l_int32 index, l_float64 *pval)
l_dnaGetDValue()
Definition: dnabasic.c:660
l_ok l_dnaaAddDna(L_DNAA *daa, L_DNA *da, l_int32 copyflag)
l_dnaaAddDna()
Definition: dnabasic.c:1314
void l_dnaDestroy(L_DNA **pda)
l_dnaDestroy()
Definition: dnabasic.c:323
void l_dnaaDestroy(L_DNAA **pdaa)
l_dnaaDestroy()
Definition: dnabasic.c:1281
L_KERNEL * makeFlatKernel(l_int32 height, l_int32 width, l_int32 cy, l_int32 cx)
makeFlatKernel()
Definition: kernel.c:1065
void kernelDestroy(L_KERNEL **pkel)
kernelDestroy()
Definition: kernel.c:148
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
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:460
l_ok numaWriteStderr(NUMA *na)
numaWriteStderr()
Definition: numabasic.c:1212
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1617
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
NUMAA * numaaCreate(l_int32 n)
numaaCreate()
Definition: numabasic.c:1302
l_ok numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1435
void numaaDestroy(NUMAA **pnaa)
numaaDestroy()
Definition: numabasic.c:1401
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 * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
l_ok pixSetBorderRingVal(PIX *pixs, l_int32 dist, l_uint32 val)
pixSetBorderRingVal()
Definition: pix2.c:1623
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:192
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
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1481
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:618
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
l_int32 * makePixelSumTab8(void)
makePixelSumTab8()
Definition: pix3.c:2354
PIX * pixSubtract(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixSubtract()
Definition: pix3.c:1717
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:1048
@ L_SELECT_IF_GTE
Definition: pix.h:578
@ L_COPY
Definition: pix.h:505
@ L_CLONE
Definition: pix.h:506
@ L_INSERT
Definition: pix.h:504
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:404
BOX * pixaGetBox(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetBox()
Definition: pixabasic.c:764
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:629
PIXA * pixaCreateFromBoxa(PIX *pixs, BOXA *boxa, l_int32 start, l_int32 num, l_int32 *pcropwarn)
pixaCreateFromBoxa()
Definition: pixabasic.c:268
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:647
PIX * pixSelectByArea(PIX *pixs, l_float32 thresh, l_int32 connectivity, l_int32 type, l_int32 *pchanged)
pixSelectByArea()
Definition: pixafunc1.c:831
l_ok ptaGetIPt(PTA *pta, l_int32 index, l_int32 *px, l_int32 *py)
ptaGetIPt()
Definition: ptabasic.c:527
l_ok ptaAddPt(PTA *pta, l_float32 x, l_float32 y)
ptaAddPt()
Definition: ptabasic.c:328
l_int32 ptaGetCount(PTA *pta)
ptaGetCount()
Definition: ptabasic.c:480
PTA * ptaCreate(l_int32 n)
ptaCreate()
Definition: ptabasic.c:120
void ptaDestroy(PTA **ppta)
ptaDestroy()
Definition: ptabasic.c:191
PIX * pixGenerateFromPta(PTA *pta, l_int32 w, l_int32 h)
pixGenerateFromPta()
Definition: ptafunc1.c:1962
l_int32 lqueueGetCount(L_QUEUE *lq)
lqueueGetCount()
Definition: queue.c:276
void lqueueDestroy(L_QUEUE **plq, l_int32 freeflag)
lqueueDestroy()
Definition: queue.c:132
void * lqueueRemove(L_QUEUE *lq)
lqueueRemove()
Definition: queue.c:249
l_ok lqueueAdd(L_QUEUE *lq, void *item)
lqueueAdd()
Definition: queue.c:184
L_QUEUE * lqueueCreate(l_int32 nalloc)
lqueueCreate()
Definition: queue.c:93
PIX * pixSeedspread(PIX *pixs, l_int32 connectivity)
pixSeedspread()
Definition: seedfill.c:2752
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: morph.h:89
Definition: queue.h:65
l_ok genRandomIntOnInterval(l_int32 start, l_int32 end, l_int32 seed, l_int32 *pval)
genRandomIntOnInterval()
Definition: utils1.c:651
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306