Leptonica 1.68
C Image Processing Library

graymorphlow.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 /*
00018  *  graymorphlow.c
00019  *
00020  *      Low-level grayscale morphological operations
00021  *
00022  *            void     dilateGrayLow()
00023  *            void     erodeGrayLow()
00024  *
00025  *      
00026  *      We use the van Herk/Gil-Werman (vHGW) algorithm, [van Herk,
00027  *      Patt. Recog. Let. 13, pp. 517-521, 1992; Gil and Werman,
00028  *      IEEE Trans PAMI 15(5), pp. 504-507, 1993.] 
00029  *      This was the first grayscale morphology
00030  *      algorithm to compute dilation and erosion with
00031  *      complexity independent of the size of the structuring
00032  *      element.  It is simple and elegant, and surprising that
00033  *      it was discovered as recently as 1992.  It works for
00034  *      SEs composed of horizontal and/or vertical lines.  The
00035  *      general case requires finding the Min or Max over an
00036  *      arbitrary set of pixels, and this requires a number of
00037  *      pixel comparisons equal to the SE "size" at each pixel
00038  *      in the image.  The vHGW algorithm requires not
00039  *      more than 3 comparisons at each point.  The algorithm has been
00040  *      recently refined by Gil and Kimmel ("Efficient Dilation
00041  *      Erosion, Opening and Closing Algorithms", in "Mathematical
00042  *      Morphology and its Applications to Image and Signal Processing",
00043  *      the proceedings of the International Symposium on Mathematical
00044  *      Morphology, Palo Alto, CA, June 2000, Kluwer Academic
00045  *      Publishers, pp. 301-310).  They bring this number down below
00046  *      1.5 comparisons per output pixel but at a cost of significantly
00047  *      increased complexity, so I don't bother with that here.
00048  *
00049  *      In brief, the method is as follows.  We evaluate the dilation
00050  *      in groups of "size" pixels, equal to the size of the SE.
00051  *      For horizontal, we start at x = "size"/2 and go
00052  *      (w - 2 * ("size"/2))/"size" steps.  This means that
00053  *      we don't evaluate the first 0.5 * "size" pixels and, worst
00054  *      case, the last 1.5 * "size" pixels.  Thus we embed the
00055  *      image in a larger image with these augmented dimensions, where
00056  *      the new border pixels are appropriately initialized (0 for
00057  *      dilation; 255 for erosion), and remove the boundary at the end.
00058  *      (For vertical, use h instead of w.)   Then for each group
00059  *      of "size" pixels, we form an array of length 2 * "size" + 1,
00060  *      consisting of backward and forward partial maxima (for
00061  *      dilation) or minima (for erosion).  This represents a
00062  *      jumping window computed from the source image, over which
00063  *      the SE will slide.  The center of the array gets the source
00064  *      pixel at the center of the SE.  Call this the center pixel
00065  *      of the window.  Array values to left of center get
00066  *      the maxima(minima) of the pixels from the center
00067  *      one and going to the left an equal distance.  Array
00068  *      values to the right of center get the maxima(minima) to
00069  *      the pixels from the center one and going to the right
00070  *      an equal distance.  These are computed sequentially starting
00071  *      from the center one.  The SE (of length "size") can slide over this 
00072  *      window (of length 2 * "size + 1) at "size" different places.
00073  *      At each place, the maxima(minima) of the values in the window
00074  *      that correspond to the end points of the SE give the extremal
00075  *      values over that interval, and these are stored at the dest
00076  *      pixel corresponding to the SE center.  A picture is worth
00077  *      at least this many words, so if this isn't clear, see the
00078  *      leptonica documentation on grayscale morphology.
00079  *      
00080  */
00081 
00082 #include <stdio.h>
00083 
00084 #include "allheaders.h"
00085 
00086 
00087 
00088 /*-----------------------------------------------------------------*
00089  *              Low-level gray morphological operations            *
00090  *-----------------------------------------------------------------*/
00091 /*!
00092  *  dilateGrayLow()
00093  *
00094  *    Input: datad, w, h, wpld (8 bpp image)
00095  *           datas, wpls  (8 bpp image, of same dimensions)
00096  *           size  (full length of SEL; restricted to odd numbers)
00097  *           direction  (L_HORIZ or L_VERT)
00098  *           buffer  (holds full line or column of src image pixels)
00099  *           maxarray  (array of dimension 2*size+1)
00100  *    Return: void
00101  *           
00102  *    Note: To eliminate border effects on the actual image, these images
00103  *          are prepared with an additional border of dimensions:
00104  *             leftpix = 0.5 * size
00105  *             rightpix = 1.5 * size
00106  *             toppix = 0.5 * size
00107  *             bottompix = 1.5 * size
00108  *          and we initialize the src border pixels to 0.
00109  *          This allows full processing over the actual image; at
00110  *          the end the border is removed.
00111  *
00112  *    Method: Algorithm by van Herk and Gil and Werman
00113  */
00114 void
00115 dilateGrayLow(l_uint32  *datad,
00116               l_int32    w,
00117               l_int32    h,
00118               l_int32    wpld,
00119               l_uint32  *datas,
00120               l_int32    wpls,
00121               l_int32    size,
00122               l_int32    direction,
00123               l_uint8   *buffer,
00124               l_uint8   *maxarray)
00125 {
00126 l_int32    i, j, k;
00127 l_int32    hsize, nsteps, startmax, startx, starty;
00128 l_uint8    maxval;
00129 l_uint32  *lines, *lined;
00130 
00131     if (direction == L_HORIZ) {
00132         hsize = size / 2;
00133         nsteps = (w - 2 * hsize) / size;
00134         for (i = 0; i < h; i++) {
00135             lines = datas + i * wpls;
00136             lined = datad + i * wpld;
00137 
00138                 /* fill buffer with pixels in byte order */
00139             for (j = 0; j < w; j++)
00140                 buffer[j] = GET_DATA_BYTE(lines, j);
00141 
00142             for (j = 0; j < nsteps; j++)
00143             {
00144                     /* refill the minarray */
00145                 startmax = (j + 1) * size - 1;
00146                 maxarray[size - 1] = buffer[startmax];
00147                 for (k = 1; k < size; k++) {
00148                     maxarray[size - 1 - k] =
00149                         L_MAX(maxarray[size - k], buffer[startmax - k]);
00150                     maxarray[size - 1 + k] =
00151                         L_MAX(maxarray[size + k - 2], buffer[startmax + k]);
00152                 }
00153 
00154                     /* compute dilation values */
00155                 startx = hsize + j * size;
00156                 SET_DATA_BYTE(lined, startx, maxarray[0]);
00157                 SET_DATA_BYTE(lined, startx + size - 1, maxarray[2 * size - 2]);
00158                 for (k = 1; k < size - 1; k++) {
00159                     maxval = L_MAX(maxarray[k], maxarray[k + size - 1]);
00160                     SET_DATA_BYTE(lined, startx + k, maxval);
00161                 }
00162             }
00163         }
00164     }
00165     else {   /* direction == L_VERT */ 
00166         hsize = size / 2;
00167         nsteps = (h - 2 * hsize) / size;
00168         for (j = 0; j < w; j++) {
00169 
00170                 /* fill buffer with pixels in byte order */
00171             for (i = 0; i < h; i++) {
00172                 lines = datas + i * wpls;
00173                 buffer[i] = GET_DATA_BYTE(lines, j);
00174             }
00175 
00176             for (i = 0; i < nsteps; i++)
00177             {
00178                     /* refill the minarray */
00179                 startmax = (i + 1) * size - 1;
00180                 maxarray[size - 1] = buffer[startmax];
00181                 for (k = 1; k < size; k++) {
00182                     maxarray[size - 1 - k] =
00183                         L_MAX(maxarray[size - k], buffer[startmax - k]);
00184                     maxarray[size - 1 + k] =
00185                         L_MAX(maxarray[size + k - 2], buffer[startmax + k]);
00186                 }
00187 
00188                     /* compute dilation values */
00189                 starty = hsize + i * size;
00190                 lined = datad + starty * wpld;
00191                 SET_DATA_BYTE(lined, j, maxarray[0]);
00192                 SET_DATA_BYTE(lined + (size - 1) * wpld, j,
00193                         maxarray[2 * size - 2]);
00194                 for (k = 1; k < size - 1; k++) {
00195                     maxval = L_MAX(maxarray[k], maxarray[k + size - 1]);
00196                     SET_DATA_BYTE(lined + wpld * k, j, maxval);
00197                 }
00198             }
00199         }
00200     }
00201             
00202     return;
00203 }
00204 
00205 
00206 /*!
00207  *  erodeGrayLow()
00208  *
00209  *    Input: datad, w, h, wpld (8 bpp image)
00210  *           datas, wpls  (8 bpp image, of same dimensions)
00211  *           size  (full length of SEL; restricted to odd numbers)
00212  *           direction  (L_HORIZ or L_VERT)
00213  *           buffer  (holds full line or column of src image pixels)
00214  *           minarray  (array of dimension 2*size+1)
00215  *    Return: void
00216  *           
00217  *    Note: To eliminate border effects on the actual image, these images
00218  *          are prepared with an additional border of dimensions:
00219  *             leftpix = 0.5 * size
00220  *             rightpix = 1.5 * size
00221  *             toppix = 0.5 * size
00222  *             bottompix = 1.5 * size
00223  *          and we initialize the src border pixels to 255.
00224  *          This allows full processing over the actual image; at
00225  *          the end the border is removed.
00226  *
00227  *    Method: Algorithm by van Herk and Gil and Werman
00228  *
00229  */
00230 void
00231 erodeGrayLow(l_uint32  *datad,
00232              l_int32    w,
00233              l_int32    h,
00234              l_int32    wpld,
00235              l_uint32  *datas,
00236              l_int32    wpls,
00237              l_int32    size,
00238              l_int32    direction,
00239              l_uint8   *buffer,
00240              l_uint8   *minarray)
00241 {
00242 l_int32    i, j, k;
00243 l_int32    hsize, nsteps, startmin, startx, starty;
00244 l_uint8    minval;
00245 l_uint32  *lines, *lined;
00246 
00247     if (direction == L_HORIZ) {
00248         hsize = size / 2;
00249         nsteps = (w - 2 * hsize) / size;
00250         for (i = 0; i < h; i++) {
00251             lines = datas + i * wpls;
00252             lined = datad + i * wpld;
00253 
00254                 /* fill buffer with pixels in byte order */
00255             for (j = 0; j < w; j++)
00256                 buffer[j] = GET_DATA_BYTE(lines, j);
00257 
00258             for (j = 0; j < nsteps; j++)
00259             {
00260                     /* refill the minarray */
00261                 startmin = (j + 1) * size - 1;
00262                 minarray[size - 1] = buffer[startmin];
00263                 for (k = 1; k < size; k++) {
00264                     minarray[size - 1 - k] =
00265                         L_MIN(minarray[size - k], buffer[startmin - k]);
00266                     minarray[size - 1 + k] =
00267                         L_MIN(minarray[size + k - 2], buffer[startmin + k]);
00268                 }
00269 
00270                     /* compute erosion values */
00271                 startx = hsize + j * size;
00272                 SET_DATA_BYTE(lined, startx, minarray[0]);
00273                 SET_DATA_BYTE(lined, startx + size - 1, minarray[2 * size - 2]);
00274                 for (k = 1; k < size - 1; k++) {
00275                     minval = L_MIN(minarray[k], minarray[k + size - 1]);
00276                     SET_DATA_BYTE(lined, startx + k, minval);
00277                 }
00278             }
00279         }
00280     }
00281     else {   /* direction == L_VERT */ 
00282         hsize = size / 2;
00283         nsteps = (h - 2 * hsize) / size;
00284         for (j = 0; j < w; j++) {
00285 
00286                 /* fill buffer with pixels in byte order */
00287             for (i = 0; i < h; i++) {
00288                 lines = datas + i * wpls;
00289                 buffer[i] = GET_DATA_BYTE(lines, j);
00290             }
00291 
00292             for (i = 0; i < nsteps; i++)
00293             {
00294                     /* refill the minarray */
00295                 startmin = (i + 1) * size - 1;
00296                 minarray[size - 1] = buffer[startmin];
00297                 for (k = 1; k < size; k++) {
00298                     minarray[size - 1 - k] =
00299                         L_MIN(minarray[size - k], buffer[startmin - k]);
00300                     minarray[size - 1 + k] =
00301                         L_MIN(minarray[size + k - 2], buffer[startmin + k]);
00302                 }
00303 
00304                     /* compute erosion values */
00305                 starty = hsize + i * size;
00306                 lined = datad + starty * wpld;
00307                 SET_DATA_BYTE(lined, j, minarray[0]);
00308                 SET_DATA_BYTE(lined + (size - 1) * wpld, j,
00309                         minarray[2 * size - 2]);
00310                 for (k = 1; k < size - 1; k++) {
00311                     minval = L_MIN(minarray[k], minarray[k + size - 1]);
00312                     SET_DATA_BYTE(lined + wpld * k, j, minval);
00313                 }
00314             }
00315         }
00316     }
00317             
00318     return;
00319 }
00320 
00321 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines