Leptonica  1.73
Image processing and image analysis suite
conncomp.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 
91 #include "allheaders.h"
92 
99 struct FillSeg
100 {
101  l_int32 xleft;
102  l_int32 xright;
103  l_int32 y;
104  l_int32 dy;
105 };
106 typedef struct FillSeg FILLSEG;
107 
108 
109  /* Static accessors for FillSegs on a stack */
110 static void pushFillsegBB(L_STACK *stack, l_int32 xleft, l_int32 xright,
111  l_int32 y, l_int32 dy, l_int32 ymax,
112  l_int32 *pminx, l_int32 *pmaxx,
113  l_int32 *pminy, l_int32 *pmaxy);
114 static void pushFillseg(L_STACK *stack, l_int32 xleft, l_int32 xright,
115  l_int32 y, l_int32 dy, l_int32 ymax);
116 static void popFillseg(L_STACK *stack, l_int32 *pxleft, l_int32 *pxright,
117  l_int32 *py, l_int32 *pdy);
118 
119 
120 #ifndef NO_CONSOLE_IO
121 #define DEBUG 0
122 #endif /* ~NO_CONSOLE_IO */
123 
124 
125 /*-----------------------------------------------------------------------*
126  * Bounding boxes of 4 Connected Components *
127  *-----------------------------------------------------------------------*/
143 BOXA *
145  PIXA **ppixa,
146  l_int32 connectivity)
147 {
148 
149  PROCNAME("pixConnComp");
150 
151  if (ppixa) *ppixa = NULL;
152  if (!pixs)
153  return (BOXA *)ERROR_PTR("pixs not defined", procName, NULL);
154  if (pixGetDepth(pixs) != 1)
155  return (BOXA *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
156  if (connectivity != 4 && connectivity != 8)
157  return (BOXA *)ERROR_PTR("connectivity not 4 or 8", procName, NULL);
158 
159  if (!ppixa)
160  return pixConnCompBB(pixs, connectivity);
161  else
162  return pixConnCompPixa(pixs, ppixa, connectivity);
163 }
164 
165 
189 BOXA *
191  PIXA **ppixa,
192  l_int32 connectivity)
193 {
194 l_int32 h, iszero;
195 l_int32 x, y, xstart, ystart;
196 PIX *pix1, *pix2, *pix3, *pix4;
197 PIXA *pixa;
198 BOX *box;
199 BOXA *boxa;
200 L_STACK *stack, *auxstack;
201 
202  PROCNAME("pixConnCompPixa");
203 
204  if (!ppixa)
205  return (BOXA *)ERROR_PTR("&pixa not defined", procName, NULL);
206  *ppixa = NULL;
207  if (!pixs || pixGetDepth(pixs) != 1)
208  return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
209  if (connectivity != 4 && connectivity != 8)
210  return (BOXA *)ERROR_PTR("connectivity not 4 or 8", procName, NULL);
211 
212  pix1 = pix2 = pix3 = pix4 = NULL;
213  stack = NULL;
214  pixa = pixaCreate(0);
215  boxa = NULL;
216  *ppixa = pixa;
217  pixZero(pixs, &iszero);
218  if (iszero)
219  return boxaCreate(1); /* return empty boxa and empty pixa */
220 
221  pix1 = pixCopy(NULL, pixs);
222  pix2 = pixCopy(NULL, pixs);
223  if (!pix1 || !pix2) {
224  L_ERROR("pix1 or pix2 not made\n", procName);
225  pixaDestroy(ppixa);
226  goto cleanup;
227  }
228 
229  h = pixGetHeight(pixs);
230  if ((stack = lstackCreate(h)) == NULL) {
231  L_ERROR("stack not made\n", procName);
232  pixaDestroy(ppixa);
233  goto cleanup;
234  }
235  auxstack = lstackCreate(0);
236  stack->auxstack = auxstack;
237  boxa = boxaCreate(0);
238 
239  xstart = 0;
240  ystart = 0;
241  while (1) {
242  if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y))
243  break;
244 
245  if ((box = pixSeedfillBB(pix1, stack, x, y, connectivity)) == NULL) {
246  boxaDestroy(&boxa);
247  pixaDestroy(ppixa);
248  L_ERROR("box not made\n", procName);
249  goto cleanup;
250  }
251  boxaAddBox(boxa, box, L_INSERT);
252 
253  /* Save the c.c. and remove from pix2 as well */
254  pix3 = pixClipRectangle(pix1, box, NULL);
255  pix4 = pixClipRectangle(pix2, box, NULL);
256  pixXor(pix3, pix3, pix4);
257  pixRasterop(pix2, box->x, box->y, box->w, box->h, PIX_SRC ^ PIX_DST,
258  pix3, 0, 0);
259  pixaAddPix(pixa, pix3, L_INSERT);
260  pixDestroy(&pix4);
261 
262  xstart = x;
263  ystart = y;
264  }
265 
266 #if DEBUG
267  pixCountPixels(pix1, &iszero, NULL);
268  fprintf(stderr, "Number of remaining pixels = %d\n", iszero);
269  pixWrite("junkremain", pix1, IFF_PNG);
270 #endif /* DEBUG */
271 
272  /* Remove old boxa of pixa and replace with a copy */
273  boxaDestroy(&pixa->boxa);
274  pixa->boxa = boxaCopy(boxa, L_COPY);
275  *ppixa = pixa;
276 
277  /* Cleanup, freeing the fillsegs on each stack */
278 cleanup:
279  lstackDestroy(&stack, TRUE);
280  pixDestroy(&pix1);
281  pixDestroy(&pix2);
282  return boxa;
283 }
284 
285 
302 BOXA *
304  l_int32 connectivity)
305 {
306 l_int32 h, iszero;
307 l_int32 x, y, xstart, ystart;
308 PIX *pix1;
309 BOX *box;
310 BOXA *boxa;
311 L_STACK *stack, *auxstack;
312 
313  PROCNAME("pixConnCompBB");
314 
315  if (!pixs || pixGetDepth(pixs) != 1)
316  return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
317  if (connectivity != 4 && connectivity != 8)
318  return (BOXA *)ERROR_PTR("connectivity not 4 or 8", procName, NULL);
319 
320  boxa = NULL;
321  pix1 = NULL;
322  stack = NULL;
323  pixZero(pixs, &iszero);
324  if (iszero)
325  return boxaCreate(1); /* return empty boxa */
326 
327  if ((pix1 = pixCopy(NULL, pixs)) == NULL)
328  return (BOXA *)ERROR_PTR("pix1 not made", procName, NULL);
329 
330  h = pixGetHeight(pixs);
331  if ((stack = lstackCreate(h)) == NULL) {
332  L_ERROR("stack not made\n", procName);
333  goto cleanup;
334  }
335  auxstack = lstackCreate(0);
336  stack->auxstack = auxstack;
337  boxa = boxaCreate(0);
338 
339  xstart = 0;
340  ystart = 0;
341  while (1) {
342  if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y))
343  break;
344 
345  if ((box = pixSeedfillBB(pix1, stack, x, y, connectivity)) == NULL) {
346  L_ERROR("box not made\n", procName);
347  boxaDestroy(&boxa);
348  goto cleanup;
349  }
350  boxaAddBox(boxa, box, L_INSERT);
351 
352  xstart = x;
353  ystart = y;
354  }
355 
356 #if DEBUG
357  pixCountPixels(pix1, &iszero, NULL);
358  fprintf(stderr, "Number of remaining pixels = %d\n", iszero);
359  pixWrite("junkremain", pix1, IFF_PNG);
360 #endif /* DEBUG */
361 
362  /* Cleanup, freeing the fillsegs on each stack */
363 cleanup:
364  lstackDestroy(&stack, TRUE);
365  pixDestroy(&pix1);
366  return boxa;
367 }
368 
369 
384 l_int32
386  l_int32 connectivity,
387  l_int32 *pcount)
388 {
389 l_int32 h, iszero;
390 l_int32 x, y, xstart, ystart;
391 PIX *pix1;
392 L_STACK *stack, *auxstack;
393 
394  PROCNAME("pixCountConnComp");
395 
396  if (!pcount)
397  return ERROR_INT("&count not defined", procName, 1);
398  *pcount = 0; /* initialize the count to 0 */
399  if (!pixs || pixGetDepth(pixs) != 1)
400  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
401  if (connectivity != 4 && connectivity != 8)
402  return ERROR_INT("connectivity not 4 or 8", procName, 1);
403 
404  stack = NULL;
405  pixZero(pixs, &iszero);
406  if (iszero)
407  return 0;
408 
409  if ((pix1 = pixCopy(NULL, pixs)) == NULL)
410  return ERROR_INT("pix1 not made", procName, 1);
411  h = pixGetHeight(pixs);
412  if ((stack = lstackCreate(h)) == NULL) {
413  pixDestroy(&pix1);
414  return ERROR_INT("stack not made\n", procName, 1);
415  }
416  auxstack = lstackCreate(0);
417  stack->auxstack = auxstack;
418 
419  xstart = 0;
420  ystart = 0;
421  while (1) {
422  if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y))
423  break;
424 
425  pixSeedfill(pix1, stack, x, y, connectivity);
426  (*pcount)++;
427  xstart = x;
428  ystart = y;
429  }
430 
431  /* Cleanup, freeing the fillsegs on each stack */
432  lstackDestroy(&stack, TRUE);
433  pixDestroy(&pix1);
434  return 0;
435 }
436 
437 
446 l_int32
448  l_int32 xstart,
449  l_int32 ystart,
450  l_int32 *px,
451  l_int32 *py)
452 {
453 l_int32 w, h, d, wpl;
454 l_uint32 *data;
455 
456  PROCNAME("nextOnPixelInRaster");
457 
458  if (!pixs)
459  return ERROR_INT("pixs not defined", procName, 0);
460  pixGetDimensions(pixs, &w, &h, &d);
461  if (d != 1)
462  return ERROR_INT("pixs not 1 bpp", procName, 0);
463 
464  wpl = pixGetWpl(pixs);
465  data = pixGetData(pixs);
466  return nextOnPixelInRasterLow(data, w, h, wpl, xstart, ystart, px, py);
467 }
468 
469 
480 l_int32
481 nextOnPixelInRasterLow(l_uint32 *data,
482  l_int32 w,
483  l_int32 h,
484  l_int32 wpl,
485  l_int32 xstart,
486  l_int32 ystart,
487  l_int32 *px,
488  l_int32 *py)
489 {
490 l_int32 i, x, y, xend, startword;
491 l_uint32 *line, *pword;
492 
493  /* Look at the first word */
494  line = data + ystart * wpl;
495  pword = line + (xstart / 32);
496  if (*pword) {
497  xend = xstart - (xstart % 32) + 31;
498  for (x = xstart; x <= xend && x < w; x++) {
499  if (GET_DATA_BIT(line, x)) {
500  *px = x;
501  *py = ystart;
502  return 1;
503  }
504  }
505  }
506 
507  /* Continue with the rest of the line */
508  startword = (xstart / 32) + 1;
509  x = 32 * startword;
510  for (pword = line + startword; x < w; pword++, x += 32) {
511  if (*pword) {
512  for (i = 0; i < 32 && x < w; i++, x++) {
513  if (GET_DATA_BIT(line, x)) {
514  *px = x;
515  *py = ystart;
516  return 1;
517  }
518  }
519  }
520  }
521 
522  /* Continue with following lines */
523  for (y = ystart + 1; y < h; y++) {
524  line = data + y * wpl;
525  for (pword = line, x = 0; x < w; pword++, x += 32) {
526  if (*pword) {
527  for (i = 0; i < 32 && x < w; i++, x++) {
528  if (GET_DATA_BIT(line, x)) {
529  *px = x;
530  *py = y;
531  return 1;
532  }
533  }
534  }
535  }
536  }
537 
538  return 0;
539 }
540 
541 
557 BOX *
559  L_STACK *stack,
560  l_int32 x,
561  l_int32 y,
562  l_int32 connectivity)
563 {
564 BOX *box;
565 
566  PROCNAME("pixSeedfillBB");
567 
568  if (!pixs || pixGetDepth(pixs) != 1)
569  return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
570  if (!stack)
571  return (BOX *)ERROR_PTR("stack not defined", procName, NULL);
572  if (connectivity != 4 && connectivity != 8)
573  return (BOX *)ERROR_PTR("connectivity not 4 or 8", procName, NULL);
574 
575  if (connectivity == 4) {
576  if ((box = pixSeedfill4BB(pixs, stack, x, y)) == NULL)
577  return (BOX *)ERROR_PTR("box not made", procName, NULL);
578  } else if (connectivity == 8) {
579  if ((box = pixSeedfill8BB(pixs, stack, x, y)) == NULL)
580  return (BOX *)ERROR_PTR("box not made", procName, NULL);
581  } else {
582  return (BOX *)ERROR_PTR("connectivity not 4 or 8", procName, NULL);
583  }
584 
585  return box;
586 }
587 
588 
620 BOX *
622  L_STACK *stack,
623  l_int32 x,
624  l_int32 y)
625 {
626 l_int32 w, h, xstart, wpl, x1, x2, dy;
627 l_int32 xmax, ymax;
628 l_int32 minx, maxx, miny, maxy; /* for bounding box of this c.c. */
629 l_uint32 *data, *line;
630 BOX *box;
631 
632  PROCNAME("pixSeedfill4BB");
633 
634  if (!pixs || pixGetDepth(pixs) != 1)
635  return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
636  if (!stack)
637  return (BOX *)ERROR_PTR("stack not defined", procName, NULL);
638  if (!stack->auxstack)
639  stack->auxstack = lstackCreate(0);
640 
641  pixGetDimensions(pixs, &w, &h, NULL);
642  xmax = w - 1;
643  ymax = h - 1;
644  data = pixGetData(pixs);
645  wpl = pixGetWpl(pixs);
646  line = data + y * wpl;
647 
648  /* Check pix value of seed; must be within the image and ON */
649  if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
650  return NULL;
651 
652  /* Init stack to seed:
653  * Must first init b.b. values to prevent valgrind from complaining;
654  * then init b.b. boundaries correctly to seed. */
655  minx = miny = 100000;
656  maxx = maxy = 0;
657  pushFillsegBB(stack, x, x, y, 1, ymax, &minx, &maxx, &miny, &maxy);
658  pushFillsegBB(stack, x, x, y + 1, -1, ymax, &minx, &maxx, &miny, &maxy);
659  minx = maxx = x;
660  miny = maxy = y;
661 
662  while (lstackGetCount(stack) > 0) {
663  /* Pop segment off stack and fill a neighboring scan line */
664  popFillseg(stack, &x1, &x2, &y, &dy);
665  line = data + y * wpl;
666 
667  /* A segment of scanline y - dy for x1 <= x <= x2 was
668  * previously filled. We now explore adjacent pixels
669  * in scan line y. There are three regions: to the
670  * left of x1 - 1, between x1 and x2, and to the right of x2.
671  * These regions are handled differently. Leaks are
672  * possible expansions beyond the previous segment and
673  * going back in the -dy direction. These can happen
674  * for x < x1 - 1 and for x > x2 + 1. Any "leak" segments
675  * are plugged with a push in the -dy (opposite) direction.
676  * And any segments found anywhere are always extended
677  * in the +dy direction. */
678  for (x = x1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
679  CLEAR_DATA_BIT(line,x);
680  if (x >= x1) /* pix at x1 was off and was not cleared */
681  goto skip;
682  xstart = x + 1;
683  if (xstart < x1 - 1) /* leak on left? */
684  pushFillsegBB(stack, xstart, x1 - 1, y, -dy,
685  ymax, &minx, &maxx, &miny, &maxy);
686 
687  x = x1 + 1;
688  do {
689  for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
690  CLEAR_DATA_BIT(line, x);
691  pushFillsegBB(stack, xstart, x - 1, y, dy,
692  ymax, &minx, &maxx, &miny, &maxy);
693  if (x > x2 + 1) /* leak on right? */
694  pushFillsegBB(stack, x2 + 1, x - 1, y, -dy,
695  ymax, &minx, &maxx, &miny, &maxy);
696  skip: for (x++; x <= x2 &&
697  x <= xmax &&
698  (GET_DATA_BIT(line, x) == 0); x++)
699  ;
700  xstart = x;
701  } while (x <= x2 && x <= xmax);
702  }
703 
704  if ((box = boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1))
705  == NULL)
706  return (BOX *)ERROR_PTR("box not made", procName, NULL);
707  return box;
708 }
709 
710 
735 BOX *
737  L_STACK *stack,
738  l_int32 x,
739  l_int32 y)
740 {
741 l_int32 w, h, xstart, wpl, x1, x2, dy;
742 l_int32 xmax, ymax;
743 l_int32 minx, maxx, miny, maxy; /* for bounding box of this c.c. */
744 l_uint32 *data, *line;
745 BOX *box;
746 
747  PROCNAME("pixSeedfill8BB");
748 
749  if (!pixs || pixGetDepth(pixs) != 1)
750  return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
751  if (!stack)
752  return (BOX *)ERROR_PTR("stack not defined", procName, NULL);
753  if (!stack->auxstack)
754  stack->auxstack = lstackCreate(0);
755 
756  pixGetDimensions(pixs, &w, &h, NULL);
757  xmax = w - 1;
758  ymax = h - 1;
759  data = pixGetData(pixs);
760  wpl = pixGetWpl(pixs);
761  line = data + y * wpl;
762 
763  /* Check pix value of seed; must be ON */
764  if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
765  return NULL;
766 
767  /* Init stack to seed:
768  * Must first init b.b. values to prevent valgrind from complaining;
769  * then init b.b. boundaries correctly to seed. */
770  minx = miny = 100000;
771  maxx = maxy = 0;
772  pushFillsegBB(stack, x, x, y, 1, ymax, &minx, &maxx, &miny, &maxy);
773  pushFillsegBB(stack, x, x, y + 1, -1, ymax, &minx, &maxx, &miny, &maxy);
774  minx = maxx = x;
775  miny = maxy = y;
776 
777  while (lstackGetCount(stack) > 0) {
778  /* Pop segment off stack and fill a neighboring scan line */
779  popFillseg(stack, &x1, &x2, &y, &dy);
780  line = data + y * wpl;
781 
782  /* A segment of scanline y - dy for x1 <= x <= x2 was
783  * previously filled. We now explore adjacent pixels
784  * in scan line y. There are three regions: to the
785  * left of x1, between x1 and x2, and to the right of x2.
786  * These regions are handled differently. Leaks are
787  * possible expansions beyond the previous segment and
788  * going back in the -dy direction. These can happen
789  * for x < x1 and for x > x2. Any "leak" segments
790  * are plugged with a push in the -dy (opposite) direction.
791  * And any segments found anywhere are always extended
792  * in the +dy direction. */
793  for (x = x1 - 1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
794  CLEAR_DATA_BIT(line,x);
795  if (x >= x1 - 1) /* pix at x1 - 1 was off and was not cleared */
796  goto skip;
797  xstart = x + 1;
798  if (xstart < x1) /* leak on left? */
799  pushFillsegBB(stack, xstart, x1 - 1, y, -dy,
800  ymax, &minx, &maxx, &miny, &maxy);
801 
802  x = x1;
803  do {
804  for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
805  CLEAR_DATA_BIT(line, x);
806  pushFillsegBB(stack, xstart, x - 1, y, dy,
807  ymax, &minx, &maxx, &miny, &maxy);
808  if (x > x2) /* leak on right? */
809  pushFillsegBB(stack, x2 + 1, x - 1, y, -dy,
810  ymax, &minx, &maxx, &miny, &maxy);
811  skip: for (x++; x <= x2 + 1 &&
812  x <= xmax &&
813  (GET_DATA_BIT(line, x) == 0); x++)
814  ;
815  xstart = x;
816  } while (x <= x2 + 1 && x <= xmax);
817  }
818 
819  if ((box = boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1))
820  == NULL)
821  return (BOX *)ERROR_PTR("box not made", procName, NULL);
822  return box;
823 }
824 
825 
841 l_int32
843  L_STACK *stack,
844  l_int32 x,
845  l_int32 y,
846  l_int32 connectivity)
847 {
848 l_int32 retval;
849 
850  PROCNAME("pixSeedfill");
851 
852  if (!pixs || pixGetDepth(pixs) != 1)
853  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
854  if (!stack)
855  return ERROR_INT("stack not defined", procName, 1);
856  if (connectivity != 4 && connectivity != 8)
857  return ERROR_INT("connectivity not 4 or 8", procName, 1);
858 
859  if (connectivity == 4)
860  retval = pixSeedfill4(pixs, stack, x, y);
861  else /* connectivity == 8 */
862  retval = pixSeedfill8(pixs, stack, x, y);
863 
864  return retval;
865 }
866 
867 
885 l_int32
887  L_STACK *stack,
888  l_int32 x,
889  l_int32 y)
890 {
891 l_int32 w, h, xstart, wpl, x1, x2, dy;
892 l_int32 xmax, ymax;
893 l_uint32 *data, *line;
894 
895  PROCNAME("pixSeedfill4");
896 
897  if (!pixs || pixGetDepth(pixs) != 1)
898  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
899  if (!stack)
900  return ERROR_INT("stack not defined", procName, 1);
901  if (!stack->auxstack)
902  stack->auxstack = lstackCreate(0);
903 
904  pixGetDimensions(pixs, &w, &h, NULL);
905  xmax = w - 1;
906  ymax = h - 1;
907  data = pixGetData(pixs);
908  wpl = pixGetWpl(pixs);
909  line = data + y * wpl;
910 
911  /* Check pix value of seed; must be within the image and ON */
912  if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
913  return 0;
914 
915  /* Init stack to seed */
916  pushFillseg(stack, x, x, y, 1, ymax);
917  pushFillseg(stack, x, x, y + 1, -1, ymax);
918 
919  while (lstackGetCount(stack) > 0) {
920  /* Pop segment off stack and fill a neighboring scan line */
921  popFillseg(stack, &x1, &x2, &y, &dy);
922  line = data + y * wpl;
923 
924  /* A segment of scanline y - dy for x1 <= x <= x2 was
925  * previously filled. We now explore adjacent pixels
926  * in scan line y. There are three regions: to the
927  * left of x1 - 1, between x1 and x2, and to the right of x2.
928  * These regions are handled differently. Leaks are
929  * possible expansions beyond the previous segment and
930  * going back in the -dy direction. These can happen
931  * for x < x1 - 1 and for x > x2 + 1. Any "leak" segments
932  * are plugged with a push in the -dy (opposite) direction.
933  * And any segments found anywhere are always extended
934  * in the +dy direction. */
935  for (x = x1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
936  CLEAR_DATA_BIT(line,x);
937  if (x >= x1) /* pix at x1 was off and was not cleared */
938  goto skip;
939  xstart = x + 1;
940  if (xstart < x1 - 1) /* leak on left? */
941  pushFillseg(stack, xstart, x1 - 1, y, -dy, ymax);
942 
943  x = x1 + 1;
944  do {
945  for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
946  CLEAR_DATA_BIT(line, x);
947  pushFillseg(stack, xstart, x - 1, y, dy, ymax);
948  if (x > x2 + 1) /* leak on right? */
949  pushFillseg(stack, x2 + 1, x - 1, y, -dy, ymax);
950  skip: for (x++; x <= x2 &&
951  x <= xmax &&
952  (GET_DATA_BIT(line, x) == 0); x++)
953  ;
954  xstart = x;
955  } while (x <= x2 && x <= xmax);
956  }
957 
958  return 0;
959 }
960 
961 
979 l_int32
981  L_STACK *stack,
982  l_int32 x,
983  l_int32 y)
984 {
985 l_int32 w, h, xstart, wpl, x1, x2, dy;
986 l_int32 xmax, ymax;
987 l_uint32 *data, *line;
988 
989  PROCNAME("pixSeedfill8");
990 
991  if (!pixs || pixGetDepth(pixs) != 1)
992  return ERROR_INT("pixs not defined or not 1 bpp", procName, 1);
993  if (!stack)
994  return ERROR_INT("stack not defined", procName, 1);
995  if (!stack->auxstack)
996  stack->auxstack = lstackCreate(0);
997 
998  pixGetDimensions(pixs, &w, &h, NULL);
999  xmax = w - 1;
1000  ymax = h - 1;
1001  data = pixGetData(pixs);
1002  wpl = pixGetWpl(pixs);
1003  line = data + y * wpl;
1004 
1005  /* Check pix value of seed; must be ON */
1006  if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0))
1007  return 0;
1008 
1009  /* Init stack to seed */
1010  pushFillseg(stack, x, x, y, 1, ymax);
1011  pushFillseg(stack, x, x, y + 1, -1, ymax);
1012 
1013  while (lstackGetCount(stack) > 0) {
1014  /* Pop segment off stack and fill a neighboring scan line */
1015  popFillseg(stack, &x1, &x2, &y, &dy);
1016  line = data + y * wpl;
1017 
1018  /* A segment of scanline y - dy for x1 <= x <= x2 was
1019  * previously filled. We now explore adjacent pixels
1020  * in scan line y. There are three regions: to the
1021  * left of x1, between x1 and x2, and to the right of x2.
1022  * These regions are handled differently. Leaks are
1023  * possible expansions beyond the previous segment and
1024  * going back in the -dy direction. These can happen
1025  * for x < x1 and for x > x2. Any "leak" segments
1026  * are plugged with a push in the -dy (opposite) direction.
1027  * And any segments found anywhere are always extended
1028  * in the +dy direction. */
1029  for (x = x1 - 1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--)
1030  CLEAR_DATA_BIT(line,x);
1031  if (x >= x1 - 1) /* pix at x1 - 1 was off and was not cleared */
1032  goto skip;
1033  xstart = x + 1;
1034  if (xstart < x1) /* leak on left? */
1035  pushFillseg(stack, xstart, x1 - 1, y, -dy, ymax);
1036 
1037  x = x1;
1038  do {
1039  for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++)
1040  CLEAR_DATA_BIT(line, x);
1041  pushFillseg(stack, xstart, x - 1, y, dy, ymax);
1042  if (x > x2) /* leak on right? */
1043  pushFillseg(stack, x2 + 1, x - 1, y, -dy, ymax);
1044  skip: for (x++; x <= x2 + 1 &&
1045  x <= xmax &&
1046  (GET_DATA_BIT(line, x) == 0); x++)
1047  ;
1048  xstart = x;
1049  } while (x <= x2 + 1 && x <= xmax);
1050  }
1051 
1052  return 0;
1053 }
1054 
1055 
1056 
1057 /*-----------------------------------------------------------------------*
1058  * Static stack helper functions: push and pop fillsegs *
1059  *-----------------------------------------------------------------------*/
1082 static void
1084  l_int32 xleft,
1085  l_int32 xright,
1086  l_int32 y,
1087  l_int32 dy,
1088  l_int32 ymax,
1089  l_int32 *pminx,
1090  l_int32 *pmaxx,
1091  l_int32 *pminy,
1092  l_int32 *pmaxy)
1093 {
1094 FILLSEG *fseg;
1095 L_STACK *auxstack;
1096 
1097  PROCNAME("pushFillsegBB");
1098 
1099  if (!stack) {
1100  L_ERROR("stack not defined\n", procName);
1101  return;
1102  }
1103 
1104  *pminx = L_MIN(*pminx, xleft);
1105  *pmaxx = L_MAX(*pmaxx, xright);
1106  *pminy = L_MIN(*pminy, y);
1107  *pmaxy = L_MAX(*pmaxy, y);
1108 
1109  if (y + dy >= 0 && y + dy <= ymax) {
1110  if ((auxstack = stack->auxstack) == NULL) {
1111  L_ERROR("auxstack not defined\n", procName);
1112  return;
1113  }
1114 
1115  /* Get a fillseg to use */
1116  if (lstackGetCount(auxstack) > 0) {
1117  fseg = (FILLSEG *)lstackRemove(auxstack);
1118  } else {
1119  if ((fseg = (FILLSEG *)LEPT_CALLOC(1, sizeof(FILLSEG))) == NULL) {
1120  L_ERROR("fillseg not made\n", procName);
1121  return;
1122  }
1123  }
1124 
1125  fseg->xleft = xleft;
1126  fseg->xright = xright;
1127  fseg->y = y;
1128  fseg->dy = dy;
1129  lstackAdd(stack, fseg);
1130  }
1131  return;
1132 }
1133 
1134 
1153 static void
1155  l_int32 xleft,
1156  l_int32 xright,
1157  l_int32 y,
1158  l_int32 dy,
1159  l_int32 ymax)
1160 {
1161 FILLSEG *fseg;
1162 L_STACK *auxstack;
1163 
1164  PROCNAME("pushFillseg");
1165 
1166  if (!stack) {
1167  L_ERROR("stack not defined\n", procName);
1168  return;
1169  }
1170 
1171  if (y + dy >= 0 && y + dy <= ymax) {
1172  if ((auxstack = stack->auxstack) == NULL) {
1173  L_ERROR("auxstack not defined\n", procName);
1174  return;
1175  }
1176 
1177  /* Get a fillseg to use */
1178  if (lstackGetCount(auxstack) > 0) {
1179  fseg = (FILLSEG *)lstackRemove(auxstack);
1180  } else {
1181  if ((fseg = (FILLSEG *)LEPT_CALLOC(1, sizeof(FILLSEG))) == NULL) {
1182  L_ERROR("fillseg not made\n", procName);
1183  return;
1184  }
1185  }
1186 
1187  fseg->xleft = xleft;
1188  fseg->xright = xright;
1189  fseg->y = y;
1190  fseg->dy = dy;
1191  lstackAdd(stack, fseg);
1192  }
1193  return;
1194 }
1195 
1196 
1214 static void
1216  l_int32 *pxleft,
1217  l_int32 *pxright,
1218  l_int32 *py,
1219  l_int32 *pdy)
1220 {
1221 FILLSEG *fseg;
1222 L_STACK *auxstack;
1223 
1224  PROCNAME("popFillseg");
1225 
1226  if (!stack) {
1227  L_ERROR("stack not defined\n", procName);
1228  return;
1229  }
1230  if ((auxstack = stack->auxstack) == NULL) {
1231  L_ERROR("auxstack not defined\n", procName);
1232  return;
1233  }
1234 
1235  if ((fseg = (FILLSEG *)lstackRemove(stack)) == NULL)
1236  return;
1237 
1238  *pxleft = fseg->xleft;
1239  *pxright = fseg->xright;
1240  *py = fseg->y + fseg->dy; /* this now points to the new line */
1241  *pdy = fseg->dy;
1242 
1243  /* Save it for re-use */
1244  lstackAdd(auxstack, fseg);
1245  return;
1246 }
BOX * pixSeedfill4BB(PIX *pixs, L_STACK *stack, l_int32 x, l_int32 y)
pixSeedfill4BB()
Definition: conncomp.c:621
The struct FillSeg is used by the Heckbert seedfill algorithm to hold information about image segment...
Definition: conncomp.c:99
BOX * pixSeedfillBB(PIX *pixs, L_STACK *stack, l_int32 x, l_int32 y, l_int32 connectivity)
pixSeedfillBB()
Definition: conncomp.c:558
void lstackDestroy(L_STACK **plstack, l_int32 freeflag)
lstackDestroy()
Definition: stack.c:121
struct Boxa * boxa
Definition: pix.h:460
l_int32 nextOnPixelInRaster(PIX *pixs, l_int32 xstart, l_int32 ystart, l_int32 *px, l_int32 *py)
nextOnPixelInRaster()
Definition: conncomp.c:447
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:161
l_int32 pixZero(PIX *pix, l_int32 *pempty)
pixZero()
Definition: pix3.c:1702
BOX * pixSeedfill8BB(PIX *pixs, L_STACK *stack, l_int32 x, l_int32 y)
pixSeedfill8BB()
Definition: conncomp.c:736
l_int32 lstackGetCount(L_STACK *lstack)
lstackGetCount()
Definition: stack.c:247
l_int32 y
Definition: pix.h:483
l_int32 boxaAddBox(BOXA *boxa, BOX *box, l_int32 copyflag)
boxaAddBox()
Definition: boxbasic.c:615
static void pushFillsegBB(L_STACK *stack, l_int32 xleft, l_int32 xright, l_int32 y, l_int32 dy, l_int32 ymax, l_int32 *pminx, l_int32 *pmaxx, l_int32 *pminy, l_int32 *pmaxy)
pushFillsegBB()
Definition: conncomp.c:1083
BOXA * boxaCopy(BOXA *boxa, l_int32 copyflag)
boxaCopy()
Definition: boxbasic.c:531
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:577
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1602
l_int32 y
Definition: conncomp.c:103
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:117
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1013
Definition: pix.h:492
#define CLEAR_DATA_BIT(pdata, n)
Definition: arrayaccess.h:125
l_int32 pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:193
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:144
static const l_int32 L_INSERT
Definition: pix.h:710
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition: pix3.c:1574
void * lstackRemove(L_STACK *lstack)
lstackRemove()
Definition: stack.c:197
l_int32 pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
l_int32 w
Definition: pix.h:484
BOXA * pixConnCompBB(PIX *pixs, l_int32 connectivity)
pixConnCompBB()
Definition: conncomp.c:303
l_int32 pixCountConnComp(PIX *pixs, l_int32 connectivity, l_int32 *pcount)
pixCountConnComp()
Definition: conncomp.c:385
l_int32 pixSeedfill4(PIX *pixs, L_STACK *stack, l_int32 x, l_int32 y)
pixSeedfill4()
Definition: conncomp.c:886
L_STACK * lstackCreate(l_int32 nalloc)
lstackCreate()
Definition: stack.c:78
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:545
l_int32 x
Definition: pix.h:482
Definition: pix.h:454
l_int32 xright
Definition: conncomp.c:102
BOXA * pixConnCompPixa(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnCompPixa()
Definition: conncomp.c:190
static void pushFillseg(L_STACK *stack, l_int32 xleft, l_int32 xright, l_int32 y, l_int32 dy, l_int32 ymax)
pushFillseg()
Definition: conncomp.c:1154
struct L_Stack * auxstack
Definition: stack.h:64
l_int32 dy
Definition: conncomp.c:104
static void popFillseg(L_STACK *stack, l_int32 *pxleft, l_int32 *pxright, l_int32 *py, l_int32 *pdy)
popFillseg()
Definition: conncomp.c:1215
Definition: pix.h:705
l_int32 h
Definition: pix.h:485
Definition: pix.h:134
BOXA * boxaCreate(l_int32 n)
boxaCreate()
Definition: boxbasic.c:496
#define PIX_SRC
Definition: pix.h:327
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:630
l_int32 xleft
Definition: conncomp.c:101
l_int32 pixGetDimensions(PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1052
l_int32 pixSeedfill(PIX *pixs, L_STACK *stack, l_int32 x, l_int32 y, l_int32 connectivity)
pixSeedfill()
Definition: conncomp.c:842
l_int32 pixSeedfill8(PIX *pixs, L_STACK *stack, l_int32 x, l_int32 y)
pixSeedfill8()
Definition: conncomp.c:980
l_int32 nextOnPixelInRasterLow(l_uint32 *data, l_int32 w, l_int32 h, l_int32 wpl, l_int32 xstart, l_int32 ystart, l_int32 *px, l_int32 *py)
nextOnPixelInRasterLow()
Definition: conncomp.c:481
l_int32 pixCountPixels(PIX *pixs, l_int32 *pcount, l_int32 *tab8)
pixCountPixels()
Definition: pix3.c:1824
l_int32 lstackAdd(L_STACK *lstack, void *item)
lstackAdd()
Definition: stack.c:167
Definition: pix.h:480
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:398
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:164
Definition: stack.h:59
#define PIX_DST
Definition: pix.h:328