Leptonica 1.68
C Image Processing Library
|
00001 /*====================================================================* 00002 - Copyright (C) 2001 Leptonica. All rights reserved. 00003 - This software is distributed in the hope that it will be 00004 - useful, but with NO WARRANTY OF ANY KIND. 00005 - No author or distributor accepts responsibility to anyone for the 00006 - consequences of using this software, or for whether it serves any 00007 - particular purpose or works at all, unless he or she says so in 00008 - writing. Everyone is granted permission to copy, modify and 00009 - redistribute this source code, for commercial or non-commercial 00010 - purposes, with the following restrictions: (1) the origin of this 00011 - source code must not be misrepresented; (2) modified versions must 00012 - be plainly marked as such; and (3) this notice may not be removed 00013 - or altered from any source or modified source distribution. 00014 *====================================================================*/ 00015 00016 /* 00017 * seedfilllow.c 00018 * 00019 * Seedfill: 00020 * Gray seedfill (source: Luc Vincent:fast-hybrid-grayscale-reconstruction) 00021 * void seedfillBinaryLow() 00022 * void seedfillGrayLow() 00023 * void seedfillGrayInvLow() 00024 * void seedfillGrayLowSimple() 00025 * void seedfillGrayInvLowSimple() 00026 * 00027 * Distance function: 00028 * void distanceFunctionLow() 00029 * 00030 * Seed spread: 00031 * void seedspreadLow() 00032 * 00033 */ 00034 00035 #include <stdio.h> 00036 #include <stdlib.h> 00037 #include <math.h> 00038 #include "allheaders.h" 00039 00040 struct L_Pixel 00041 { 00042 l_int32 x; 00043 l_int32 y; 00044 }; 00045 typedef struct L_Pixel L_PIXEL; 00046 00047 00048 /*-----------------------------------------------------------------------* 00049 * Vincent's Iterative Binary Seedfill * 00050 *-----------------------------------------------------------------------*/ 00051 /*! 00052 * seedfillBinaryLow() 00053 * 00054 * Notes: 00055 * (1) This is an in-place fill, where the seed image is 00056 * filled, clipping to the filling mask, in one full 00057 * cycle of UL -> LR and LR -> UL raster scans. 00058 * (2) Assume the mask is a filling mask, not a blocking mask. 00059 * (3) Assume that the RHS pad bits of the mask 00060 * are properly set to 0. 00061 * (4) Clip to the smallest dimensions to avoid invalid reads. 00062 */ 00063 void 00064 seedfillBinaryLow(l_uint32 *datas, 00065 l_int32 hs, 00066 l_int32 wpls, 00067 l_uint32 *datam, 00068 l_int32 hm, 00069 l_int32 wplm, 00070 l_int32 connectivity) 00071 { 00072 l_int32 i, j, h, wpl; 00073 l_uint32 word, mask; 00074 l_uint32 wordabove, wordleft, wordbelow, wordright; 00075 l_uint32 wordprev; /* test against this in previous iteration */ 00076 l_uint32 *lines, *linem; 00077 00078 PROCNAME("seedfillBinaryLow"); 00079 00080 h = L_MIN(hs, hm); 00081 wpl = L_MIN(wpls, wplm); 00082 00083 switch (connectivity) 00084 { 00085 case 4: 00086 /* UL --> LR scan */ 00087 for (i = 0; i < h; i++) { 00088 lines = datas + i * wpls; 00089 linem = datam + i * wplm; 00090 for (j = 0; j < wpl; j++) { 00091 word = *(lines + j); 00092 mask = *(linem + j); 00093 00094 /* OR from word above and from word to left; mask */ 00095 if (i > 0) { 00096 wordabove = *(lines - wpls + j); 00097 word |= wordabove; 00098 } 00099 if (j > 0) { 00100 wordleft = *(lines + j - 1); 00101 word |= wordleft << 31; 00102 } 00103 word &= mask; 00104 00105 /* No need to fill horizontally? */ 00106 if (!word || !(~word)) { 00107 *(lines + j) = word; 00108 continue; 00109 } 00110 00111 while (1) { 00112 wordprev = word; 00113 word = (word | (word >> 1) | (word << 1)) & mask; 00114 if ((word ^ wordprev) == 0) { 00115 *(lines + j) = word; 00116 break; 00117 } 00118 } 00119 } 00120 } 00121 00122 /* LR --> UL scan */ 00123 for (i = h - 1; i >= 0; i--) { 00124 lines = datas + i * wpls; 00125 linem = datam + i * wplm; 00126 for (j = wpl - 1; j >= 0; j--) { 00127 word = *(lines + j); 00128 mask = *(linem + j); 00129 00130 /* OR from word below and from word to right; mask */ 00131 if (i < h - 1) { 00132 wordbelow = *(lines + wpls + j); 00133 word |= wordbelow; 00134 } 00135 if (j < wpl - 1) { 00136 wordright = *(lines + j + 1); 00137 word |= wordright >> 31; 00138 } 00139 word &= mask; 00140 00141 /* No need to fill horizontally? */ 00142 if (!word || !(~word)) { 00143 *(lines + j) = word; 00144 continue; 00145 } 00146 00147 while (1) { 00148 wordprev = word; 00149 word = (word | (word >> 1) | (word << 1)) & mask; 00150 if ((word ^ wordprev) == 0) { 00151 *(lines + j) = word; 00152 break; 00153 } 00154 } 00155 } 00156 } 00157 break; 00158 00159 case 8: 00160 /* UL --> LR scan */ 00161 for (i = 0; i < h; i++) { 00162 lines = datas + i * wpls; 00163 linem = datam + i * wplm; 00164 for (j = 0; j < wpl; j++) { 00165 word = *(lines + j); 00166 mask = *(linem + j); 00167 00168 /* OR from words above and from word to left; mask */ 00169 if (i > 0) { 00170 wordabove = *(lines - wpls + j); 00171 word |= (wordabove | (wordabove << 1) | (wordabove >> 1)); 00172 if (j > 0) 00173 word |= (*(lines - wpls + j - 1)) << 31; 00174 if (j < wpl - 1) 00175 word |= (*(lines - wpls + j + 1)) >> 31; 00176 } 00177 if (j > 0) { 00178 wordleft = *(lines + j - 1); 00179 word |= wordleft << 31; 00180 } 00181 word &= mask; 00182 00183 /* No need to fill horizontally? */ 00184 if (!word || !(~word)) { 00185 *(lines + j) = word; 00186 continue; 00187 } 00188 00189 while (1) { 00190 wordprev = word; 00191 word = (word | (word >> 1) | (word << 1)) & mask; 00192 if ((word ^ wordprev) == 0) { 00193 *(lines + j) = word; 00194 break; 00195 } 00196 } 00197 } 00198 } 00199 00200 /* LR --> UL scan */ 00201 for (i = h - 1; i >= 0; i--) { 00202 lines = datas + i * wpls; 00203 linem = datam + i * wplm; 00204 for (j = wpl - 1; j >= 0; j--) { 00205 word = *(lines + j); 00206 mask = *(linem + j); 00207 00208 /* OR from words below and from word to right; mask */ 00209 if (i < h - 1) { 00210 wordbelow = *(lines + wpls + j); 00211 word |= (wordbelow | (wordbelow << 1) | (wordbelow >> 1)); 00212 if (j > 0) 00213 word |= (*(lines + wpls + j - 1)) << 31; 00214 if (j < wpl - 1) 00215 word |= (*(lines + wpls + j + 1)) >> 31; 00216 } 00217 if (j < wpl - 1) { 00218 wordright = *(lines + j + 1); 00219 word |= wordright >> 31; 00220 } 00221 word &= mask; 00222 00223 /* No need to fill horizontally? */ 00224 if (!word || !(~word)) { 00225 *(lines + j) = word; 00226 continue; 00227 } 00228 00229 while (1) { 00230 wordprev = word; 00231 word = (word | (word >> 1) | (word << 1)) & mask; 00232 if ((word ^ wordprev) == 0) { 00233 *(lines + j) = word; 00234 break; 00235 } 00236 } 00237 } 00238 } 00239 break; 00240 00241 default: 00242 L_ERROR("connectivity must be 4 or 8", procName); 00243 } 00244 00245 return; 00246 } 00247 00248 00249 00250 /*-----------------------------------------------------------------------* 00251 * Vincent's Hybrid Grayscale Seedfill * 00252 *-----------------------------------------------------------------------*/ 00253 /*! 00254 * seedfillGrayLow() 00255 * 00256 * Notes: 00257 * (1) The pixels are numbered as follows: 00258 * 1 2 3 00259 * 4 x 5 00260 * 6 7 8 00261 * This low-level filling operation consists of two scans, 00262 * raster and anti-raster, covering the entire seed image. 00263 * This is followed by a breadth-first propagation operation to 00264 * complete the fill. 00265 * During the anti-raster scan, every pixel p whose current value 00266 * could still be propagated after the anti-raster scan is put into 00267 * the FIFO queue. 00268 * The propagation step is a breadth-first fill to completion. 00269 * Unlike the simple grayscale seedfill pixSeedfillGraySimple(), 00270 * where at least two full raster/anti-raster iterations are required 00271 * for completion and verification, the hybrid method uses only a 00272 * single raster/anti-raster set of scans. 00273 * (2) The filling action can be visualized from the following example. 00274 * Suppose the mask, which clips the fill, is a sombrero-shaped 00275 * surface, where the highest point is 200 and the low pixels 00276 * around the rim are 30. Beyond the rim, the mask goes up a bit. 00277 * Suppose the seed, which is filled, consists of a single point 00278 * of height 150, located below the max of the mask, with 00279 * the rest 0. Then in the raster scan, nothing happens until 00280 * the high seed point is encountered, and then this value is 00281 * propagated right and down, until it hits the side of the 00282 * sombrero. The seed can never exceed the mask, so it fills 00283 * to the rim, going lower along the mask surface. When it 00284 * passes the rim, the seed continues to fill at the rim 00285 * height to the edge of the seed image. Then on the 00286 * anti-raster scan, the seed fills flat inside the 00287 * sombrero to the upper and left, and then out from the 00288 * rim as before. The final result has a seed that is 00289 * flat outside the rim, and inside it fills the sombrero 00290 * but only up to 150. If the rim height varies, the 00291 * filled seed outside the rim will be at the highest 00292 * point on the rim, which is a saddle point on the rim. 00293 * (3) Reference paper : 00294 * L. Vincent, Morphological grayscale reconstruction in image 00295 * analysis: applications and efficient algorithms, IEEE Transactions 00296 * on Image Processing, vol. 2, no. 2, pp. 176-201, 1993. 00297 */ 00298 void 00299 seedfillGrayLow(l_uint32 *datas, 00300 l_int32 w, 00301 l_int32 h, 00302 l_int32 wpls, 00303 l_uint32 *datam, 00304 l_int32 wplm, 00305 l_int32 connectivity) 00306 { 00307 l_uint8 val1, val2, val3, val4, val5, val6, val7, val8; 00308 l_uint8 val, maxval, maskval, boolval; 00309 l_int32 i, j, imax, jmax, queue_size; 00310 l_uint32 *lines, *linem; 00311 L_PIXEL *pixel; 00312 L_QUEUE *lq_pixel; 00313 00314 PROCNAME("seedfillGrayLow"); 00315 00316 imax = h - 1; 00317 jmax = w - 1; 00318 00319 /* In the worst case, most of the pixels could be pushed 00320 * onto the FIFO queue during anti-raster scan. However this 00321 * will rarely happen, and we initialize the queue ptr size to 00322 * the image perimeter. */ 00323 lq_pixel = lqueueCreate(2 * (w + h)); 00324 00325 switch (connectivity) 00326 { 00327 case 4: 00328 /* UL --> LR scan (Raster Order) 00329 * If I : mask image 00330 * J : marker image 00331 * Let p be the currect pixel; 00332 * J(p) <- (max{J(p) union J(p) neighbors in raster order}) 00333 * intersection I(p) */ 00334 for (i = 0; i < h; i++) { 00335 lines = datas + i * wpls; 00336 linem = datam + i * wplm; 00337 for (j = 0; j < w; j++) { 00338 if ((maskval = GET_DATA_BYTE(linem, j)) > 0) { 00339 maxval = 0; 00340 if (i > 0) 00341 maxval = GET_DATA_BYTE(lines - wpls, j); 00342 if (j > 0) { 00343 val4 = GET_DATA_BYTE(lines, j - 1); 00344 maxval = L_MAX(maxval, val4); 00345 } 00346 val = GET_DATA_BYTE(lines, j); 00347 maxval = L_MAX(maxval, val); 00348 val = L_MIN(maxval, maskval); 00349 SET_DATA_BYTE(lines, j, val); 00350 } 00351 } 00352 } 00353 00354 /* LR --> UL scan (anti-raster order) 00355 * Let p be the currect pixel; 00356 * J(p) <- (max{J(p) union J(p) neighbors in anti-raster order}) 00357 * intersection I(p) */ 00358 for (i = imax; i >= 0; i--) { 00359 lines = datas + i * wpls; 00360 linem = datam + i * wplm; 00361 for (j = jmax; j >= 0; j--) { 00362 boolval = FALSE; 00363 if ((maskval = GET_DATA_BYTE(linem, j)) > 0) { 00364 maxval = 0; 00365 if (i < imax) 00366 maxval = GET_DATA_BYTE(lines + wpls, j); 00367 if (j < jmax) { 00368 val5 = GET_DATA_BYTE(lines, j + 1); 00369 maxval = L_MAX(maxval, val5); 00370 } 00371 val = GET_DATA_BYTE(lines, j); 00372 maxval = L_MAX(maxval, val); 00373 val = L_MIN(maxval, maskval); 00374 SET_DATA_BYTE(lines, j, val); 00375 00376 /* 00377 * If there exists a point (q) which belongs to J(p) 00378 * neighbors in anti-raster order such that J(q) < J(p) 00379 * and J(q) < I(q) then 00380 * fifo_add(p) */ 00381 if (i < imax) { 00382 val7 = GET_DATA_BYTE(lines + wpls, j); 00383 if ((val7 < val) && 00384 (val7 < GET_DATA_BYTE(linem + wplm, j))) { 00385 boolval = TRUE; 00386 } 00387 } 00388 if (j < jmax) { 00389 val5 = GET_DATA_BYTE(lines, j + 1); 00390 if (!boolval && (val5 < val) && 00391 (val5 < GET_DATA_BYTE(linem, j + 1))) { 00392 boolval = TRUE; 00393 } 00394 } 00395 if (boolval) { 00396 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00397 pixel->x = i; 00398 pixel->y = j; 00399 lqueueAdd(lq_pixel, pixel); 00400 } 00401 } 00402 } 00403 } 00404 00405 /* Propagation step: 00406 * while fifo_empty = false 00407 * p <- fifo_first() 00408 * for every pixel (q) belong to neighbors of (p) 00409 * if J(q) < J(p) and I(q) != J(q) 00410 * J(q) <- min(J(p), I(q)); 00411 * fifo_add(q); 00412 * end 00413 * end 00414 * end */ 00415 queue_size = lqueueGetCount(lq_pixel); 00416 while (queue_size) { 00417 pixel = (L_PIXEL *)lqueueRemove(lq_pixel); 00418 i = pixel->x; 00419 j = pixel->y; 00420 FREE(pixel); 00421 lines = datas + i * wpls; 00422 linem = datam + i * wplm; 00423 00424 if ((val = GET_DATA_BYTE(lines, j)) > 0) { 00425 if (i > 0) { 00426 val2 = GET_DATA_BYTE(lines - wpls, j); 00427 maskval = GET_DATA_BYTE(linem - wplm, j); 00428 if (val > val2 && val2 != maskval) { 00429 SET_DATA_BYTE(lines - wpls, j, L_MIN(val, maskval)); 00430 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00431 pixel->x = i - 1; 00432 pixel->y = j; 00433 lqueueAdd(lq_pixel, pixel); 00434 } 00435 00436 } 00437 if (j > 0) { 00438 val4 = GET_DATA_BYTE(lines, j - 1); 00439 maskval = GET_DATA_BYTE(linem, j - 1); 00440 if (val > val4 && val4 != maskval) { 00441 SET_DATA_BYTE(lines, j - 1, L_MIN(val, maskval)); 00442 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00443 pixel->x = i; 00444 pixel->y = j - 1; 00445 lqueueAdd(lq_pixel, pixel); 00446 } 00447 } 00448 if (i < imax) { 00449 val7 = GET_DATA_BYTE(lines + wpls, j); 00450 maskval = GET_DATA_BYTE(linem + wplm, j); 00451 if (val > val7 && val7 != maskval) { 00452 SET_DATA_BYTE(lines + wpls, j, L_MIN(val, maskval)); 00453 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00454 pixel->x = i + 1; 00455 pixel->y = j; 00456 lqueueAdd(lq_pixel, pixel); 00457 } 00458 } 00459 if (j < jmax) { 00460 val5 = GET_DATA_BYTE(lines, j + 1); 00461 maskval = GET_DATA_BYTE(linem, j + 1); 00462 if (val > val5 && val5 != maskval) { 00463 SET_DATA_BYTE(lines, j + 1, L_MIN(val, maskval)); 00464 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00465 pixel->x = i; 00466 pixel->y = j + 1; 00467 lqueueAdd(lq_pixel, pixel); 00468 } 00469 } 00470 } 00471 00472 queue_size = lqueueGetCount(lq_pixel); 00473 } 00474 00475 break; 00476 00477 case 8: 00478 /* UL --> LR scan (Raster Order) 00479 * If I : mask image 00480 * J : marker image 00481 * Let p be the currect pixel; 00482 * J(p) <- (max{J(p) union J(p) neighbors in raster order}) 00483 * intersection I(p) */ 00484 for (i = 0; i < h; i++) { 00485 lines = datas + i * wpls; 00486 linem = datam + i * wplm; 00487 for (j = 0; j < w; j++) { 00488 if ((maskval = GET_DATA_BYTE(linem, j)) > 0) { 00489 maxval = 0; 00490 if (i > 0) { 00491 if (j > 0) 00492 maxval = GET_DATA_BYTE(lines - wpls, j - 1); 00493 if (j < jmax) { 00494 val3 = GET_DATA_BYTE(lines - wpls, j + 1); 00495 maxval = L_MAX(maxval, val3); 00496 } 00497 val2 = GET_DATA_BYTE(lines - wpls, j); 00498 maxval = L_MAX(maxval, val2); 00499 } 00500 if (j > 0) { 00501 val4 = GET_DATA_BYTE(lines, j - 1); 00502 maxval = L_MAX(maxval, val4); 00503 } 00504 val = GET_DATA_BYTE(lines, j); 00505 maxval = L_MAX(maxval, val); 00506 val = L_MIN(maxval, maskval); 00507 SET_DATA_BYTE(lines, j, val); 00508 } 00509 } 00510 } 00511 00512 /* LR --> UL scan (anti-raster order) 00513 * Let p be the currect pixel; 00514 * J(p) <- (max{J(p) union J(p) neighbors in anti-raster order}) 00515 * intersection I(p) */ 00516 for (i = imax; i >= 0; i--) { 00517 lines = datas + i * wpls; 00518 linem = datam + i * wplm; 00519 for (j = jmax; j >= 0; j--) { 00520 boolval = FALSE; 00521 if ((maskval = GET_DATA_BYTE(linem, j)) > 0) { 00522 maxval = 0; 00523 if (i < imax) { 00524 if (j > 0) { 00525 maxval = GET_DATA_BYTE(lines + wpls, j - 1); 00526 } 00527 if (j < jmax) { 00528 val8 = GET_DATA_BYTE(lines + wpls, j + 1); 00529 maxval = L_MAX(maxval, val8); 00530 } 00531 val7 = GET_DATA_BYTE(lines + wpls, j); 00532 maxval = L_MAX(maxval, val7); 00533 } 00534 if (j < jmax) { 00535 val5 = GET_DATA_BYTE(lines, j + 1); 00536 maxval = L_MAX(maxval, val5); 00537 } 00538 val = GET_DATA_BYTE(lines, j); 00539 maxval = L_MAX(maxval, val); 00540 val = L_MIN(maxval, maskval); 00541 SET_DATA_BYTE(lines, j, val); 00542 00543 /* If there exists a point (q) which belongs to J(p) 00544 * neighbors in anti-raster order such that J(q) < J(p) 00545 * and J(q) < I(q) then 00546 * fifo_add(p) */ 00547 if (i < imax) { 00548 if (j > 0) { 00549 val6 = GET_DATA_BYTE(lines + wpls, j - 1); 00550 if ((val6 < val) && 00551 (val6 < GET_DATA_BYTE(linem + wplm, j - 1))) { 00552 boolval = TRUE; 00553 } 00554 } 00555 if (j < jmax) { 00556 val8 = GET_DATA_BYTE(lines + wpls, j + 1); 00557 if (!boolval && (val8 < val) && 00558 (val8 < GET_DATA_BYTE(linem + wplm, j + 1))) { 00559 boolval = TRUE; 00560 } 00561 } 00562 val7 = GET_DATA_BYTE(lines + wpls, j); 00563 if (!boolval && (val7 < val) && 00564 (val7 < GET_DATA_BYTE(linem + wplm, j))) { 00565 boolval = TRUE; 00566 } 00567 } 00568 if (j < jmax) { 00569 val5 = GET_DATA_BYTE(lines, j + 1); 00570 if (!boolval && (val5 < val) && 00571 (val5 < GET_DATA_BYTE(linem, j + 1))) { 00572 boolval = TRUE; 00573 } 00574 } 00575 if (boolval) { 00576 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00577 pixel->x = i; 00578 pixel->y = j; 00579 lqueueAdd(lq_pixel, pixel); 00580 } 00581 } 00582 } 00583 } 00584 00585 /* Propagation step: 00586 * while fifo_empty = false 00587 * p <- fifo_first() 00588 * for every pixel (q) belong to neighbors of (p) 00589 * if J(q) < J(p) and I(q) != J(q) 00590 * J(q) <- min(J(p), I(q)); 00591 * fifo_add(q); 00592 * end 00593 * end 00594 * end */ 00595 queue_size = lqueueGetCount(lq_pixel); 00596 while (queue_size) { 00597 pixel = (L_PIXEL *)lqueueRemove(lq_pixel); 00598 i = pixel->x; 00599 j = pixel->y; 00600 FREE(pixel); 00601 lines = datas + i * wpls; 00602 linem = datam + i * wplm; 00603 00604 if ((val = GET_DATA_BYTE(lines, j)) > 0) { 00605 if (i > 0) { 00606 if (j > 0) { 00607 val1 = GET_DATA_BYTE(lines - wpls, j - 1); 00608 maskval = GET_DATA_BYTE(linem - wplm, j - 1); 00609 if (val > val1 && val1 != maskval) { 00610 SET_DATA_BYTE(lines - wpls, j - 1, L_MIN(val, maskval)); 00611 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00612 pixel->x = i - 1; 00613 pixel->y = j - 1; 00614 lqueueAdd(lq_pixel, pixel); 00615 } 00616 } 00617 if (j < jmax) { 00618 val3 = GET_DATA_BYTE(lines - wpls, j + 1); 00619 maskval = GET_DATA_BYTE(linem - wplm, j + 1); 00620 if (val > val3 && val3 != maskval) { 00621 SET_DATA_BYTE(lines - wpls, j + 1, L_MIN(val, maskval)); 00622 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00623 pixel->x = i - 1; 00624 pixel->y = j + 1; 00625 lqueueAdd(lq_pixel, pixel); 00626 } 00627 } 00628 val2 = GET_DATA_BYTE(lines - wpls, j); 00629 maskval = GET_DATA_BYTE(linem - wplm, j); 00630 if (val > val2 && val2 != maskval) { 00631 SET_DATA_BYTE(lines - wpls, j, L_MIN(val, maskval)); 00632 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00633 pixel->x = i - 1; 00634 pixel->y = j; 00635 lqueueAdd(lq_pixel, pixel); 00636 } 00637 00638 } 00639 if (j > 0) { 00640 val4 = GET_DATA_BYTE(lines, j - 1); 00641 maskval = GET_DATA_BYTE(linem, j - 1); 00642 if (val > val4 && val4 != maskval) { 00643 SET_DATA_BYTE(lines, j - 1, L_MIN(val, maskval)); 00644 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00645 pixel->x = i; 00646 pixel->y = j - 1; 00647 lqueueAdd(lq_pixel, pixel); 00648 } 00649 } 00650 if (i < imax) { 00651 if (j > 0) { 00652 val6 = GET_DATA_BYTE(lines + wpls, j - 1); 00653 maskval = GET_DATA_BYTE(linem + wplm, j - 1); 00654 if (val > val6 && val6 != maskval) { 00655 SET_DATA_BYTE(lines + wpls, j - 1, L_MIN(val, maskval)); 00656 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00657 pixel->x = i + 1; 00658 pixel->y = j - 1; 00659 lqueueAdd(lq_pixel, pixel); 00660 } 00661 } 00662 if (j < jmax) { 00663 val8 = GET_DATA_BYTE(lines + wpls, j + 1); 00664 maskval = GET_DATA_BYTE(linem + wplm, j + 1); 00665 if (val > val8 && val8 != maskval) { 00666 SET_DATA_BYTE(lines + wpls, j + 1, L_MIN(val, maskval)); 00667 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00668 pixel->x = i + 1; 00669 pixel->y = j + 1; 00670 lqueueAdd(lq_pixel, pixel); 00671 } 00672 } 00673 val7 = GET_DATA_BYTE(lines + wpls, j); 00674 maskval = GET_DATA_BYTE(linem + wplm, j); 00675 if (val > val7 && val7 != maskval) { 00676 SET_DATA_BYTE(lines + wpls, j, L_MIN(val, maskval)); 00677 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00678 pixel->x = i + 1; 00679 pixel->y = j; 00680 lqueueAdd(lq_pixel, pixel); 00681 } 00682 } 00683 if (j < jmax) { 00684 val5 = GET_DATA_BYTE(lines, j + 1); 00685 maskval = GET_DATA_BYTE(linem, j + 1); 00686 if (val > val5 && val5 != maskval) { 00687 SET_DATA_BYTE(lines, j + 1, L_MIN(val, maskval)); 00688 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00689 pixel->x = i; 00690 pixel->y = j + 1; 00691 lqueueAdd(lq_pixel, pixel); 00692 } 00693 } 00694 } 00695 00696 queue_size = lqueueGetCount(lq_pixel); 00697 } 00698 break; 00699 00700 default: 00701 L_ERROR("connectivity must be 4 or 8", procName); 00702 lqueueDestroy(&lq_pixel, TRUE); 00703 } 00704 00705 lqueueDestroy(&lq_pixel, TRUE); 00706 return; 00707 } 00708 00709 00710 /*! 00711 * seedfillGrayInvLow() 00712 * 00713 * Notes: 00714 * (1) The pixels are numbered as follows: 00715 * 1 2 3 00716 * 4 x 5 00717 * 6 7 8 00718 * This low-level filling operation consists of two scans, 00719 * raster and anti-raster, covering the entire seed image. 00720 * During the anti-raster scan, every pixel p such that its 00721 * current value could still be propogated during the next 00722 * raster scanning is put into the FIFO-queue. 00723 * Next step is the propagation step where where we update 00724 * and propagate the values using FIFO structure created in 00725 * anti-raster scan. 00726 * (2) The "Inv" signifies the fact that in this case, filling 00727 * of the seed only takes place when the seed value is 00728 * greater than the mask value. The mask will act to stop 00729 * the fill when it is higher than the seed level. (This is 00730 * in contrast to conventional grayscale filling where the 00731 * seed always fills below the mask.) 00732 * (3) An example of use is a basin, described by the mask (pixm), 00733 * where within the basin, the seed pix (pixs) gets filled to the 00734 * height of the highest seed pixel that is above its 00735 * corresponding max pixel. Filling occurs while the 00736 * propagating seed pixels in pixs are larger than the 00737 * corresponding mask values in pixm. 00738 * (4) Reference paper : 00739 * L. Vincent, Morphological grayscale reconstruction in image 00740 * analysis: applications and efficient algorithms, IEEE Transactions 00741 * on Image Processing, vol. 2, no. 2, pp. 176-201, 1993. 00742 */ 00743 void 00744 seedfillGrayInvLow(l_uint32 *datas, 00745 l_int32 w, 00746 l_int32 h, 00747 l_int32 wpls, 00748 l_uint32 *datam, 00749 l_int32 wplm, 00750 l_int32 connectivity) 00751 { 00752 l_uint8 val1, val2, val3, val4, val5, val6, val7, val8; 00753 l_uint8 val, maxval, maskval, boolval; 00754 l_int32 i, j, imax, jmax, queue_size; 00755 l_uint32 *lines, *linem; 00756 L_PIXEL *pixel; 00757 L_QUEUE *lq_pixel; 00758 00759 PROCNAME("seedfillGrayInvLow"); 00760 00761 imax = h - 1; 00762 jmax = w - 1; 00763 00764 /* In the worst case, most of the pixels could be pushed 00765 * onto the FIFO queue during anti-raster scan. However this 00766 * will rarely happen, and we initialize the queue ptr size to 00767 * the image perimeter. */ 00768 lq_pixel = lqueueCreate(2 * (w + h)); 00769 00770 switch (connectivity) 00771 { 00772 case 4: 00773 /* UL --> LR scan (Raster Order) 00774 * If I : mask image 00775 * J : marker image 00776 * Let p be the currect pixel; 00777 * tmp <- max{J(p) union J(p) neighbors in raster order} 00778 * if (tmp > I(p)) 00779 * J(p) <- tmp 00780 * end */ 00781 for (i = 0; i < h; i++) { 00782 lines = datas + i * wpls; 00783 linem = datam + i * wplm; 00784 for (j = 0; j < w; j++) { 00785 if ((maskval = GET_DATA_BYTE(linem, j)) < 255) { 00786 maxval = GET_DATA_BYTE(lines, j); 00787 if (i > 0) { 00788 val2 = GET_DATA_BYTE(lines - wpls, j); 00789 maxval = L_MAX(maxval, val2); 00790 } 00791 if (j > 0) { 00792 val4 = GET_DATA_BYTE(lines, j - 1); 00793 maxval = L_MAX(maxval, val4); 00794 } 00795 if (maxval > maskval) 00796 SET_DATA_BYTE(lines, j, maxval); 00797 } 00798 } 00799 } 00800 00801 /* LR --> UL scan (anti-raster order) 00802 * If I : mask image 00803 * J : marker image 00804 * Let p be the currect pixel; 00805 * tmp <- max{J(p) union J(p) neighbors in anti-raster order} 00806 * if (tmp > I(p)) 00807 * J(p) <- tmp 00808 * end */ 00809 for (i = imax; i >= 0; i--) { 00810 lines = datas + i * wpls; 00811 linem = datam + i * wplm; 00812 for (j = jmax; j >= 0; j--) { 00813 boolval = FALSE; 00814 if ((maskval = GET_DATA_BYTE(linem, j)) < 255) { 00815 val = maxval = GET_DATA_BYTE(lines, j); 00816 if (i < imax) { 00817 val7 = GET_DATA_BYTE(lines + wpls, j); 00818 maxval = L_MAX(maxval, val7); 00819 } 00820 if (j < jmax) { 00821 val5 = GET_DATA_BYTE(lines, j + 1); 00822 maxval = L_MAX(maxval, val5); 00823 } 00824 if (maxval > maskval) 00825 SET_DATA_BYTE(lines, j, maxval); 00826 val = GET_DATA_BYTE(lines, j); 00827 00828 /* 00829 * If there exists a point (q) which belongs to J(p) 00830 * neighbors in anti-raster order such that J(q) < J(p) 00831 * and J(p) > I(q) then 00832 * fifo_add(p) */ 00833 if (i < imax) { 00834 val7 = GET_DATA_BYTE(lines + wpls, j); 00835 if ((val7 < val) && 00836 (val > GET_DATA_BYTE(linem + wplm, j))) { 00837 boolval = TRUE; 00838 } 00839 } 00840 if (j < jmax) { 00841 val5 = GET_DATA_BYTE(lines, j + 1); 00842 if (!boolval && (val5 < val) && 00843 (val > GET_DATA_BYTE(linem, j + 1))) { 00844 boolval = TRUE; 00845 } 00846 } 00847 if (boolval) { 00848 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00849 pixel->x = i; 00850 pixel->y = j; 00851 lqueueAdd(lq_pixel, pixel); 00852 } 00853 } 00854 } 00855 } 00856 00857 /* Propagation step: 00858 * while fifo_empty = false 00859 * p <- fifo_first() 00860 * for every pixel (q) belong to neighbors of (p) 00861 * if J(q) < J(p) and J(p) > I(q) 00862 * J(q) <- min(J(p), I(q)); 00863 * fifo_add(q); 00864 * end 00865 * end 00866 * end */ 00867 queue_size = lqueueGetCount(lq_pixel); 00868 while (queue_size) { 00869 pixel = (L_PIXEL *)lqueueRemove(lq_pixel); 00870 i = pixel->x; 00871 j = pixel->y; 00872 FREE(pixel); 00873 lines = datas + i * wpls; 00874 linem = datam + i * wplm; 00875 00876 if ((val = GET_DATA_BYTE(lines, j)) > 0) { 00877 if (i > 0) { 00878 val2 = GET_DATA_BYTE(lines - wpls, j); 00879 maskval = GET_DATA_BYTE(linem - wplm, j); 00880 if (val > val2 && val > maskval) { 00881 SET_DATA_BYTE(lines - wpls, j, val); 00882 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00883 pixel->x = i - 1; 00884 pixel->y = j; 00885 lqueueAdd(lq_pixel, pixel); 00886 } 00887 00888 } 00889 if (j > 0) { 00890 val4 = GET_DATA_BYTE(lines, j - 1); 00891 maskval = GET_DATA_BYTE(linem, j - 1); 00892 if (val > val4 && val > maskval) { 00893 SET_DATA_BYTE(lines, j - 1, val); 00894 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00895 pixel->x = i; 00896 pixel->y = j - 1; 00897 lqueueAdd(lq_pixel, pixel); 00898 } 00899 } 00900 if (i < imax) { 00901 val7 = GET_DATA_BYTE(lines + wpls, j); 00902 maskval = GET_DATA_BYTE(linem + wplm, j); 00903 if (val > val7 && val > maskval) { 00904 SET_DATA_BYTE(lines + wpls, j, val); 00905 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00906 pixel->x = i + 1; 00907 pixel->y = j; 00908 lqueueAdd(lq_pixel, pixel); 00909 } 00910 } 00911 if (j < jmax) { 00912 val5 = GET_DATA_BYTE(lines, j + 1); 00913 maskval = GET_DATA_BYTE(linem, j + 1); 00914 if (val > val5 && val > maskval) { 00915 SET_DATA_BYTE(lines, j + 1, val); 00916 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 00917 pixel->x = i; 00918 pixel->y = j + 1; 00919 lqueueAdd(lq_pixel, pixel); 00920 } 00921 } 00922 } 00923 00924 queue_size = lqueueGetCount(lq_pixel); 00925 } 00926 00927 break; 00928 00929 case 8: 00930 /* UL --> LR scan (Raster Order) 00931 * If I : mask image 00932 * J : marker image 00933 * Let p be the currect pixel; 00934 * tmp <- max{J(p) union J(p) neighbors in raster order} 00935 * if (tmp > I(p)) 00936 * J(p) <- tmp 00937 * end */ 00938 for (i = 0; i < h; i++) { 00939 lines = datas + i * wpls; 00940 linem = datam + i * wplm; 00941 for (j = 0; j < w; j++) { 00942 if ((maskval = GET_DATA_BYTE(linem, j)) < 255) { 00943 maxval = GET_DATA_BYTE(lines, j); 00944 if (i > 0) { 00945 if (j > 0) { 00946 val1 = GET_DATA_BYTE(lines - wpls, j - 1); 00947 maxval = L_MAX(maxval, val1); 00948 } 00949 if (j < jmax) { 00950 val3 = GET_DATA_BYTE(lines - wpls, j + 1); 00951 maxval = L_MAX(maxval, val3); 00952 } 00953 val2 = GET_DATA_BYTE(lines - wpls, j); 00954 maxval = L_MAX(maxval, val2); 00955 } 00956 if (j > 0) { 00957 val4 = GET_DATA_BYTE(lines, j - 1); 00958 maxval = L_MAX(maxval, val4); 00959 } 00960 if (maxval > maskval) 00961 SET_DATA_BYTE(lines, j, maxval); 00962 } 00963 } 00964 } 00965 00966 /* LR --> UL scan (anti-raster order) 00967 * If I : mask image 00968 * J : marker image 00969 * Let p be the currect pixel; 00970 * tmp <- max{J(p) union J(p) neighbors in anti-raster order} 00971 * if (tmp > I(p)) 00972 * J(p) <- tmp 00973 * end */ 00974 for (i = imax; i >= 0; i--) { 00975 lines = datas + i * wpls; 00976 linem = datam + i * wplm; 00977 for (j = jmax; j >= 0; j--) { 00978 boolval = FALSE; 00979 if ((maskval = GET_DATA_BYTE(linem, j)) < 255) { 00980 maxval = GET_DATA_BYTE(lines, j); 00981 if (i < imax) { 00982 if (j > 0) { 00983 val6 = GET_DATA_BYTE(lines + wpls, j - 1); 00984 maxval = L_MAX(maxval, val6); 00985 } 00986 if (j < jmax) { 00987 val8 = GET_DATA_BYTE(lines + wpls, j + 1); 00988 maxval = L_MAX(maxval, val8); 00989 } 00990 val7 = GET_DATA_BYTE(lines + wpls, j); 00991 maxval = L_MAX(maxval, val7); 00992 } 00993 if (j < jmax) { 00994 val5 = GET_DATA_BYTE(lines, j + 1); 00995 maxval = L_MAX(maxval, val5); 00996 } 00997 if (maxval > maskval) 00998 SET_DATA_BYTE(lines, j, maxval); 00999 val = GET_DATA_BYTE(lines, j); 01000 01001 /* 01002 * If there exists a point (q) which belongs to J(p) 01003 * neighbors in anti-raster order such that J(q) < J(p) 01004 * and J(p) > I(q) then 01005 * fifo_add(p) */ 01006 if (i < imax) { 01007 if (j > 0) { 01008 val6 = GET_DATA_BYTE(lines + wpls, j - 1); 01009 if ((val6 < val) && 01010 (val > GET_DATA_BYTE(linem + wplm, j - 1))) { 01011 boolval = TRUE; 01012 } 01013 } 01014 if (j < jmax) { 01015 val8 = GET_DATA_BYTE(lines + wpls, j + 1); 01016 if (!boolval && (val8 < val) && 01017 (val > GET_DATA_BYTE(linem + wplm, j + 1))) { 01018 boolval = TRUE; 01019 } 01020 } 01021 val7 = GET_DATA_BYTE(lines + wpls, j); 01022 if (!boolval && (val7 < val) && 01023 (val > GET_DATA_BYTE(linem + wplm, j))) { 01024 boolval = TRUE; 01025 } 01026 } 01027 if (j < jmax) { 01028 val5 = GET_DATA_BYTE(lines, j + 1); 01029 if (!boolval && (val5 < val) && 01030 (val > GET_DATA_BYTE(linem, j + 1))) { 01031 boolval = TRUE; 01032 } 01033 } 01034 if (boolval) { 01035 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 01036 pixel->x = i; 01037 pixel->y = j; 01038 lqueueAdd(lq_pixel, pixel); 01039 } 01040 } 01041 } 01042 } 01043 01044 /* Propagation step: 01045 * while fifo_empty = false 01046 * p <- fifo_first() 01047 * for every pixel (q) belong to neighbors of (p) 01048 * if J(q) < J(p) and J(p) > I(q) 01049 * J(q) <- min(J(p), I(q)); 01050 * fifo_add(q); 01051 * end 01052 * end 01053 * end */ 01054 queue_size = lqueueGetCount(lq_pixel); 01055 while (queue_size) { 01056 pixel = (L_PIXEL *)lqueueRemove(lq_pixel); 01057 i = pixel->x; 01058 j = pixel->y; 01059 FREE(pixel); 01060 lines = datas + i * wpls; 01061 linem = datam + i * wplm; 01062 01063 if ((val = GET_DATA_BYTE(lines, j)) > 0) { 01064 if (i > 0) { 01065 if (j > 0) { 01066 val1 = GET_DATA_BYTE(lines - wpls, j - 1); 01067 maskval = GET_DATA_BYTE(linem - wplm, j - 1); 01068 if (val > val1 && val > maskval) { 01069 SET_DATA_BYTE(lines - wpls, j - 1, val); 01070 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 01071 pixel->x = i - 1; 01072 pixel->y = j - 1; 01073 lqueueAdd(lq_pixel, pixel); 01074 } 01075 } 01076 if (j < jmax) { 01077 val3 = GET_DATA_BYTE(lines - wpls, j + 1); 01078 maskval = GET_DATA_BYTE(linem - wplm, j + 1); 01079 if (val > val3 && val > maskval) { 01080 SET_DATA_BYTE(lines - wpls, j + 1, val); 01081 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 01082 pixel->x = i - 1; 01083 pixel->y = j + 1; 01084 lqueueAdd(lq_pixel, pixel); 01085 } 01086 } 01087 val2 = GET_DATA_BYTE(lines - wpls, j); 01088 maskval = GET_DATA_BYTE(linem - wplm, j); 01089 if (val > val2 && val > maskval) { 01090 SET_DATA_BYTE(lines - wpls, j, val); 01091 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 01092 pixel->x = i - 1; 01093 pixel->y = j; 01094 lqueueAdd(lq_pixel, pixel); 01095 } 01096 01097 } 01098 if (j > 0) { 01099 val4 = GET_DATA_BYTE(lines, j - 1); 01100 maskval = GET_DATA_BYTE(linem, j - 1); 01101 if (val > val4 && val > maskval) { 01102 SET_DATA_BYTE(lines, j - 1, val); 01103 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 01104 pixel->x = i; 01105 pixel->y = j - 1; 01106 lqueueAdd(lq_pixel, pixel); 01107 } 01108 } 01109 if (i < imax) { 01110 if (j > 0) { 01111 val6 = GET_DATA_BYTE(lines + wpls, j - 1); 01112 maskval = GET_DATA_BYTE(linem + wplm, j - 1); 01113 if (val > val6 && val > maskval) { 01114 SET_DATA_BYTE(lines + wpls, j - 1, val); 01115 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 01116 pixel->x = i + 1; 01117 pixel->y = j - 1; 01118 lqueueAdd(lq_pixel, pixel); 01119 } 01120 } 01121 if (j < jmax) { 01122 val8 = GET_DATA_BYTE(lines + wpls, j + 1); 01123 maskval = GET_DATA_BYTE(linem + wplm, j + 1); 01124 if (val > val8 && val > maskval) { 01125 SET_DATA_BYTE(lines + wpls, j + 1, val); 01126 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 01127 pixel->x = i + 1; 01128 pixel->y = j + 1; 01129 lqueueAdd(lq_pixel, pixel); 01130 } 01131 } 01132 val7 = GET_DATA_BYTE(lines + wpls, j); 01133 maskval = GET_DATA_BYTE(linem + wplm, j); 01134 if (val > val7 && val > maskval) { 01135 SET_DATA_BYTE(lines + wpls, j, val); 01136 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 01137 pixel->x = i + 1; 01138 pixel->y = j; 01139 lqueueAdd(lq_pixel, pixel); 01140 } 01141 } 01142 if (j < jmax) { 01143 val5 = GET_DATA_BYTE(lines, j + 1); 01144 maskval = GET_DATA_BYTE(linem, j + 1); 01145 if (val > val5 && val > maskval) { 01146 SET_DATA_BYTE(lines, j + 1, val); 01147 pixel = (L_PIXEL *)CALLOC(1, sizeof(L_PIXEL)); 01148 pixel->x = i; 01149 pixel->y = j + 1; 01150 lqueueAdd(lq_pixel, pixel); 01151 } 01152 } 01153 } 01154 01155 queue_size = lqueueGetCount(lq_pixel); 01156 } 01157 break; 01158 01159 default: 01160 lqueueDestroy(&lq_pixel, TRUE); 01161 L_ERROR("connectivity must be 4 or 8", procName); 01162 } 01163 01164 lqueueDestroy(&lq_pixel, TRUE); 01165 return; 01166 } 01167 01168 /*-----------------------------------------------------------------------* 01169 * Vincent's Iterative Grayscale Seedfill * 01170 *-----------------------------------------------------------------------*/ 01171 /*! 01172 * seedfillGrayLowSimple() 01173 * 01174 * Notes: 01175 * (1) The pixels are numbered as follows: 01176 * 1 2 3 01177 * 4 x 5 01178 * 6 7 8 01179 * This low-level filling operation consists of two scans, 01180 * raster and anti-raster, covering the entire seed image. 01181 * The caller typically iterates until the filling is 01182 * complete. 01183 * (2) The filling action can be visualized from the following example. 01184 * Suppose the mask, which clips the fill, is a sombrero-shaped 01185 * surface, where the highest point is 200 and the low pixels 01186 * around the rim are 30. Beyond the rim, the mask goes up a bit. 01187 * Suppose the seed, which is filled, consists of a single point 01188 * of height 150, located below the max of the mask, with 01189 * the rest 0. Then in the raster scan, nothing happens until 01190 * the high seed point is encountered, and then this value is 01191 * propagated right and down, until it hits the side of the 01192 * sombrero. The seed can never exceed the mask, so it fills 01193 * to the rim, going lower along the mask surface. When it 01194 * passes the rim, the seed continues to fill at the rim 01195 * height to the edge of the seed image. Then on the 01196 * anti-raster scan, the seed fills flat inside the 01197 * sombrero to the upper and left, and then out from the 01198 * rim as before. The final result has a seed that is 01199 * flat outside the rim, and inside it fills the sombrero 01200 * but only up to 150. If the rim height varies, the 01201 * filled seed outside the rim will be at the highest 01202 * point on the rim, which is a saddle point on the rim. 01203 */ 01204 void 01205 seedfillGrayLowSimple(l_uint32 *datas, 01206 l_int32 w, 01207 l_int32 h, 01208 l_int32 wpls, 01209 l_uint32 *datam, 01210 l_int32 wplm, 01211 l_int32 connectivity) 01212 { 01213 l_uint8 val2, val3, val4, val5, val7, val8; 01214 l_uint8 val, maxval, maskval; 01215 l_int32 i, j, imax, jmax; 01216 l_uint32 *lines, *linem; 01217 01218 PROCNAME("seedfillGrayLowSimple"); 01219 01220 imax = h - 1; 01221 jmax = w - 1; 01222 01223 switch (connectivity) 01224 { 01225 case 4: 01226 /* UL --> LR scan */ 01227 for (i = 0; i < h; i++) { 01228 lines = datas + i * wpls; 01229 linem = datam + i * wplm; 01230 for (j = 0; j < w; j++) { 01231 if ((maskval = GET_DATA_BYTE(linem, j)) > 0) { 01232 maxval = 0; 01233 if (i > 0) 01234 maxval = GET_DATA_BYTE(lines - wpls, j); 01235 if (j > 0) { 01236 val4 = GET_DATA_BYTE(lines, j - 1); 01237 maxval = L_MAX(maxval, val4); 01238 } 01239 val = GET_DATA_BYTE(lines, j); 01240 maxval = L_MAX(maxval, val); 01241 val = L_MIN(maxval, maskval); 01242 SET_DATA_BYTE(lines, j, val); 01243 } 01244 } 01245 } 01246 01247 /* LR --> UL scan */ 01248 for (i = imax; i >= 0; i--) { 01249 lines = datas + i * wpls; 01250 linem = datam + i * wplm; 01251 for (j = jmax; j >= 0; j--) { 01252 if ((maskval = GET_DATA_BYTE(linem, j)) > 0) { 01253 maxval = 0; 01254 if (i < imax) 01255 maxval = GET_DATA_BYTE(lines + wpls, j); 01256 if (j < jmax) { 01257 val5 = GET_DATA_BYTE(lines, j + 1); 01258 maxval = L_MAX(maxval, val5); 01259 } 01260 val = GET_DATA_BYTE(lines, j); 01261 maxval = L_MAX(maxval, val); 01262 val = L_MIN(maxval, maskval); 01263 SET_DATA_BYTE(lines, j, val); 01264 } 01265 } 01266 } 01267 break; 01268 01269 case 8: 01270 /* UL --> LR scan */ 01271 for (i = 0; i < h; i++) { 01272 lines = datas + i * wpls; 01273 linem = datam + i * wplm; 01274 for (j = 0; j < w; j++) { 01275 if ((maskval = GET_DATA_BYTE(linem, j)) > 0) { 01276 maxval = 0; 01277 if (i > 0) { 01278 if (j > 0) 01279 maxval = GET_DATA_BYTE(lines - wpls, j - 1); 01280 if (j < jmax) { 01281 val2 = GET_DATA_BYTE(lines - wpls, j + 1); 01282 maxval = L_MAX(maxval, val2); 01283 } 01284 val3 = GET_DATA_BYTE(lines - wpls, j); 01285 maxval = L_MAX(maxval, val3); 01286 } 01287 if (j > 0) { 01288 val4 = GET_DATA_BYTE(lines, j - 1); 01289 maxval = L_MAX(maxval, val4); 01290 } 01291 val = GET_DATA_BYTE(lines, j); 01292 maxval = L_MAX(maxval, val); 01293 val = L_MIN(maxval, maskval); 01294 SET_DATA_BYTE(lines, j, val); 01295 } 01296 } 01297 } 01298 01299 /* LR --> UL scan */ 01300 for (i = imax; i >= 0; i--) { 01301 lines = datas + i * wpls; 01302 linem = datam + i * wplm; 01303 for (j = jmax; j >= 0; j--) { 01304 if ((maskval = GET_DATA_BYTE(linem, j)) > 0) { 01305 maxval = 0; 01306 if (i < imax) { 01307 if (j > 0) 01308 maxval = GET_DATA_BYTE(lines + wpls, j - 1); 01309 if (j < jmax) { 01310 val8 = GET_DATA_BYTE(lines + wpls, j + 1); 01311 maxval = L_MAX(maxval, val8); 01312 } 01313 val7 = GET_DATA_BYTE(lines + wpls, j); 01314 maxval = L_MAX(maxval, val7); 01315 } 01316 if (j < jmax) { 01317 val5 = GET_DATA_BYTE(lines, j + 1); 01318 maxval = L_MAX(maxval, val5); 01319 } 01320 val = GET_DATA_BYTE(lines, j); 01321 maxval = L_MAX(maxval, val); 01322 val = L_MIN(maxval, maskval); 01323 SET_DATA_BYTE(lines, j, val); 01324 } 01325 } 01326 } 01327 break; 01328 01329 default: 01330 L_ERROR("connectivity must be 4 or 8", procName); 01331 } 01332 01333 return; 01334 } 01335 01336 01337 /*! 01338 * seedfillGrayInvLowSimple() 01339 * 01340 * Notes: 01341 * (1) The pixels are numbered as follows: 01342 * 1 2 3 01343 * 4 x 5 01344 * 6 7 8 01345 * This low-level filling operation consists of two scans, 01346 * raster and anti-raster, covering the entire seed image. 01347 * The caller typically iterates until the filling is 01348 * complete. 01349 * (2) The "Inv" signifies the fact that in this case, filling 01350 * of the seed only takes place when the seed value is 01351 * greater than the mask value. The mask will act to stop 01352 * the fill when it is higher than the seed level. (This is 01353 * in contrast to conventional grayscale filling where the 01354 * seed always fills below the mask.) 01355 * (3) An example of use is a basin, described by the mask (pixm), 01356 * where within the basin, the seed pix (pixs) gets filled to the 01357 * height of the highest seed pixel that is above its 01358 * corresponding max pixel. Filling occurs while the 01359 * propagating seed pixels in pixs are larger than the 01360 * corresponding mask values in pixm. 01361 */ 01362 void 01363 seedfillGrayInvLowSimple(l_uint32 *datas, 01364 l_int32 w, 01365 l_int32 h, 01366 l_int32 wpls, 01367 l_uint32 *datam, 01368 l_int32 wplm, 01369 l_int32 connectivity) 01370 { 01371 l_uint8 val1, val2, val3, val4, val5, val6, val7, val8; 01372 l_uint8 maxval, maskval; 01373 l_int32 i, j, imax, jmax; 01374 l_uint32 *lines, *linem; 01375 01376 PROCNAME("seedfillGrayInvLowSimple"); 01377 01378 imax = h - 1; 01379 jmax = w - 1; 01380 01381 switch (connectivity) 01382 { 01383 case 4: 01384 /* UL --> LR scan */ 01385 for (i = 0; i < h; i++) { 01386 lines = datas + i * wpls; 01387 linem = datam + i * wplm; 01388 for (j = 0; j < w; j++) { 01389 if ((maskval = GET_DATA_BYTE(linem, j)) < 255) { 01390 maxval = GET_DATA_BYTE(lines, j); 01391 if (i > 0) { 01392 val2 = GET_DATA_BYTE(lines - wpls, j); 01393 maxval = L_MAX(maxval, val2); 01394 } 01395 if (j > 0) { 01396 val4 = GET_DATA_BYTE(lines, j - 1); 01397 maxval = L_MAX(maxval, val4); 01398 } 01399 if (maxval > maskval) 01400 SET_DATA_BYTE(lines, j, maxval); 01401 } 01402 } 01403 } 01404 01405 /* LR --> UL scan */ 01406 for (i = imax; i >= 0; i--) { 01407 lines = datas + i * wpls; 01408 linem = datam + i * wplm; 01409 for (j = jmax; j >= 0; j--) { 01410 if ((maskval = GET_DATA_BYTE(linem, j)) < 255) { 01411 maxval = GET_DATA_BYTE(lines, j); 01412 if (i < imax) { 01413 val7 = GET_DATA_BYTE(lines + wpls, j); 01414 maxval = L_MAX(maxval, val7); 01415 } 01416 if (j < jmax) { 01417 val5 = GET_DATA_BYTE(lines, j + 1); 01418 maxval = L_MAX(maxval, val5); 01419 } 01420 if (maxval > maskval) 01421 SET_DATA_BYTE(lines, j, maxval); 01422 } 01423 } 01424 } 01425 break; 01426 01427 case 8: 01428 /* UL --> LR scan */ 01429 for (i = 0; i < h; i++) { 01430 lines = datas + i * wpls; 01431 linem = datam + i * wplm; 01432 for (j = 0; j < w; j++) { 01433 if ((maskval = GET_DATA_BYTE(linem, j)) < 255) { 01434 maxval = GET_DATA_BYTE(lines, j); 01435 if (i > 0) { 01436 if (j > 0) { 01437 val1 = GET_DATA_BYTE(lines - wpls, j - 1); 01438 maxval = L_MAX(maxval, val1); 01439 } 01440 if (j < jmax) { 01441 val2 = GET_DATA_BYTE(lines - wpls, j + 1); 01442 maxval = L_MAX(maxval, val2); 01443 } 01444 val3 = GET_DATA_BYTE(lines - wpls, j); 01445 maxval = L_MAX(maxval, val3); 01446 } 01447 if (j > 0) { 01448 val4 = GET_DATA_BYTE(lines, j - 1); 01449 maxval = L_MAX(maxval, val4); 01450 } 01451 if (maxval > maskval) 01452 SET_DATA_BYTE(lines, j, maxval); 01453 } 01454 } 01455 } 01456 01457 /* LR --> UL scan */ 01458 for (i = imax; i >= 0; i--) { 01459 lines = datas + i * wpls; 01460 linem = datam + i * wplm; 01461 for (j = jmax; j >= 0; j--) { 01462 if ((maskval = GET_DATA_BYTE(linem, j)) < 255) { 01463 maxval = GET_DATA_BYTE(lines, j); 01464 if (i < imax) { 01465 if (j > 0) { 01466 val6 = GET_DATA_BYTE(lines + wpls, j - 1); 01467 maxval = L_MAX(maxval, val6); 01468 } 01469 if (j < jmax) { 01470 val8 = GET_DATA_BYTE(lines + wpls, j + 1); 01471 maxval = L_MAX(maxval, val8); 01472 } 01473 val7 = GET_DATA_BYTE(lines + wpls, j); 01474 maxval = L_MAX(maxval, val7); 01475 } 01476 if (j < jmax) { 01477 val5 = GET_DATA_BYTE(lines, j + 1); 01478 maxval = L_MAX(maxval, val5); 01479 } 01480 if (maxval > maskval) 01481 SET_DATA_BYTE(lines, j, maxval); 01482 } 01483 } 01484 } 01485 break; 01486 01487 default: 01488 L_ERROR("connectivity must be 4 or 8", procName); 01489 } 01490 01491 return; 01492 } 01493 01494 01495 /*-----------------------------------------------------------------------* 01496 * Vincent's Distance Function method * 01497 *-----------------------------------------------------------------------*/ 01498 /*! 01499 * distanceFunctionLow() 01500 */ 01501 void 01502 distanceFunctionLow(l_uint32 *datad, 01503 l_int32 w, 01504 l_int32 h, 01505 l_int32 d, 01506 l_int32 wpld, 01507 l_int32 connectivity) 01508 { 01509 l_int32 val1, val2, val3, val4, val5, val6, val7, val8, minval, val; 01510 l_int32 i, j, imax, jmax; 01511 l_uint32 *lined; 01512 01513 PROCNAME("distanceFunctionLow"); 01514 01515 /* One raster scan followed by one anti-raster scan. 01516 * This does not re-set the 1-boundary of pixels that 01517 * were initialized to either 0 or maxval. */ 01518 imax = h - 1; 01519 jmax = w - 1; 01520 switch (connectivity) 01521 { 01522 case 4: 01523 if (d == 8) { 01524 /* UL --> LR scan */ 01525 for (i = 1; i < imax; i++) { 01526 lined = datad + i * wpld; 01527 for (j = 1; j < jmax; j++) { 01528 if ((val = GET_DATA_BYTE(lined, j)) > 0) { 01529 val2 = GET_DATA_BYTE(lined - wpld, j); 01530 val4 = GET_DATA_BYTE(lined, j - 1); 01531 minval = L_MIN(val2, val4); 01532 minval = L_MIN(minval, 254); 01533 SET_DATA_BYTE(lined, j, minval + 1); 01534 } 01535 } 01536 } 01537 01538 /* LR --> UL scan */ 01539 for (i = imax - 1; i > 0; i--) { 01540 lined = datad + i * wpld; 01541 for (j = jmax - 1; j > 0; j--) { 01542 if ((val = GET_DATA_BYTE(lined, j)) > 0) { 01543 val7 = GET_DATA_BYTE(lined + wpld, j); 01544 val5 = GET_DATA_BYTE(lined, j + 1); 01545 minval = L_MIN(val5, val7); 01546 minval = L_MIN(minval + 1, val); 01547 SET_DATA_BYTE(lined, j, minval); 01548 } 01549 } 01550 } 01551 } 01552 else { /* d == 16 */ 01553 /* UL --> LR scan */ 01554 for (i = 1; i < imax; i++) { 01555 lined = datad + i * wpld; 01556 for (j = 1; j < jmax; j++) { 01557 if ((val = GET_DATA_TWO_BYTES(lined, j)) > 0) { 01558 val2 = GET_DATA_TWO_BYTES(lined - wpld, j); 01559 val4 = GET_DATA_TWO_BYTES(lined, j - 1); 01560 minval = L_MIN(val2, val4); 01561 minval = L_MIN(minval, 0xfffe); 01562 SET_DATA_TWO_BYTES(lined, j, minval + 1); 01563 } 01564 } 01565 } 01566 01567 /* LR --> UL scan */ 01568 for (i = imax - 1; i > 0; i--) { 01569 lined = datad + i * wpld; 01570 for (j = jmax - 1; j > 0; j--) { 01571 if ((val = GET_DATA_TWO_BYTES(lined, j)) > 0) { 01572 val7 = GET_DATA_TWO_BYTES(lined + wpld, j); 01573 val5 = GET_DATA_TWO_BYTES(lined, j + 1); 01574 minval = L_MIN(val5, val7); 01575 minval = L_MIN(minval + 1, val); 01576 SET_DATA_TWO_BYTES(lined, j, minval); 01577 } 01578 } 01579 } 01580 } 01581 break; 01582 01583 case 8: 01584 if (d == 8) { 01585 /* UL --> LR scan */ 01586 for (i = 1; i < imax; i++) { 01587 lined = datad + i * wpld; 01588 for (j = 1; j < jmax; j++) { 01589 if ((val = GET_DATA_BYTE(lined, j)) > 0) { 01590 val1 = GET_DATA_BYTE(lined - wpld, j - 1); 01591 val2 = GET_DATA_BYTE(lined - wpld, j); 01592 val3 = GET_DATA_BYTE(lined - wpld, j + 1); 01593 val4 = GET_DATA_BYTE(lined, j - 1); 01594 minval = L_MIN(val1, val2); 01595 minval = L_MIN(minval, val3); 01596 minval = L_MIN(minval, val4); 01597 minval = L_MIN(minval, 254); 01598 SET_DATA_BYTE(lined, j, minval + 1); 01599 } 01600 } 01601 } 01602 01603 /* LR --> UL scan */ 01604 for (i = imax - 1; i > 0; i--) { 01605 lined = datad + i * wpld; 01606 for (j = jmax - 1; j > 0; j--) { 01607 if ((val = GET_DATA_BYTE(lined, j)) > 0) { 01608 val8 = GET_DATA_BYTE(lined + wpld, j + 1); 01609 val7 = GET_DATA_BYTE(lined + wpld, j); 01610 val6 = GET_DATA_BYTE(lined + wpld, j - 1); 01611 val5 = GET_DATA_BYTE(lined, j + 1); 01612 minval = L_MIN(val8, val7); 01613 minval = L_MIN(minval, val6); 01614 minval = L_MIN(minval, val5); 01615 minval = L_MIN(minval + 1, val); 01616 SET_DATA_BYTE(lined, j, minval); 01617 } 01618 } 01619 } 01620 } 01621 else { /* d == 16 */ 01622 /* UL --> LR scan */ 01623 for (i = 1; i < imax; i++) { 01624 lined = datad + i * wpld; 01625 for (j = 1; j < jmax; j++) { 01626 if ((val = GET_DATA_TWO_BYTES(lined, j)) > 0) { 01627 val1 = GET_DATA_TWO_BYTES(lined - wpld, j - 1); 01628 val2 = GET_DATA_TWO_BYTES(lined - wpld, j); 01629 val3 = GET_DATA_TWO_BYTES(lined - wpld, j + 1); 01630 val4 = GET_DATA_TWO_BYTES(lined, j - 1); 01631 minval = L_MIN(val1, val2); 01632 minval = L_MIN(minval, val3); 01633 minval = L_MIN(minval, val4); 01634 minval = L_MIN(minval, 0xfffe); 01635 SET_DATA_TWO_BYTES(lined, j, minval + 1); 01636 } 01637 } 01638 } 01639 01640 /* LR --> UL scan */ 01641 for (i = imax - 1; i > 0; i--) { 01642 lined = datad + i * wpld; 01643 for (j = jmax - 1; j > 0; j--) { 01644 if ((val = GET_DATA_TWO_BYTES(lined, j)) > 0) { 01645 val8 = GET_DATA_TWO_BYTES(lined + wpld, j + 1); 01646 val7 = GET_DATA_TWO_BYTES(lined + wpld, j); 01647 val6 = GET_DATA_TWO_BYTES(lined + wpld, j - 1); 01648 val5 = GET_DATA_TWO_BYTES(lined, j + 1); 01649 minval = L_MIN(val8, val7); 01650 minval = L_MIN(minval, val6); 01651 minval = L_MIN(minval, val5); 01652 minval = L_MIN(minval + 1, val); 01653 SET_DATA_TWO_BYTES(lined, j, minval); 01654 } 01655 } 01656 } 01657 } 01658 break; 01659 01660 default: 01661 L_ERROR("connectivity must be 4 or 8", procName); 01662 break; 01663 } 01664 01665 return; 01666 } 01667 01668 01669 /*-----------------------------------------------------------------------* 01670 * Seed spread (based on distance function) * 01671 *-----------------------------------------------------------------------*/ 01672 /*! 01673 * seedspreadLow() 01674 * 01675 * See pixSeedspread() for a brief description of the algorithm here. 01676 */ 01677 void 01678 seedspreadLow(l_uint32 *datad, 01679 l_int32 w, 01680 l_int32 h, 01681 l_int32 wpld, 01682 l_uint32 *datat, 01683 l_int32 wplt, 01684 l_int32 connectivity) 01685 { 01686 l_int32 val1t, val2t, val3t, val4t, val5t, val6t, val7t, val8t; 01687 l_int32 i, j, imax, jmax, minval, valt, vald; 01688 l_uint32 *linet, *lined; 01689 01690 PROCNAME("seedspreadLow"); 01691 01692 /* One raster scan followed by one anti-raster scan. 01693 * pixt is initialized to have 0 on pixels where the 01694 * input is specified in pixd, and to have 1 on all 01695 * other pixels. We only change pixels in pixt and pixd 01696 * that are non-zero in pixt. */ 01697 imax = h - 1; 01698 jmax = w - 1; 01699 switch (connectivity) 01700 { 01701 case 4: 01702 /* UL --> LR scan */ 01703 for (i = 1; i < h; i++) { 01704 linet = datat + i * wplt; 01705 lined = datad + i * wpld; 01706 for (j = 1; j < jmax; j++) { 01707 if ((valt = GET_DATA_TWO_BYTES(linet, j)) > 0) { 01708 val2t = GET_DATA_TWO_BYTES(linet - wplt, j); 01709 val4t = GET_DATA_TWO_BYTES(linet, j - 1); 01710 minval = L_MIN(val2t, val4t); 01711 minval = L_MIN(minval, 0xfffe); 01712 SET_DATA_TWO_BYTES(linet, j, minval + 1); 01713 if (val2t < val4t) 01714 vald = GET_DATA_BYTE(lined - wpld, j); 01715 else 01716 vald = GET_DATA_BYTE(lined, j - 1); 01717 SET_DATA_BYTE(lined, j, vald); 01718 } 01719 } 01720 } 01721 01722 /* LR --> UL scan */ 01723 for (i = imax - 1; i > 0; i--) { 01724 linet = datat + i * wplt; 01725 lined = datad + i * wpld; 01726 for (j = jmax - 1; j > 0; j--) { 01727 if ((valt = GET_DATA_TWO_BYTES(linet, j)) > 0) { 01728 val7t = GET_DATA_TWO_BYTES(linet + wplt, j); 01729 val5t = GET_DATA_TWO_BYTES(linet, j + 1); 01730 minval = L_MIN(val5t, val7t); 01731 minval = L_MIN(minval + 1, valt); 01732 if (valt > minval) { /* replace */ 01733 SET_DATA_TWO_BYTES(linet, j, minval); 01734 if (val5t < val7t) 01735 vald = GET_DATA_BYTE(lined, j + 1); 01736 else 01737 vald = GET_DATA_BYTE(lined + wplt, j); 01738 SET_DATA_BYTE(lined, j, vald); 01739 } 01740 } 01741 } 01742 } 01743 break; 01744 case 8: 01745 /* UL --> LR scan */ 01746 for (i = 1; i < h; i++) { 01747 linet = datat + i * wplt; 01748 lined = datad + i * wpld; 01749 for (j = 1; j < jmax; j++) { 01750 if ((valt = GET_DATA_TWO_BYTES(linet, j)) > 0) { 01751 val1t = GET_DATA_TWO_BYTES(linet - wplt, j - 1); 01752 val2t = GET_DATA_TWO_BYTES(linet - wplt, j); 01753 val3t = GET_DATA_TWO_BYTES(linet - wplt, j + 1); 01754 val4t = GET_DATA_TWO_BYTES(linet, j - 1); 01755 minval = L_MIN(val1t, val2t); 01756 minval = L_MIN(minval, val3t); 01757 minval = L_MIN(minval, val4t); 01758 minval = L_MIN(minval, 0xfffe); 01759 SET_DATA_TWO_BYTES(linet, j, minval + 1); 01760 if (minval == val1t) 01761 vald = GET_DATA_BYTE(lined - wpld, j - 1); 01762 else if (minval == val2t) 01763 vald = GET_DATA_BYTE(lined - wpld, j); 01764 else if (minval == val3t) 01765 vald = GET_DATA_BYTE(lined - wpld, j + 1); 01766 else /* minval == val4t */ 01767 vald = GET_DATA_BYTE(lined, j - 1); 01768 SET_DATA_BYTE(lined, j, vald); 01769 } 01770 } 01771 } 01772 01773 /* LR --> UL scan */ 01774 for (i = imax - 1; i > 0; i--) { 01775 linet = datat + i * wplt; 01776 lined = datad + i * wpld; 01777 for (j = jmax - 1; j > 0; j--) { 01778 if ((valt = GET_DATA_TWO_BYTES(linet, j)) > 0) { 01779 val8t = GET_DATA_TWO_BYTES(linet + wplt, j + 1); 01780 val7t = GET_DATA_TWO_BYTES(linet + wplt, j); 01781 val6t = GET_DATA_TWO_BYTES(linet + wplt, j - 1); 01782 val5t = GET_DATA_TWO_BYTES(linet, j + 1); 01783 minval = L_MIN(val8t, val7t); 01784 minval = L_MIN(minval, val6t); 01785 minval = L_MIN(minval, val5t); 01786 minval = L_MIN(minval + 1, valt); 01787 if (valt > minval) { /* replace */ 01788 SET_DATA_TWO_BYTES(linet, j, minval); 01789 if (minval == val5t + 1) 01790 vald = GET_DATA_BYTE(lined, j + 1); 01791 else if (minval == val6t + 1) 01792 vald = GET_DATA_BYTE(lined + wpld, j - 1); 01793 else if (minval == val7t + 1) 01794 vald = GET_DATA_BYTE(lined + wpld, j); 01795 else /* minval == val8t + 1 */ 01796 vald = GET_DATA_BYTE(lined + wpld, j + 1); 01797 SET_DATA_BYTE(lined, j, vald); 01798 } 01799 } 01800 } 01801 } 01802 break; 01803 default: 01804 L_ERROR("connectivity must be 4 or 8", procName); 01805 break; 01806 } 01807 01808 return; 01809 }