Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
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
64struct ColorEl {
65 l_int32 x;
66 l_int32 y;
67 l_uint32 color;
68};
69typedef struct ColorEl COLOREL;
70
71 /* Ignore pixels with smaller max component */
72static l_int32 DefaultMinMax = 70;
73
74 /* Static helpers */
75static COLOREL *colorelCreate(l_int32 x, l_int32 y, l_uint32 color);
76static 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);
80static void pixGetVisitedNeighbors(PIX *pixs, l_int32 x, l_int32 y,
81 l_uint32 *visited);
82static l_int32 findNextUnvisited(PIX *pixv, l_int32 *px, l_int32 *py);
83static l_int32 colorsAreSimilarForFill(l_uint32 val1, l_uint32 val2,
84 l_int32 maxdiff);
85static l_int32 pixelColorIsValid(l_uint32 val, l_int32 minmax);
86static l_int32 pixelIsOnColorBoundary(PIX *pixs, l_int32 x, l_int32 y);
87static l_int32 evalColorfillData(L_COLORFILL *cf, l_int32 debug);
88
89
90/*---------------------------------------------------------------------*
91 * Colorfill creation and destruction *
92 *---------------------------------------------------------------------*/
108 l_int32 nx,
109 l_int32 ny)
110{
111l_int32 i, j, w, h, tw, th, ntiles;
112BOX *box;
113BOXA *boxas;
114L_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
155void
157{
158L_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 * ----------------------------------------------------------------------- */
221l_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{
232l_int32 i, n;
233PIX *pix1, *pix2, *pix3;
234PIXA *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
292PIX *
294 l_int32 minmax,
295 l_int32 maxdiff,
296 l_int32 smooth,
297 l_int32 minarea,
298 l_int32 debug)
299{
300l_int32 x, y, w, h;
301l_uint32 val;
302L_KERNEL *kel;
303PIX *pixm, *pixm1, *pixv, *pixnc, *pixncd, *pixss, *pixf;
304PTA *pta1;
305L_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 * ----------------------------------------------------------------------- */
403PIXA *
405 l_int32 h,
406 l_int32 nseeds,
407 l_int32 range)
408{
409l_int32 i, j, x, y, rval, gval, bval, start, end;
410l_uint32 color;
411l_float64 dval;
412L_DNA *da;
413PIX *pix1, *pix2, *pix3, *pix4;
414PIXA *pixa;
415PTA *pta;
416PIXCMAP *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 * ----------------------------------------------------------------------- */
490static COLOREL *
491colorelCreate(l_int32 x,
492 l_int32 y,
493 l_uint32 color)
494{
495COLOREL *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
528static 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{
539l_int32 w, h, np;
540l_uint32 visited[8]; /* W, N, E, S, NW, NE, SW, SE */
541l_uint32 color, val;
542COLOREL *el;
543PTA *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
678static 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
709static l_int32
711 l_int32 *px,
712 l_int32 *py)
713{
714l_int32 ret;
715PIX *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
749static l_int32
751 l_uint32 val2,
752 l_int32 maxdiff)
753{
754l_int32 rdiff, gdiff, bdiff, maxindex, del1, del2, del3, maxdel;
755l_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
782static l_int32
783pixelColorIsValid(l_uint32 val,
784 l_int32 minmax)
785{
786l_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
804static l_int32
806 l_int32 x,
807 l_int32 y)
808{
809l_int32 w, h;
810l_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
841static l_int32
843 l_int32 debug)
844{
845l_int32 i, j, n, nc, w, h, x, y, count;
846l_float32 rval, gval, bval;
847l_uint32 pixel;
848l_int32 *tab;
849BOX *box1;
850BOXA *boxa1;
851L_DNA *da;
852NUMA *na;
853PIX *pixm, *pix1, *pix2, *pixdb;
854PIXA *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}
PIX * pixColorFill(PIX *pixs, l_int32 minmax, l_int32 maxdiff, l_int32 smooth, l_int32 minarea, l_int32 debug)
pixColorFill()
Definition colorfill.c:293
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
L_COLORFILL * l_colorfillCreate(PIX *pixs, l_int32 nx, l_int32 ny)
l_colorfillCreate()
Definition colorfill.c:107
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
PIXA * makeColorfillTestData(l_int32 w, l_int32 h, l_int32 nseeds, l_int32 range)
makeColorfillTestData()
Definition colorfill.c:404
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
@ 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
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