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