Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/conncomp.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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 | |
| 27 /*! | |
| 28 * \file conncomp.c | |
| 29 * <pre> | |
| 30 * | |
| 31 * Connected component counting and extraction, using Heckbert's | |
| 32 * stack-based filling algorithm. | |
| 33 * | |
| 34 * 4- and 8-connected components: counts, bounding boxes and images | |
| 35 * | |
| 36 * Top-level calls: | |
| 37 * BOXA *pixConnComp() | |
| 38 * BOXA *pixConnCompPixa() | |
| 39 * BOXA *pixConnCompBB() | |
| 40 * l_int32 pixCountConnComp() | |
| 41 * | |
| 42 * Identify the next c.c. to be erased: | |
| 43 * l_int32 nextOnPixelInRaster() | |
| 44 * static l_int32 nextOnPixelInRasterLow() | |
| 45 * | |
| 46 * Erase the c.c., saving the b.b.: | |
| 47 * BOX *pixSeedfillBB() | |
| 48 * BOX *pixSeedfill4BB() | |
| 49 * BOX *pixSeedfill8BB() | |
| 50 * | |
| 51 * Just erase the c.c.: | |
| 52 * l_int32 pixSeedfill() | |
| 53 * l_int32 pixSeedfill4() | |
| 54 * l_int32 pixSeedfill8() | |
| 55 * | |
| 56 * Static stack helper functions for single raster line seedfill: | |
| 57 * static void pushFillsegBB() | |
| 58 * static void pushFillseg() | |
| 59 * static void popFillseg() | |
| 60 * | |
| 61 * The basic method in pixConnCompBB() is very simple. We scan the | |
| 62 * image in raster order, looking for the next ON pixel. When it | |
| 63 * is found, we erase it and every pixel of the 4- or 8-connected | |
| 64 * component to which it belongs, using Heckbert's seedfill | |
| 65 * algorithm. As pixels are erased, we keep track of the | |
| 66 * minimum rectangle that encloses all erased pixels; after | |
| 67 * the connected component has been erased, we save its | |
| 68 * bounding box in an array of boxes. When all pixels in the | |
| 69 * image have been erased, we have an array that describes every | |
| 70 * 4- or 8-connected component in terms of its bounding box. | |
| 71 * | |
| 72 * pixConnCompPixa() is a slight variation on pixConnCompBB(), | |
| 73 * where we additionally save an array of images (in a Pixa) | |
| 74 * of each of the 4- or 8-connected components. This is done trivially | |
| 75 * by maintaining two temporary images. We erase a component from one, | |
| 76 * and use the bounding box to extract the pixels within the b.b. | |
| 77 * from each of the two images. An XOR between these subimages | |
| 78 * gives the erased component. Then we erase the component from the | |
| 79 * second image using the XOR again, with the extracted component | |
| 80 * placed on the second image at the location of the bounding box. | |
| 81 * Rasterop does all the work. At the end, we have an array | |
| 82 * of the 4- or 8-connected components, as well as an array of the | |
| 83 * bounding boxes that describe where they came from in the original image. | |
| 84 * | |
| 85 * If you just want the number of connected components, pixCountConnComp() | |
| 86 * is a bit faster than pixConnCompBB(), because it doesn't have to | |
| 87 * keep track of the bounding rectangles for each c.c. | |
| 88 * </pre> | |
| 89 */ | |
| 90 | |
| 91 #ifdef HAVE_CONFIG_H | |
| 92 #include <config_auto.h> | |
| 93 #endif /* HAVE_CONFIG_H */ | |
| 94 | |
| 95 #include "allheaders.h" | |
| 96 #include "pix_internal.h" | |
| 97 | |
| 98 /*! | |
| 99 * \brief The struct FillSeg is used by the Heckbert seedfill algorithm to | |
| 100 * hold information about image segments that are waiting to be | |
| 101 * investigated. We use two Stacks, one to hold the FillSegs in use, | |
| 102 * and an auxiliary Stack as a reservoir to hold FillSegs for re-use. | |
| 103 */ | |
| 104 struct FillSeg | |
| 105 { | |
| 106 l_int32 xleft; /*!< left edge of run */ | |
| 107 l_int32 xright; /*!< right edge of run */ | |
| 108 l_int32 y; /*!< run y */ | |
| 109 l_int32 dy; /*!< parent segment direction: 1 above, -1 below) */ | |
| 110 }; | |
| 111 typedef struct FillSeg FILLSEG; | |
| 112 | |
| 113 static l_int32 nextOnPixelInRasterLow(l_uint32 *data, l_int32 w, l_int32 h, | |
| 114 l_int32 wpl, l_int32 xstart, | |
| 115 l_int32 ystart, l_int32 *px, l_int32 *py); | |
| 116 | |
| 117 /* Static accessors for FillSegs on a stack */ | |
| 118 static void pushFillsegBB(L_STACK *stack, l_int32 xleft, l_int32 xright, | |
| 119 l_int32 y, l_int32 dy, l_int32 ymax, | |
| 120 l_int32 *pminx, l_int32 *pmaxx, | |
| 121 l_int32 *pminy, l_int32 *pmaxy); | |
| 122 static void pushFillseg(L_STACK *stack, l_int32 xleft, l_int32 xright, | |
| 123 l_int32 y, l_int32 dy, l_int32 ymax); | |
| 124 static void popFillseg(L_STACK *stack, l_int32 *pxleft, l_int32 *pxright, | |
| 125 l_int32 *py, l_int32 *pdy); | |
| 126 | |
| 127 | |
| 128 #ifndef NO_CONSOLE_IO | |
| 129 #define DEBUG 0 | |
| 130 #endif /* ~NO_CONSOLE_IO */ | |
| 131 | |
| 132 | |
| 133 /*-----------------------------------------------------------------------* | |
| 134 * Bounding boxes of 4 Connected Components * | |
| 135 *-----------------------------------------------------------------------*/ | |
| 136 /*! | |
| 137 * \brief pixConnComp() | |
| 138 * | |
| 139 * \param[in] pixs 1 bpp | |
| 140 * \param[out] ppixa [optional] pixa of each c.c. | |
| 141 * \param[in] connectivity 4 or 8 | |
| 142 * \return boxa, or NULL on error | |
| 143 * | |
| 144 * <pre> | |
| 145 * Notes: | |
| 146 * (1) This is the top-level call for getting bounding boxes or | |
| 147 * a pixa of the components, and it can be used instead | |
| 148 * of either pixConnCompBB() or pixConnCompPixa(), rsp. | |
| 149 * </pre> | |
| 150 */ | |
| 151 BOXA * | |
| 152 pixConnComp(PIX *pixs, | |
| 153 PIXA **ppixa, | |
| 154 l_int32 connectivity) | |
| 155 { | |
| 156 | |
| 157 if (ppixa) *ppixa = NULL; | |
| 158 if (!pixs || pixGetDepth(pixs) != 1) | |
| 159 return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL); | |
| 160 if (connectivity != 4 && connectivity != 8) | |
| 161 return (BOXA *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL); | |
| 162 | |
| 163 if (!ppixa) | |
| 164 return pixConnCompBB(pixs, connectivity); | |
| 165 else | |
| 166 return pixConnCompPixa(pixs, ppixa, connectivity); | |
| 167 } | |
| 168 | |
| 169 | |
| 170 /*! | |
| 171 * \brief pixConnCompPixa() | |
| 172 * | |
| 173 * \param[in] pixs 1 bpp | |
| 174 * \param[out] ppixa pixa of each c.c. | |
| 175 * \param[in] connectivity 4 or 8 | |
| 176 * \return boxa, or NULL on error | |
| 177 * | |
| 178 * <pre> | |
| 179 * Notes: | |
| 180 * (1) This finds bounding boxes of 4- or 8-connected components | |
| 181 * in a binary image, and saves images of each c.c | |
| 182 * in a pixa array. | |
| 183 * (2) It sets up 2 temporary pix, and for each c.c. that is | |
| 184 * located in raster order, it erases the c.c. from one pix, | |
| 185 * then uses the b.b. to extract the c.c. from the two pix using | |
| 186 * an XOR, and finally erases the c.c. from the second pix. | |
| 187 * (3) A clone of the returned boxa (where all boxes in the array | |
| 188 * are clones) is inserted into the pixa. | |
| 189 * (4) If the input is valid, this always returns a boxa and a pixa. | |
| 190 * If pixs is empty, the boxa and pixa will be empty. | |
| 191 * </pre> | |
| 192 */ | |
| 193 BOXA * | |
| 194 pixConnCompPixa(PIX *pixs, | |
| 195 PIXA **ppixa, | |
| 196 l_int32 connectivity) | |
| 197 { | |
| 198 l_int32 h, iszero; | |
| 199 l_int32 x, y, xstart, ystart; | |
| 200 PIX *pix1, *pix2, *pix3, *pix4; | |
| 201 PIXA *pixa; | |
| 202 BOX *box; | |
| 203 BOXA *boxa; | |
| 204 L_STACK *stack, *auxstack; | |
| 205 | |
| 206 if (!ppixa) | |
| 207 return (BOXA *)ERROR_PTR("&pixa not defined", __func__, NULL); | |
| 208 *ppixa = NULL; | |
| 209 if (!pixs || pixGetDepth(pixs) != 1) | |
| 210 return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL); | |
| 211 if (connectivity != 4 && connectivity != 8) | |
| 212 return (BOXA *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL); | |
| 213 | |
| 214 pix1 = pix2 = pix3 = pix4 = NULL; | |
| 215 stack = NULL; | |
| 216 pixa = pixaCreate(0); | |
| 217 boxa = NULL; | |
| 218 *ppixa = pixa; | |
| 219 pixZero(pixs, &iszero); | |
| 220 if (iszero) | |
| 221 return boxaCreate(1); /* return empty boxa and empty pixa */ | |
| 222 | |
| 223 pixSetPadBits(pixs, 0); | |
| 224 pix1 = pixCopy(NULL, pixs); | |
| 225 pix2 = pixCopy(NULL, pixs); | |
| 226 if (!pix1 || !pix2) { | |
| 227 L_ERROR("pix1 or pix2 not made\n", __func__); | |
| 228 pixaDestroy(ppixa); | |
| 229 goto cleanup; | |
| 230 } | |
| 231 | |
| 232 h = pixGetHeight(pixs); | |
| 233 if ((stack = lstackCreate(h)) == NULL) { | |
| 234 L_ERROR("stack not made\n", __func__); | |
| 235 pixaDestroy(ppixa); | |
| 236 goto cleanup; | |
| 237 } | |
| 238 auxstack = lstackCreate(0); | |
| 239 stack->auxstack = auxstack; | |
| 240 boxa = boxaCreate(0); | |
| 241 | |
| 242 xstart = 0; | |
| 243 ystart = 0; | |
| 244 while (1) { | |
| 245 if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y)) | |
| 246 break; | |
| 247 | |
| 248 if ((box = pixSeedfillBB(pix1, stack, x, y, connectivity)) == NULL) { | |
| 249 boxaDestroy(&boxa); | |
| 250 pixaDestroy(ppixa); | |
| 251 L_ERROR("box not made\n", __func__); | |
| 252 goto cleanup; | |
| 253 } | |
| 254 boxaAddBox(boxa, box, L_INSERT); | |
| 255 | |
| 256 /* Save the c.c. and remove from pix2 as well */ | |
| 257 pix3 = pixClipRectangle(pix1, box, NULL); | |
| 258 pix4 = pixClipRectangle(pix2, box, NULL); | |
| 259 pixXor(pix3, pix3, pix4); | |
| 260 pixRasterop(pix2, box->x, box->y, box->w, box->h, PIX_SRC ^ PIX_DST, | |
| 261 pix3, 0, 0); | |
| 262 pixaAddPix(pixa, pix3, L_INSERT); | |
| 263 pixDestroy(&pix4); | |
| 264 | |
| 265 xstart = x; | |
| 266 ystart = y; | |
| 267 } | |
| 268 | |
| 269 #if DEBUG | |
| 270 pixCountPixels(pix1, &iszero, NULL); | |
| 271 lept_stderr("Number of remaining pixels = %d\n", iszero); | |
| 272 lept_mkdir("lept/cc"); | |
| 273 pixWriteDebug("/tmp/lept/cc/remain.png", pix1, IFF_PNG); | |
| 274 #endif /* DEBUG */ | |
| 275 | |
| 276 /* Remove old boxa of pixa and replace with a copy */ | |
| 277 boxaDestroy(&pixa->boxa); | |
| 278 pixa->boxa = boxaCopy(boxa, L_COPY); | |
| 279 *ppixa = pixa; | |
| 280 | |
| 281 /* Cleanup, freeing the fillsegs on each stack */ | |
| 282 cleanup: | |
| 283 lstackDestroy(&stack, TRUE); | |
| 284 pixDestroy(&pix1); | |
| 285 pixDestroy(&pix2); | |
| 286 return boxa; | |
| 287 } | |
| 288 | |
| 289 | |
| 290 /*! | |
| 291 * \brief pixConnCompBB() | |
| 292 * | |
| 293 * \param[in] pixs 1 bpp | |
| 294 * \param[in] connectivity 4 or 8 | |
| 295 * \return boxa, or NULL on error | |
| 296 * | |
| 297 * <pre> | |
| 298 * Notes: | |
| 299 * (1) Finds bounding boxes of 4- or 8-connected components | |
| 300 * in a binary image. | |
| 301 * (2) This works on a copy of the input pix. The c.c. are located | |
| 302 * in raster order and erased one at a time. In the process, | |
| 303 * the b.b. is computed and saved. | |
| 304 * </pre> | |
| 305 */ | |
| 306 BOXA * | |
| 307 pixConnCompBB(PIX *pixs, | |
| 308 l_int32 connectivity) | |
| 309 { | |
| 310 l_int32 h, iszero; | |
| 311 l_int32 x, y, xstart, ystart; | |
| 312 PIX *pix1; | |
| 313 BOX *box; | |
| 314 BOXA *boxa; | |
| 315 L_STACK *stack, *auxstack; | |
| 316 | |
| 317 if (!pixs || pixGetDepth(pixs) != 1) | |
| 318 return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL); | |
| 319 if (connectivity != 4 && connectivity != 8) | |
| 320 return (BOXA *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL); | |
| 321 | |
| 322 boxa = NULL; | |
| 323 pix1 = NULL; | |
| 324 stack = NULL; | |
| 325 pixZero(pixs, &iszero); | |
| 326 if (iszero) | |
| 327 return boxaCreate(1); /* return empty boxa */ | |
| 328 | |
| 329 pixSetPadBits(pixs, 0); | |
| 330 if ((pix1 = pixCopy(NULL, pixs)) == NULL) | |
| 331 return (BOXA *)ERROR_PTR("pix1 not made", __func__, NULL); | |
| 332 | |
| 333 h = pixGetHeight(pixs); | |
| 334 if ((stack = lstackCreate(h)) == NULL) { | |
| 335 L_ERROR("stack not made\n", __func__); | |
| 336 goto cleanup; | |
| 337 } | |
| 338 auxstack = lstackCreate(0); | |
| 339 stack->auxstack = auxstack; | |
| 340 boxa = boxaCreate(0); | |
| 341 | |
| 342 xstart = 0; | |
| 343 ystart = 0; | |
| 344 while (1) { | |
| 345 if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y)) | |
| 346 break; | |
| 347 | |
| 348 if ((box = pixSeedfillBB(pix1, stack, x, y, connectivity)) == NULL) { | |
| 349 L_ERROR("box not made\n", __func__); | |
| 350 boxaDestroy(&boxa); | |
| 351 goto cleanup; | |
| 352 } | |
| 353 boxaAddBox(boxa, box, L_INSERT); | |
| 354 | |
| 355 xstart = x; | |
| 356 ystart = y; | |
| 357 } | |
| 358 | |
| 359 #if DEBUG | |
| 360 pixCountPixels(pix1, &iszero, NULL); | |
| 361 lept_stderr("Number of remaining pixels = %d\n", iszero); | |
| 362 lept_mkdir("lept/cc"); | |
| 363 pixWriteDebug("/tmp/lept/cc/remain.png", pix1, IFF_PNG); | |
| 364 #endif /* DEBUG */ | |
| 365 | |
| 366 /* Cleanup, freeing the fillsegs on each stack */ | |
| 367 cleanup: | |
| 368 lstackDestroy(&stack, TRUE); | |
| 369 pixDestroy(&pix1); | |
| 370 return boxa; | |
| 371 } | |
| 372 | |
| 373 | |
| 374 /*! | |
| 375 * \brief pixCountConnComp() | |
| 376 * | |
| 377 * \param[in] pixs 1 bpp | |
| 378 * \param[in] connectivity 4 or 8 | |
| 379 * \param[out] pcount | |
| 380 * \return 0 if OK, 1 on error | |
| 381 * | |
| 382 * Notes: | |
| 383 * (1 This is the top-level call for getting the number of | |
| 384 * 4- or 8-connected components in a 1 bpp image. | |
| 385 * 2 It works on a copy of the input pix. The c.c. are located | |
| 386 * in raster order and erased one at a time. | |
| 387 */ | |
| 388 l_ok | |
| 389 pixCountConnComp(PIX *pixs, | |
| 390 l_int32 connectivity, | |
| 391 l_int32 *pcount) | |
| 392 { | |
| 393 l_int32 h, iszero; | |
| 394 l_int32 x, y, xstart, ystart; | |
| 395 PIX *pix1; | |
| 396 L_STACK *stack, *auxstack; | |
| 397 | |
| 398 if (!pcount) | |
| 399 return ERROR_INT("&count not defined", __func__, 1); | |
| 400 *pcount = 0; /* initialize the count to 0 */ | |
| 401 if (!pixs || pixGetDepth(pixs) != 1) | |
| 402 return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1); | |
| 403 if (connectivity != 4 && connectivity != 8) | |
| 404 return ERROR_INT("connectivity not 4 or 8", __func__, 1); | |
| 405 | |
| 406 stack = NULL; | |
| 407 pixZero(pixs, &iszero); | |
| 408 if (iszero) | |
| 409 return 0; | |
| 410 | |
| 411 pixSetPadBits(pixs, 0); | |
| 412 if ((pix1 = pixCopy(NULL, pixs)) == NULL) | |
| 413 return ERROR_INT("pix1 not made", __func__, 1); | |
| 414 h = pixGetHeight(pixs); | |
| 415 if ((stack = lstackCreate(h)) == NULL) { | |
| 416 pixDestroy(&pix1); | |
| 417 return ERROR_INT("stack not made\n", __func__, 1); | |
| 418 } | |
| 419 auxstack = lstackCreate(0); | |
| 420 stack->auxstack = auxstack; | |
| 421 | |
| 422 xstart = 0; | |
| 423 ystart = 0; | |
| 424 while (1) { | |
| 425 if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y)) | |
| 426 break; | |
| 427 | |
| 428 pixSeedfill(pix1, stack, x, y, connectivity); | |
| 429 (*pcount)++; | |
| 430 xstart = x; | |
| 431 ystart = y; | |
| 432 } | |
| 433 | |
| 434 /* Cleanup, freeing the fillsegs on each stack */ | |
| 435 lstackDestroy(&stack, TRUE); | |
| 436 pixDestroy(&pix1); | |
| 437 return 0; | |
| 438 } | |
| 439 | |
| 440 | |
| 441 /*! | |
| 442 * \brief nextOnPixelInRaster() | |
| 443 * | |
| 444 * \param[in] pixs 1 bpp | |
| 445 * \param[in] xstart, ystart starting point for search | |
| 446 * \param[out] px, py coord value of next ON pixel | |
| 447 * \return 1 if a pixel is found; 0 otherwise or on error | |
| 448 */ | |
| 449 l_int32 | |
| 450 nextOnPixelInRaster(PIX *pixs, | |
| 451 l_int32 xstart, | |
| 452 l_int32 ystart, | |
| 453 l_int32 *px, | |
| 454 l_int32 *py) | |
| 455 { | |
| 456 l_int32 w, h, d, wpl; | |
| 457 l_uint32 *data; | |
| 458 | |
| 459 if (!pixs) | |
| 460 return ERROR_INT("pixs not defined", __func__, 0); | |
| 461 pixGetDimensions(pixs, &w, &h, &d); | |
| 462 if (d != 1) | |
| 463 return ERROR_INT("pixs not 1 bpp", __func__, 0); | |
| 464 | |
| 465 wpl = pixGetWpl(pixs); | |
| 466 data = pixGetData(pixs); | |
| 467 return nextOnPixelInRasterLow(data, w, h, wpl, xstart, ystart, px, py); | |
| 468 } | |
| 469 | |
| 470 | |
| 471 /*! | |
| 472 * \brief nextOnPixelInRasterLow() | |
| 473 * | |
| 474 * \param[in] data pix data | |
| 475 * \param[in] w, h width and height | |
| 476 * \param[in] wpl words per line | |
| 477 * \param[in] xstart, ystart starting point for search | |
| 478 * \param[out] px, py coord value of next ON pixel | |
| 479 * \return 1 if a pixel is found; 0 otherwise or on error | |
| 480 */ | |
| 481 static l_int32 | |
| 482 nextOnPixelInRasterLow(l_uint32 *data, | |
| 483 l_int32 w, | |
| 484 l_int32 h, | |
| 485 l_int32 wpl, | |
| 486 l_int32 xstart, | |
| 487 l_int32 ystart, | |
| 488 l_int32 *px, | |
| 489 l_int32 *py) | |
| 490 { | |
| 491 l_int32 i, x, y, xend, startword; | |
| 492 l_uint32 *line, *pword; | |
| 493 | |
| 494 /* Look at the first word */ | |
| 495 line = data + ystart * wpl; | |
| 496 pword = line + (xstart / 32); | |
| 497 if (*pword) { | |
| 498 xend = xstart - (xstart % 32) + 31; | |
| 499 for (x = xstart; x <= xend && x < w; x++) { | |
| 500 if (GET_DATA_BIT(line, x)) { | |
| 501 *px = x; | |
| 502 *py = ystart; | |
| 503 return 1; | |
| 504 } | |
| 505 } | |
| 506 } | |
| 507 | |
| 508 /* Continue with the rest of the line */ | |
| 509 startword = (xstart / 32) + 1; | |
| 510 x = 32 * startword; | |
| 511 for (pword = line + startword; x < w; pword++, x += 32) { | |
| 512 if (*pword) { | |
| 513 for (i = 0; i < 32 && x < w; i++, x++) { | |
| 514 if (GET_DATA_BIT(line, x)) { | |
| 515 *px = x; | |
| 516 *py = ystart; | |
| 517 return 1; | |
| 518 } | |
| 519 } | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 /* Continue with following lines */ | |
| 524 for (y = ystart + 1; y < h; y++) { | |
| 525 line = data + y * wpl; | |
| 526 for (pword = line, x = 0; x < w; pword++, x += 32) { | |
| 527 if (*pword) { | |
| 528 for (i = 0; i < 32 && x < w; i++, x++) { | |
| 529 if (GET_DATA_BIT(line, x)) { | |
| 530 *px = x; | |
| 531 *py = y; | |
| 532 return 1; | |
| 533 } | |
| 534 } | |
| 535 } | |
| 536 } | |
| 537 } | |
| 538 | |
| 539 return 0; | |
| 540 } | |
| 541 | |
| 542 | |
| 543 /*! | |
| 544 * \brief pixSeedfillBB() | |
| 545 * | |
| 546 * \param[in] pixs 1 bpp | |
| 547 * \param[in] stack for holding fillsegs | |
| 548 * \param[in] x,y location of seed pixel | |
| 549 * \param[in] connectivity 4 or 8 | |
| 550 * \return box or NULL on error | |
| 551 * | |
| 552 * <pre> | |
| 553 * Notes: | |
| 554 * (1) This is the high-level interface to Paul Heckbert's | |
| 555 * stack-based seedfill algorithm. | |
| 556 * </pre> | |
| 557 */ | |
| 558 BOX * | |
| 559 pixSeedfillBB(PIX *pixs, | |
| 560 L_STACK *stack, | |
| 561 l_int32 x, | |
| 562 l_int32 y, | |
| 563 l_int32 connectivity) | |
| 564 { | |
| 565 BOX *box; | |
| 566 | |
| 567 if (!pixs || pixGetDepth(pixs) != 1) | |
| 568 return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL); | |
| 569 if (!stack) | |
| 570 return (BOX *)ERROR_PTR("stack not defined", __func__, NULL); | |
| 571 if (connectivity != 4 && connectivity != 8) | |
| 572 return (BOX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL); | |
| 573 | |
| 574 if (connectivity == 4) { | |
| 575 if ((box = pixSeedfill4BB(pixs, stack, x, y)) == NULL) | |
| 576 return (BOX *)ERROR_PTR("box not made", __func__, NULL); | |
| 577 } else if (connectivity == 8) { | |
| 578 if ((box = pixSeedfill8BB(pixs, stack, x, y)) == NULL) | |
| 579 return (BOX *)ERROR_PTR("box not made", __func__, NULL); | |
| 580 } else { | |
| 581 return (BOX *)ERROR_PTR("connectivity not 4 or 8", __func__, NULL); | |
| 582 } | |
| 583 | |
| 584 return box; | |
| 585 } | |
| 586 | |
| 587 | |
| 588 /*! | |
| 589 * \brief pixSeedfill4BB() | |
| 590 * | |
| 591 * \param[in] pixs 1 bpp | |
| 592 * \param[in] stack for holding fillsegs | |
| 593 * \param[in] x,y location of seed pixel | |
| 594 * \return box or NULL on error. | |
| 595 * | |
| 596 * <pre> | |
| 597 * Notes: | |
| 598 * (1) This is Paul Heckbert's stack-based 4-cc seedfill algorithm. | |
| 599 * (2) This operates on the input 1 bpp pix to remove the fg seed | |
| 600 * pixel, at (x,y), and all pixels that are 4-connected to it. | |
| 601 * The seed pixel at (x,y) must initially be ON. | |
| 602 * (3) Returns the bounding box of the erased 4-cc component. | |
| 603 * (4) Reference: see Paul Heckbert's stack-based seed fill algorithm | |
| 604 * in "Graphic Gems", ed. Andrew Glassner, Academic | |
| 605 * Press, 1990. The algorithm description is given | |
| 606 * on pp. 275-277; working C code is on pp. 721-722.) | |
| 607 * The code here follows Heckbert's exactly, except | |
| 608 * we use function calls instead of macros for | |
| 609 * pushing data on and popping data off the stack. | |
| 610 * This makes sense to do because Heckbert's fixed-size | |
| 611 * stack with macros is dangerous: images exist that | |
| 612 * will overrun the stack and crash. The stack utility | |
| 613 * here grows dynamically as needed, and the fillseg | |
| 614 * structures that are not in use are stored in another | |
| 615 * stack for reuse. It should be noted that the | |
| 616 * overhead in the function calls (vs. macros) is negligible. | |
| 617 * </pre> | |
| 618 */ | |
| 619 BOX * | |
| 620 pixSeedfill4BB(PIX *pixs, | |
| 621 L_STACK *stack, | |
| 622 l_int32 x, | |
| 623 l_int32 y) | |
| 624 { | |
| 625 l_int32 w, h, xstart, wpl, x1, x2, dy; | |
| 626 l_int32 xmax, ymax; | |
| 627 l_int32 minx, maxx, miny, maxy; /* for bounding box of this c.c. */ | |
| 628 l_uint32 *data, *line; | |
| 629 BOX *box; | |
| 630 | |
| 631 if (!pixs || pixGetDepth(pixs) != 1) | |
| 632 return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL); | |
| 633 if (!stack) | |
| 634 return (BOX *)ERROR_PTR("stack not defined", __func__, NULL); | |
| 635 if (!stack->auxstack) | |
| 636 stack->auxstack = lstackCreate(0); | |
| 637 | |
| 638 pixGetDimensions(pixs, &w, &h, NULL); | |
| 639 xmax = w - 1; | |
| 640 ymax = h - 1; | |
| 641 data = pixGetData(pixs); | |
| 642 wpl = pixGetWpl(pixs); | |
| 643 line = data + y * wpl; | |
| 644 | |
| 645 /* Check pix value of seed; must be within the image and ON */ | |
| 646 if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0)) | |
| 647 return NULL; | |
| 648 | |
| 649 /* Init stack to seed: | |
| 650 * Must first init b.b. values to prevent valgrind from complaining; | |
| 651 * then init b.b. boundaries correctly to seed. */ | |
| 652 minx = miny = 100000; | |
| 653 maxx = maxy = 0; | |
| 654 pushFillsegBB(stack, x, x, y, 1, ymax, &minx, &maxx, &miny, &maxy); | |
| 655 pushFillsegBB(stack, x, x, y + 1, -1, ymax, &minx, &maxx, &miny, &maxy); | |
| 656 minx = maxx = x; | |
| 657 miny = maxy = y; | |
| 658 | |
| 659 while (lstackGetCount(stack) > 0) { | |
| 660 /* Pop segment off stack and fill a neighboring scan line */ | |
| 661 popFillseg(stack, &x1, &x2, &y, &dy); | |
| 662 line = data + y * wpl; | |
| 663 | |
| 664 /* A segment of scanline y - dy for x1 <= x <= x2 was | |
| 665 * previously filled. We now explore adjacent pixels | |
| 666 * in scan line y. There are three regions: to the | |
| 667 * left of x1 - 1, between x1 and x2, and to the right of x2. | |
| 668 * These regions are handled differently. Leaks are | |
| 669 * possible expansions beyond the previous segment and | |
| 670 * going back in the -dy direction. These can happen | |
| 671 * for x < x1 - 1 and for x > x2 + 1. Any "leak" segments | |
| 672 * are plugged with a push in the -dy (opposite) direction. | |
| 673 * And any segments found anywhere are always extended | |
| 674 * in the +dy direction. */ | |
| 675 for (x = x1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--) | |
| 676 CLEAR_DATA_BIT(line,x); | |
| 677 if (x >= x1) /* pix at x1 was off and was not cleared */ | |
| 678 goto skip; | |
| 679 xstart = x + 1; | |
| 680 if (xstart < x1 - 1) /* leak on left? */ | |
| 681 pushFillsegBB(stack, xstart, x1 - 1, y, -dy, | |
| 682 ymax, &minx, &maxx, &miny, &maxy); | |
| 683 | |
| 684 x = x1 + 1; | |
| 685 do { | |
| 686 for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++) | |
| 687 CLEAR_DATA_BIT(line, x); | |
| 688 pushFillsegBB(stack, xstart, x - 1, y, dy, | |
| 689 ymax, &minx, &maxx, &miny, &maxy); | |
| 690 if (x > x2 + 1) /* leak on right? */ | |
| 691 pushFillsegBB(stack, x2 + 1, x - 1, y, -dy, | |
| 692 ymax, &minx, &maxx, &miny, &maxy); | |
| 693 skip: for (x++; x <= x2 && | |
| 694 x <= xmax && | |
| 695 (GET_DATA_BIT(line, x) == 0); x++) | |
| 696 ; | |
| 697 xstart = x; | |
| 698 } while (x <= x2 && x <= xmax); | |
| 699 } | |
| 700 | |
| 701 if ((box = boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1)) | |
| 702 == NULL) | |
| 703 return (BOX *)ERROR_PTR("box not made", __func__, NULL); | |
| 704 return box; | |
| 705 } | |
| 706 | |
| 707 | |
| 708 /*! | |
| 709 * \brief pixSeedfill8BB() | |
| 710 * | |
| 711 * \param[in] pixs 1 bpp | |
| 712 * \param[in] stack for holding fillsegs | |
| 713 * \param[in] x,y location of seed pixel | |
| 714 * \return box or NULL on error. | |
| 715 * | |
| 716 * <pre> | |
| 717 * Notes: | |
| 718 * (1) This is Paul Heckbert's stack-based 8-cc seedfill algorithm. | |
| 719 * (2) This operates on the input 1 bpp pix to remove the fg seed | |
| 720 * pixel, at (x,y), and all pixels that are 8-connected to it. | |
| 721 * The seed pixel at (x,y) must initially be ON. | |
| 722 * (3) Returns the bounding box of the erased 8-cc component. | |
| 723 * (4) Reference: see Paul Heckbert's stack-based seed fill algorithm | |
| 724 * in "Graphic Gems", ed. Andrew Glassner, Academic | |
| 725 * Press, 1990. The algorithm description is given | |
| 726 * on pp. 275-277; working C code is on pp. 721-722.) | |
| 727 * The code here follows Heckbert's closely, except | |
| 728 * the leak checks are changed for 8 connectivity. | |
| 729 * See comments on pixSeedfill4BB() for more details. | |
| 730 * </pre> | |
| 731 */ | |
| 732 BOX * | |
| 733 pixSeedfill8BB(PIX *pixs, | |
| 734 L_STACK *stack, | |
| 735 l_int32 x, | |
| 736 l_int32 y) | |
| 737 { | |
| 738 l_int32 w, h, xstart, wpl, x1, x2, dy; | |
| 739 l_int32 xmax, ymax; | |
| 740 l_int32 minx, maxx, miny, maxy; /* for bounding box of this c.c. */ | |
| 741 l_uint32 *data, *line; | |
| 742 BOX *box; | |
| 743 | |
| 744 if (!pixs || pixGetDepth(pixs) != 1) | |
| 745 return (BOX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL); | |
| 746 if (!stack) | |
| 747 return (BOX *)ERROR_PTR("stack not defined", __func__, NULL); | |
| 748 if (!stack->auxstack) | |
| 749 stack->auxstack = lstackCreate(0); | |
| 750 | |
| 751 pixGetDimensions(pixs, &w, &h, NULL); | |
| 752 xmax = w - 1; | |
| 753 ymax = h - 1; | |
| 754 data = pixGetData(pixs); | |
| 755 wpl = pixGetWpl(pixs); | |
| 756 line = data + y * wpl; | |
| 757 | |
| 758 /* Check pix value of seed; must be ON */ | |
| 759 if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0)) | |
| 760 return NULL; | |
| 761 | |
| 762 /* Init stack to seed: | |
| 763 * Must first init b.b. values to prevent valgrind from complaining; | |
| 764 * then init b.b. boundaries correctly to seed. */ | |
| 765 minx = miny = 100000; | |
| 766 maxx = maxy = 0; | |
| 767 pushFillsegBB(stack, x, x, y, 1, ymax, &minx, &maxx, &miny, &maxy); | |
| 768 pushFillsegBB(stack, x, x, y + 1, -1, ymax, &minx, &maxx, &miny, &maxy); | |
| 769 minx = maxx = x; | |
| 770 miny = maxy = y; | |
| 771 | |
| 772 while (lstackGetCount(stack) > 0) { | |
| 773 /* Pop segment off stack and fill a neighboring scan line */ | |
| 774 popFillseg(stack, &x1, &x2, &y, &dy); | |
| 775 line = data + y * wpl; | |
| 776 | |
| 777 /* A segment of scanline y - dy for x1 <= x <= x2 was | |
| 778 * previously filled. We now explore adjacent pixels | |
| 779 * in scan line y. There are three regions: to the | |
| 780 * left of x1, between x1 and x2, and to the right of x2. | |
| 781 * These regions are handled differently. Leaks are | |
| 782 * possible expansions beyond the previous segment and | |
| 783 * going back in the -dy direction. These can happen | |
| 784 * for x < x1 and for x > x2. Any "leak" segments | |
| 785 * are plugged with a push in the -dy (opposite) direction. | |
| 786 * And any segments found anywhere are always extended | |
| 787 * in the +dy direction. */ | |
| 788 for (x = x1 - 1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--) | |
| 789 CLEAR_DATA_BIT(line,x); | |
| 790 if (x >= x1 - 1) /* pix at x1 - 1 was off and was not cleared */ | |
| 791 goto skip; | |
| 792 xstart = x + 1; | |
| 793 if (xstart < x1) /* leak on left? */ | |
| 794 pushFillsegBB(stack, xstart, x1 - 1, y, -dy, | |
| 795 ymax, &minx, &maxx, &miny, &maxy); | |
| 796 | |
| 797 x = x1; | |
| 798 do { | |
| 799 for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++) | |
| 800 CLEAR_DATA_BIT(line, x); | |
| 801 pushFillsegBB(stack, xstart, x - 1, y, dy, | |
| 802 ymax, &minx, &maxx, &miny, &maxy); | |
| 803 if (x > x2) /* leak on right? */ | |
| 804 pushFillsegBB(stack, x2 + 1, x - 1, y, -dy, | |
| 805 ymax, &minx, &maxx, &miny, &maxy); | |
| 806 skip: for (x++; x <= x2 + 1 && | |
| 807 x <= xmax && | |
| 808 (GET_DATA_BIT(line, x) == 0); x++) | |
| 809 ; | |
| 810 xstart = x; | |
| 811 } while (x <= x2 + 1 && x <= xmax); | |
| 812 } | |
| 813 | |
| 814 if ((box = boxCreate(minx, miny, maxx - minx + 1, maxy - miny + 1)) | |
| 815 == NULL) | |
| 816 return (BOX *)ERROR_PTR("box not made", __func__, NULL); | |
| 817 return box; | |
| 818 } | |
| 819 | |
| 820 | |
| 821 /*! | |
| 822 * \brief pixSeedfill() | |
| 823 * | |
| 824 * \param[in] pixs 1 bpp | |
| 825 * \param[in] stack for holding fillsegs | |
| 826 * \param[in] x,y location of seed pixel | |
| 827 * \param[in] connectivity 4 or 8 | |
| 828 * \return 0 if OK, 1 on error | |
| 829 * | |
| 830 * <pre> | |
| 831 * Notes: | |
| 832 * (1) This removes the component from pixs with a fg pixel at (x,y). | |
| 833 * (2) See pixSeedfill4() and pixSeedfill8() for details. | |
| 834 * </pre> | |
| 835 */ | |
| 836 l_ok | |
| 837 pixSeedfill(PIX *pixs, | |
| 838 L_STACK *stack, | |
| 839 l_int32 x, | |
| 840 l_int32 y, | |
| 841 l_int32 connectivity) | |
| 842 { | |
| 843 l_int32 retval; | |
| 844 | |
| 845 if (!pixs || pixGetDepth(pixs) != 1) | |
| 846 return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1); | |
| 847 if (!stack) | |
| 848 return ERROR_INT("stack not defined", __func__, 1); | |
| 849 if (connectivity != 4 && connectivity != 8) | |
| 850 return ERROR_INT("connectivity not 4 or 8", __func__, 1); | |
| 851 | |
| 852 if (connectivity == 4) | |
| 853 retval = pixSeedfill4(pixs, stack, x, y); | |
| 854 else /* connectivity == 8 */ | |
| 855 retval = pixSeedfill8(pixs, stack, x, y); | |
| 856 | |
| 857 return retval; | |
| 858 } | |
| 859 | |
| 860 | |
| 861 /*! | |
| 862 * \brief pixSeedfill4() | |
| 863 * | |
| 864 * \param[in] pixs 1 bpp | |
| 865 * \param[in] stack for holding fillsegs | |
| 866 * \param[in] x,y location of seed pixel | |
| 867 * \return 0 if OK, 1 on error | |
| 868 * | |
| 869 * <pre> | |
| 870 * Notes: | |
| 871 * (1) This is Paul Heckbert's stack-based 4-cc seedfill algorithm. | |
| 872 * (2) This operates on the input 1 bpp pix to remove the fg seed | |
| 873 * pixel, at (x,y), and all pixels that are 4-connected to it. | |
| 874 * The seed pixel at (x,y) must initially be ON. | |
| 875 * (3) Reference: see pixSeedFill4BB() | |
| 876 * </pre> | |
| 877 */ | |
| 878 l_ok | |
| 879 pixSeedfill4(PIX *pixs, | |
| 880 L_STACK *stack, | |
| 881 l_int32 x, | |
| 882 l_int32 y) | |
| 883 { | |
| 884 l_int32 w, h, xstart, wpl, x1, x2, dy; | |
| 885 l_int32 xmax, ymax; | |
| 886 l_uint32 *data, *line; | |
| 887 | |
| 888 if (!pixs || pixGetDepth(pixs) != 1) | |
| 889 return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1); | |
| 890 if (!stack) | |
| 891 return ERROR_INT("stack not defined", __func__, 1); | |
| 892 if (!stack->auxstack) | |
| 893 stack->auxstack = lstackCreate(0); | |
| 894 | |
| 895 pixGetDimensions(pixs, &w, &h, NULL); | |
| 896 xmax = w - 1; | |
| 897 ymax = h - 1; | |
| 898 data = pixGetData(pixs); | |
| 899 wpl = pixGetWpl(pixs); | |
| 900 line = data + y * wpl; | |
| 901 | |
| 902 /* Check pix value of seed; must be within the image and ON */ | |
| 903 if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0)) | |
| 904 return 0; | |
| 905 | |
| 906 /* Init stack to seed */ | |
| 907 pushFillseg(stack, x, x, y, 1, ymax); | |
| 908 pushFillseg(stack, x, x, y + 1, -1, ymax); | |
| 909 | |
| 910 while (lstackGetCount(stack) > 0) { | |
| 911 /* Pop segment off stack and fill a neighboring scan line */ | |
| 912 popFillseg(stack, &x1, &x2, &y, &dy); | |
| 913 line = data + y * wpl; | |
| 914 | |
| 915 /* A segment of scanline y - dy for x1 <= x <= x2 was | |
| 916 * previously filled. We now explore adjacent pixels | |
| 917 * in scan line y. There are three regions: to the | |
| 918 * left of x1 - 1, between x1 and x2, and to the right of x2. | |
| 919 * These regions are handled differently. Leaks are | |
| 920 * possible expansions beyond the previous segment and | |
| 921 * going back in the -dy direction. These can happen | |
| 922 * for x < x1 - 1 and for x > x2 + 1. Any "leak" segments | |
| 923 * are plugged with a push in the -dy (opposite) direction. | |
| 924 * And any segments found anywhere are always extended | |
| 925 * in the +dy direction. */ | |
| 926 for (x = x1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--) | |
| 927 CLEAR_DATA_BIT(line,x); | |
| 928 if (x >= x1) /* pix at x1 was off and was not cleared */ | |
| 929 goto skip; | |
| 930 xstart = x + 1; | |
| 931 if (xstart < x1 - 1) /* leak on left? */ | |
| 932 pushFillseg(stack, xstart, x1 - 1, y, -dy, ymax); | |
| 933 | |
| 934 x = x1 + 1; | |
| 935 do { | |
| 936 for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++) | |
| 937 CLEAR_DATA_BIT(line, x); | |
| 938 pushFillseg(stack, xstart, x - 1, y, dy, ymax); | |
| 939 if (x > x2 + 1) /* leak on right? */ | |
| 940 pushFillseg(stack, x2 + 1, x - 1, y, -dy, ymax); | |
| 941 skip: for (x++; x <= x2 && | |
| 942 x <= xmax && | |
| 943 (GET_DATA_BIT(line, x) == 0); x++) | |
| 944 ; | |
| 945 xstart = x; | |
| 946 } while (x <= x2 && x <= xmax); | |
| 947 } | |
| 948 | |
| 949 return 0; | |
| 950 } | |
| 951 | |
| 952 | |
| 953 /*! | |
| 954 * \brief pixSeedfill8() | |
| 955 * | |
| 956 * \param[in] pixs 1 bpp | |
| 957 * \param[in] stack for holding fillsegs | |
| 958 * \param[in] x,y location of seed pixel | |
| 959 * \return 0 if OK, 1 on error | |
| 960 * | |
| 961 * <pre> | |
| 962 * Notes: | |
| 963 * (1) This is Paul Heckbert's stack-based 8-cc seedfill algorithm. | |
| 964 * (2) This operates on the input 1 bpp pix to remove the fg seed | |
| 965 * pixel, at (x,y), and all pixels that are 8-connected to it. | |
| 966 * The seed pixel at (x,y) must initially be ON. | |
| 967 * (3) Reference: see pixSeedFill8BB() | |
| 968 * </pre> | |
| 969 */ | |
| 970 l_ok | |
| 971 pixSeedfill8(PIX *pixs, | |
| 972 L_STACK *stack, | |
| 973 l_int32 x, | |
| 974 l_int32 y) | |
| 975 { | |
| 976 l_int32 w, h, xstart, wpl, x1, x2, dy; | |
| 977 l_int32 xmax, ymax; | |
| 978 l_uint32 *data, *line; | |
| 979 | |
| 980 if (!pixs || pixGetDepth(pixs) != 1) | |
| 981 return ERROR_INT("pixs not defined or not 1 bpp", __func__, 1); | |
| 982 if (!stack) | |
| 983 return ERROR_INT("stack not defined", __func__, 1); | |
| 984 if (!stack->auxstack) | |
| 985 stack->auxstack = lstackCreate(0); | |
| 986 | |
| 987 pixGetDimensions(pixs, &w, &h, NULL); | |
| 988 xmax = w - 1; | |
| 989 ymax = h - 1; | |
| 990 data = pixGetData(pixs); | |
| 991 wpl = pixGetWpl(pixs); | |
| 992 line = data + y * wpl; | |
| 993 | |
| 994 /* Check pix value of seed; must be ON */ | |
| 995 if (x < 0 || x > xmax || y < 0 || y > ymax || (GET_DATA_BIT(line, x) == 0)) | |
| 996 return 0; | |
| 997 | |
| 998 /* Init stack to seed */ | |
| 999 pushFillseg(stack, x, x, y, 1, ymax); | |
| 1000 pushFillseg(stack, x, x, y + 1, -1, ymax); | |
| 1001 | |
| 1002 while (lstackGetCount(stack) > 0) { | |
| 1003 /* Pop segment off stack and fill a neighboring scan line */ | |
| 1004 popFillseg(stack, &x1, &x2, &y, &dy); | |
| 1005 line = data + y * wpl; | |
| 1006 | |
| 1007 /* A segment of scanline y - dy for x1 <= x <= x2 was | |
| 1008 * previously filled. We now explore adjacent pixels | |
| 1009 * in scan line y. There are three regions: to the | |
| 1010 * left of x1, between x1 and x2, and to the right of x2. | |
| 1011 * These regions are handled differently. Leaks are | |
| 1012 * possible expansions beyond the previous segment and | |
| 1013 * going back in the -dy direction. These can happen | |
| 1014 * for x < x1 and for x > x2. Any "leak" segments | |
| 1015 * are plugged with a push in the -dy (opposite) direction. | |
| 1016 * And any segments found anywhere are always extended | |
| 1017 * in the +dy direction. */ | |
| 1018 for (x = x1 - 1; x >= 0 && (GET_DATA_BIT(line, x) == 1); x--) | |
| 1019 CLEAR_DATA_BIT(line,x); | |
| 1020 if (x >= x1 - 1) /* pix at x1 - 1 was off and was not cleared */ | |
| 1021 goto skip; | |
| 1022 xstart = x + 1; | |
| 1023 if (xstart < x1) /* leak on left? */ | |
| 1024 pushFillseg(stack, xstart, x1 - 1, y, -dy, ymax); | |
| 1025 | |
| 1026 x = x1; | |
| 1027 do { | |
| 1028 for (; x <= xmax && (GET_DATA_BIT(line, x) == 1); x++) | |
| 1029 CLEAR_DATA_BIT(line, x); | |
| 1030 pushFillseg(stack, xstart, x - 1, y, dy, ymax); | |
| 1031 if (x > x2) /* leak on right? */ | |
| 1032 pushFillseg(stack, x2 + 1, x - 1, y, -dy, ymax); | |
| 1033 skip: for (x++; x <= x2 + 1 && | |
| 1034 x <= xmax && | |
| 1035 (GET_DATA_BIT(line, x) == 0); x++) | |
| 1036 ; | |
| 1037 xstart = x; | |
| 1038 } while (x <= x2 + 1 && x <= xmax); | |
| 1039 } | |
| 1040 | |
| 1041 return 0; | |
| 1042 } | |
| 1043 | |
| 1044 | |
| 1045 | |
| 1046 /*-----------------------------------------------------------------------* | |
| 1047 * Static stack helper functions: push and pop fillsegs * | |
| 1048 *-----------------------------------------------------------------------*/ | |
| 1049 /*! | |
| 1050 * \brief pushFillsegBB() | |
| 1051 * | |
| 1052 * \param[in] stack | |
| 1053 * \param[in] xleft, xright | |
| 1054 * \param[in] y | |
| 1055 * \param[in] dy | |
| 1056 * \param[in] ymax | |
| 1057 * \param[out] pminx minimum x | |
| 1058 * \param[out] pmaxx maximum x | |
| 1059 * \param[out] pminy minimum y | |
| 1060 * \param[out] pmaxy maximum y | |
| 1061 * \return void | |
| 1062 * | |
| 1063 * <pre> | |
| 1064 * Notes: | |
| 1065 * (1) This adds a line segment to the stack, and returns its size. | |
| 1066 * (2) The auxiliary stack is used as a storage area to recycle | |
| 1067 * fillsegs that are no longer in use. We only calloc new | |
| 1068 * fillsegs if the auxiliary stack is empty. | |
| 1069 * </pre> | |
| 1070 */ | |
| 1071 static void | |
| 1072 pushFillsegBB(L_STACK *stack, | |
| 1073 l_int32 xleft, | |
| 1074 l_int32 xright, | |
| 1075 l_int32 y, | |
| 1076 l_int32 dy, | |
| 1077 l_int32 ymax, | |
| 1078 l_int32 *pminx, | |
| 1079 l_int32 *pmaxx, | |
| 1080 l_int32 *pminy, | |
| 1081 l_int32 *pmaxy) | |
| 1082 { | |
| 1083 FILLSEG *fseg; | |
| 1084 L_STACK *auxstack; | |
| 1085 | |
| 1086 if (!stack) { | |
| 1087 L_ERROR("stack not defined\n", __func__); | |
| 1088 return; | |
| 1089 } | |
| 1090 | |
| 1091 *pminx = L_MIN(*pminx, xleft); | |
| 1092 *pmaxx = L_MAX(*pmaxx, xright); | |
| 1093 *pminy = L_MIN(*pminy, y); | |
| 1094 *pmaxy = L_MAX(*pmaxy, y); | |
| 1095 | |
| 1096 if (y + dy >= 0 && y + dy <= ymax) { | |
| 1097 if ((auxstack = stack->auxstack) == NULL) { | |
| 1098 L_ERROR("auxstack not defined\n", __func__); | |
| 1099 return; | |
| 1100 } | |
| 1101 | |
| 1102 /* Get a fillseg to use */ | |
| 1103 if (lstackGetCount(auxstack) > 0) | |
| 1104 fseg = (FILLSEG *)lstackRemove(auxstack); | |
| 1105 else | |
| 1106 fseg = (FILLSEG *)LEPT_CALLOC(1, sizeof(FILLSEG)); | |
| 1107 fseg->xleft = xleft; | |
| 1108 fseg->xright = xright; | |
| 1109 fseg->y = y; | |
| 1110 fseg->dy = dy; | |
| 1111 lstackAdd(stack, fseg); | |
| 1112 } | |
| 1113 } | |
| 1114 | |
| 1115 | |
| 1116 /*! | |
| 1117 * \brief pushFillseg() | |
| 1118 * | |
| 1119 * \param[in] stack | |
| 1120 * \param[in] xleft, xright | |
| 1121 * \param[in] y | |
| 1122 * \param[in] dy | |
| 1123 * \param[in] ymax | |
| 1124 * \return void | |
| 1125 * | |
| 1126 * <pre> | |
| 1127 * Notes: | |
| 1128 * (1) This adds a line segment to the stack. | |
| 1129 * (2) The auxiliary stack is used as a storage area to recycle | |
| 1130 * fillsegs that are no longer in use. We only calloc new | |
| 1131 * fillsegs if the auxiliary stack is empty. | |
| 1132 * </pre> | |
| 1133 */ | |
| 1134 static void | |
| 1135 pushFillseg(L_STACK *stack, | |
| 1136 l_int32 xleft, | |
| 1137 l_int32 xright, | |
| 1138 l_int32 y, | |
| 1139 l_int32 dy, | |
| 1140 l_int32 ymax) | |
| 1141 { | |
| 1142 FILLSEG *fseg; | |
| 1143 L_STACK *auxstack; | |
| 1144 | |
| 1145 if (!stack) { | |
| 1146 L_ERROR("stack not defined\n", __func__); | |
| 1147 return; | |
| 1148 } | |
| 1149 | |
| 1150 if (y + dy >= 0 && y + dy <= ymax) { | |
| 1151 if ((auxstack = stack->auxstack) == NULL) { | |
| 1152 L_ERROR("auxstack not defined\n", __func__); | |
| 1153 return; | |
| 1154 } | |
| 1155 | |
| 1156 /* Get a fillseg to use */ | |
| 1157 if (lstackGetCount(auxstack) > 0) | |
| 1158 fseg = (FILLSEG *)lstackRemove(auxstack); | |
| 1159 else | |
| 1160 fseg = (FILLSEG *)LEPT_CALLOC(1, sizeof(FILLSEG)); | |
| 1161 fseg->xleft = xleft; | |
| 1162 fseg->xright = xright; | |
| 1163 fseg->y = y; | |
| 1164 fseg->dy = dy; | |
| 1165 lstackAdd(stack, fseg); | |
| 1166 } | |
| 1167 } | |
| 1168 | |
| 1169 | |
| 1170 /*! | |
| 1171 * \brief popFillseg() | |
| 1172 * | |
| 1173 * \param[in] stack | |
| 1174 * \param[out] pxleft left x | |
| 1175 * \param[out] pxright right x | |
| 1176 * \param[out] py y coordinate | |
| 1177 * \param[out] pdy delta y | |
| 1178 * \return void | |
| 1179 * | |
| 1180 * <pre> | |
| 1181 * Notes: | |
| 1182 * (1) This removes a line segment from the stack, and returns its size. | |
| 1183 * (2) The surplussed fillseg is placed on the auxiliary stack | |
| 1184 * for future use. | |
| 1185 * </pre> | |
| 1186 */ | |
| 1187 static void | |
| 1188 popFillseg(L_STACK *stack, | |
| 1189 l_int32 *pxleft, | |
| 1190 l_int32 *pxright, | |
| 1191 l_int32 *py, | |
| 1192 l_int32 *pdy) | |
| 1193 { | |
| 1194 FILLSEG *fseg; | |
| 1195 L_STACK *auxstack; | |
| 1196 | |
| 1197 if (!stack) { | |
| 1198 L_ERROR("stack not defined\n", __func__); | |
| 1199 return; | |
| 1200 } | |
| 1201 if ((auxstack = stack->auxstack) == NULL) { | |
| 1202 L_ERROR("auxstack not defined\n", __func__); | |
| 1203 return; | |
| 1204 } | |
| 1205 | |
| 1206 if ((fseg = (FILLSEG *)lstackRemove(stack)) == NULL) | |
| 1207 return; | |
| 1208 | |
| 1209 *pxleft = fseg->xleft; | |
| 1210 *pxright = fseg->xright; | |
| 1211 *py = fseg->y + fseg->dy; /* this now points to the new line */ | |
| 1212 *pdy = fseg->dy; | |
| 1213 | |
| 1214 /* Save it for re-use */ | |
| 1215 lstackAdd(auxstack, fseg); | |
| 1216 } |
