Leptonica 1.68
C Image Processing Library

seedfilllow.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines