Leptonica 1.68
C Image Processing Library

graymorph.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  *  graymorph.c
00019  *
00020  *      Top-level binary morphological operations (van Herk / Gil-Werman)
00021  *            PIX     *pixErodeGray()
00022  *            PIX     *pixDilateGray()
00023  *            PIX     *pixOpenGray()
00024  *            PIX     *pixCloseGray()
00025  *
00026  *      Special operations for 1x3, 3x1 and 3x3 Sels  (direct)
00027  *            PIX     *pixErodeGray3()
00028  *            PIX     *pixDilateGray3()
00029  *            PIX     *pixOpenGray3()
00030  *            PIX     *pixCloseGray3()
00031  *
00032  *
00033  *      Method: Algorithm by van Herk and Gil and Werman, 1992
00034  *
00035  *      Measured speed of the vH/G-W implementation is about 1 output
00036  *      pixel per 120 PIII clock cycles, for a horizontal or vertical
00037  *      erosion or dilation.  The computation time doubles for opening
00038  *      or closing, or for a square SE, as expected, and is independent
00039  *      of the size of the SE.
00040  *
00041  *      A faster implementation can be made directly for brick Sels
00042  *      of maximum size 3.  We unroll the computation for sets of 8 bytes.
00043  *      It needs to be called explicitly; the general functions do not
00044  *      default for the size 3 brick Sels.
00045  */
00046 
00047 #include <stdio.h>
00048 #include <stdlib.h>
00049 #include "allheaders.h"
00050 
00051 static PIX *pixErodeGray3h(PIX *pixs);
00052 static PIX *pixErodeGray3v(PIX *pixs);
00053 static PIX *pixDilateGray3h(PIX *pixs);
00054 static PIX *pixDilateGray3v(PIX *pixs);
00055 
00056 
00057 /*-----------------------------------------------------------------*
00058  *              Top-level gray morphological operations            *
00059  *-----------------------------------------------------------------*/
00060 /*!
00061  *  pixErodeGray()
00062  *
00063  *      Input:  pixs
00064  *              hsize  (of Sel; must be odd; origin implicitly in center)
00065  *              vsize  (ditto)
00066  *      Return: pixd
00067  *
00068  *  Notes:
00069  *      (1) Sel is a brick with all elements being hits
00070  *      (2) If hsize = vsize = 1, just returns a copy.
00071  */
00072 PIX *
00073 pixErodeGray(PIX     *pixs,
00074              l_int32  hsize,
00075              l_int32  vsize)
00076 {
00077 l_uint8   *buffer, *minarray;
00078 l_int32    w, h, wplb, wplt;
00079 l_int32    leftpix, rightpix, toppix, bottompix, maxsize;
00080 l_uint32  *datab, *datat;
00081 PIX       *pixb, *pixt, *pixd;
00082 
00083     PROCNAME("pixErodeGray");
00084 
00085     if (!pixs)
00086         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00087     if (pixGetDepth(pixs) != 8)
00088         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00089     if (hsize < 1 || vsize < 1)
00090         return (PIX *)ERROR_PTR("hsize or vsize < 1", procName, NULL);
00091     if ((hsize & 1) == 0 ) {
00092         L_WARNING("horiz sel size must be odd; increasing by 1", procName);
00093         hsize++;
00094     }
00095     if ((vsize & 1) == 0 ) {
00096         L_WARNING("vert sel size must be odd; increasing by 1", procName);
00097         vsize++;
00098     }
00099 
00100     if (hsize == 1 && vsize == 1)
00101         return pixCopy(NULL, pixs);
00102 
00103     if (vsize == 1) {  /* horizontal sel */
00104         leftpix = (hsize + 1) / 2;
00105         rightpix = (3 * hsize + 1) / 2;
00106         toppix = 0;
00107         bottompix = 0;
00108     }
00109     else if (hsize == 1) {  /* vertical sel */
00110         leftpix = 0;
00111         rightpix = 0;
00112         toppix = (vsize + 1) / 2;
00113         bottompix = (3 * vsize + 1) / 2;
00114     }
00115     else {
00116         leftpix = (hsize + 1) / 2;
00117         rightpix = (3 * hsize + 1) / 2;
00118         toppix = (vsize + 1) / 2;
00119         bottompix = (3 * vsize + 1) / 2;
00120     }
00121 
00122     if ((pixb = pixAddBorderGeneral(pixs,
00123                 leftpix, rightpix, toppix, bottompix, 255)) == NULL)
00124         return (PIX *)ERROR_PTR("pixb not made", procName, NULL);
00125     if ((pixt = pixCreateTemplate(pixb)) == NULL)
00126         return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
00127     
00128     pixGetDimensions(pixt, &w, &h, NULL);
00129     datab = pixGetData(pixb);
00130     datat = pixGetData(pixt);
00131     wplb = pixGetWpl(pixb);
00132     wplt = pixGetWpl(pixt);
00133 
00134     if ((buffer = (l_uint8 *)CALLOC(L_MAX(w, h), sizeof(l_uint8))) == NULL)
00135         return (PIX *)ERROR_PTR("buffer not made", procName, NULL);
00136     maxsize = L_MAX(hsize, vsize);
00137     if ((minarray = (l_uint8 *)CALLOC(2 * maxsize, sizeof(l_uint8))) == NULL)
00138         return (PIX *)ERROR_PTR("minarray not made", procName, NULL);
00139 
00140     if (vsize == 1)
00141         erodeGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
00142                      buffer, minarray);
00143     else if (hsize == 1)
00144         erodeGrayLow(datat, w, h, wplt, datab, wplb, vsize, L_VERT,
00145                      buffer, minarray);
00146     else {
00147         erodeGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
00148                      buffer, minarray);
00149         pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
00150                             PIX_SET);
00151         erodeGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
00152                      buffer, minarray);
00153         pixDestroy(&pixt);
00154         pixt = pixClone(pixb);
00155     }
00156 
00157     if ((pixd = pixRemoveBorderGeneral(pixt,
00158                 leftpix, rightpix, toppix, bottompix)) == NULL)
00159         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00160 
00161     FREE(buffer);
00162     FREE(minarray);
00163     pixDestroy(&pixb);
00164     pixDestroy(&pixt);
00165     return pixd;
00166 }
00167 
00168 
00169 /*!
00170  *  pixDilateGray()
00171  *
00172  *      Input:  pixs
00173  *              hsize  (of Sel; must be odd; origin implicitly in center)
00174  *              vsize  (ditto)
00175  *      Return: pixd
00176  *
00177  *  Notes:
00178  *      (1) Sel is a brick with all elements being hits
00179  *      (2) If hsize = vsize = 1, just returns a copy.
00180  */
00181 PIX *
00182 pixDilateGray(PIX     *pixs,
00183               l_int32  hsize,
00184               l_int32  vsize)
00185 {
00186 l_uint8   *buffer, *maxarray;
00187 l_int32    w, h, wplb, wplt;
00188 l_int32    leftpix, rightpix, toppix, bottompix, maxsize;
00189 l_uint32  *datab, *datat;
00190 PIX       *pixb, *pixt, *pixd;
00191 
00192     PROCNAME("pixDilateGray");
00193 
00194     if (!pixs)
00195         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00196     if (pixGetDepth(pixs) != 8)
00197         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00198     if (hsize < 1 || vsize < 1)
00199         return (PIX *)ERROR_PTR("hsize or vsize < 1", procName, NULL);
00200     if ((hsize & 1) == 0 ) {
00201         L_WARNING("horiz sel size must be odd; increasing by 1", procName);
00202         hsize++;
00203     }
00204     if ((vsize & 1) == 0 ) {
00205         L_WARNING("vert sel size must be odd; increasing by 1", procName);
00206         vsize++;
00207     }
00208 
00209     if (hsize == 1 && vsize == 1)
00210         return pixCopy(NULL, pixs);
00211 
00212     if (vsize == 1) {  /* horizontal sel */
00213         leftpix = (hsize + 1) / 2;
00214         rightpix = (3 * hsize + 1) / 2;
00215         toppix = 0;
00216         bottompix = 0;
00217     }
00218     else if (hsize == 1) {  /* vertical sel */
00219         leftpix = 0;
00220         rightpix = 0;
00221         toppix = (vsize + 1) / 2;
00222         bottompix = (3 * vsize + 1) / 2;
00223     }
00224     else {
00225         leftpix = (hsize + 1) / 2;
00226         rightpix = (3 * hsize + 1) / 2;
00227         toppix = (vsize + 1) / 2;
00228         bottompix = (3 * vsize + 1) / 2;
00229     }
00230 
00231     if ((pixb = pixAddBorderGeneral(pixs,
00232                 leftpix, rightpix, toppix, bottompix, 0)) == NULL)
00233         return (PIX *)ERROR_PTR("pixb not made", procName, NULL);
00234     if ((pixt = pixCreateTemplate(pixb)) == NULL)
00235         return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
00236     
00237     pixGetDimensions(pixt, &w, &h, NULL);
00238     datab = pixGetData(pixb);
00239     datat = pixGetData(pixt);
00240     wplb = pixGetWpl(pixb);
00241     wplt = pixGetWpl(pixt);
00242 
00243     if ((buffer = (l_uint8 *)CALLOC(L_MAX(w, h), sizeof(l_uint8))) == NULL)
00244         return (PIX *)ERROR_PTR("buffer not made", procName, NULL);
00245     maxsize = L_MAX(hsize, vsize);
00246     if ((maxarray = (l_uint8 *)CALLOC(2 * maxsize, sizeof(l_uint8))) == NULL)
00247         return (PIX *)ERROR_PTR("buffer not made", procName, NULL);
00248 
00249     if (vsize == 1)
00250         dilateGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
00251                       buffer, maxarray);
00252     else if (hsize == 1)
00253         dilateGrayLow(datat, w, h, wplt, datab, wplb, vsize, L_VERT,
00254                       buffer, maxarray);
00255     else {
00256         dilateGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
00257                       buffer, maxarray);
00258         pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
00259                             PIX_CLR);
00260         dilateGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
00261                       buffer, maxarray);
00262         pixDestroy(&pixt);
00263         pixt = pixClone(pixb);
00264     }
00265 
00266     if ((pixd = pixRemoveBorderGeneral(pixt,
00267                 leftpix, rightpix, toppix, bottompix)) == NULL)
00268         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00269 
00270     FREE(buffer);
00271     FREE(maxarray);
00272     pixDestroy(&pixb);
00273     pixDestroy(&pixt);
00274     return pixd;
00275 }
00276 
00277 
00278 /*!
00279  *  pixOpenGray()
00280  *
00281  *      Input:  pixs
00282  *              hsize  (of Sel; must be odd; origin implicitly in center)
00283  *              vsize  (ditto)
00284  *      Return: pixd
00285  *
00286  *  Notes:
00287  *      (1) Sel is a brick with all elements being hits
00288  *      (2) If hsize = vsize = 1, just returns a copy.
00289  */
00290 PIX *
00291 pixOpenGray(PIX     *pixs,
00292             l_int32  hsize,
00293             l_int32  vsize)
00294 {
00295 l_uint8   *buffer;
00296 l_uint8   *array;  /* used to find either min or max in interval */
00297 l_int32    w, h, wplb, wplt;
00298 l_int32    leftpix, rightpix, toppix, bottompix, maxsize;
00299 l_uint32  *datab, *datat;
00300 PIX       *pixb, *pixt, *pixd;
00301 
00302     PROCNAME("pixOpenGray");
00303 
00304     if (!pixs)
00305         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00306     if (pixGetDepth(pixs) != 8)
00307         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00308     if (hsize < 1 || vsize < 1)
00309         return (PIX *)ERROR_PTR("hsize or vsize < 1", procName, NULL);
00310     if ((hsize & 1) == 0 ) {
00311         L_WARNING("horiz sel size must be odd; increasing by 1", procName);
00312         hsize++;
00313     }
00314     if ((vsize & 1) == 0 ) {
00315         L_WARNING("vert sel size must be odd; increasing by 1", procName);
00316         vsize++;
00317     }
00318 
00319     if (hsize == 1 && vsize == 1)
00320         return pixCopy(NULL, pixs);
00321 
00322     if (vsize == 1) {  /* horizontal sel */
00323         leftpix = (hsize + 1) / 2;
00324         rightpix = (3 * hsize + 1) / 2;
00325         toppix = 0;
00326         bottompix = 0;
00327     }
00328     else if (hsize == 1) {  /* vertical sel */
00329         leftpix = 0;
00330         rightpix = 0;
00331         toppix = (vsize + 1) / 2;
00332         bottompix = (3 * vsize + 1) / 2;
00333     }
00334     else {
00335         leftpix = (hsize + 1) / 2;
00336         rightpix = (3 * hsize + 1) / 2;
00337         toppix = (vsize + 1) / 2;
00338         bottompix = (3 * vsize + 1) / 2;
00339     }
00340 
00341     if ((pixb = pixAddBorderGeneral(pixs,
00342                 leftpix, rightpix, toppix, bottompix, 255)) == NULL)
00343         return (PIX *)ERROR_PTR("pixb not made", procName, NULL);
00344     if ((pixt = pixCreateTemplate(pixb)) == NULL)
00345         return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
00346     
00347     pixGetDimensions(pixt, &w, &h, NULL);
00348     datab = pixGetData(pixb);
00349     datat = pixGetData(pixt);
00350     wplb = pixGetWpl(pixb);
00351     wplt = pixGetWpl(pixt);
00352 
00353     if ((buffer = (l_uint8 *)CALLOC(L_MAX(w, h), sizeof(l_uint8))) == NULL)
00354         return (PIX *)ERROR_PTR("buffer not made", procName, NULL);
00355     maxsize = L_MAX(hsize, vsize);
00356     if ((array = (l_uint8 *)CALLOC(2 * maxsize, sizeof(l_uint8))) == NULL)
00357         return (PIX *)ERROR_PTR("array not made", procName, NULL);
00358 
00359     if (vsize == 1) {
00360         erodeGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
00361                      buffer, array);
00362         pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
00363                             PIX_CLR);
00364         dilateGrayLow(datab, w, h, wplb, datat, wplt, hsize, L_HORIZ,
00365                       buffer, array);
00366     }
00367     else if (hsize == 1) {
00368         erodeGrayLow(datat, w, h, wplt, datab, wplb, vsize, L_VERT,
00369                      buffer, array);
00370         pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
00371                             PIX_CLR);
00372         dilateGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
00373                       buffer, array);
00374     }
00375     else {
00376         erodeGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
00377                      buffer, array);
00378         pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
00379                             PIX_SET);
00380         erodeGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
00381                      buffer, array);
00382         pixSetOrClearBorder(pixb, leftpix, rightpix, toppix, bottompix,
00383                             PIX_CLR);
00384         dilateGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
00385                       buffer, array);
00386         pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
00387                             PIX_CLR);
00388         dilateGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
00389                       buffer, array);
00390     }
00391 
00392     if ((pixd = pixRemoveBorderGeneral(pixb,
00393                 leftpix, rightpix, toppix, bottompix)) == NULL)
00394         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00395 
00396     FREE(buffer);
00397     FREE(array);
00398     pixDestroy(&pixb);
00399     pixDestroy(&pixt);
00400     return pixd;
00401 }
00402 
00403 
00404 /*!
00405  *  pixCloseGray()
00406  *
00407  *      Input:  pixs
00408  *              hsize  (of Sel; must be odd; origin implicitly in center)
00409  *              vsize  (ditto)
00410  *      Return: pixd
00411  *
00412  *  Notes:
00413  *      (1) Sel is a brick with all elements being hits
00414  *      (2) If hsize = vsize = 1, just returns a copy.
00415  */
00416 PIX *
00417 pixCloseGray(PIX     *pixs,
00418              l_int32  hsize,
00419              l_int32  vsize)
00420 {
00421 l_uint8   *buffer;
00422 l_uint8   *array;  /* used to find either min or max in interval */
00423 l_int32    w, h, wplb, wplt;
00424 l_int32    leftpix, rightpix, toppix, bottompix, maxsize;
00425 l_uint32  *datab, *datat;
00426 PIX       *pixb, *pixt, *pixd;
00427 
00428     PROCNAME("pixCloseGray");
00429 
00430     if (!pixs)
00431         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00432     if (pixGetDepth(pixs) != 8)
00433         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00434     if (hsize < 1 || vsize < 1)
00435         return (PIX *)ERROR_PTR("hsize or vsize < 1", procName, NULL);
00436     if ((hsize & 1) == 0 ) {
00437         L_WARNING("horiz sel size must be odd; increasing by 1", procName);
00438         hsize++;
00439     }
00440     if ((vsize & 1) == 0 ) {
00441         L_WARNING("vert sel size must be odd; increasing by 1", procName);
00442         vsize++;
00443     }
00444 
00445     if (hsize == 1 && vsize == 1)
00446         return pixCopy(NULL, pixs);
00447 
00448     if (vsize == 1) {  /* horizontal sel */
00449         leftpix = (hsize + 1) / 2;
00450         rightpix = (3 * hsize + 1) / 2;
00451         toppix = 0;
00452         bottompix = 0;
00453     }
00454     else if (hsize == 1) {  /* vertical sel */
00455         leftpix = 0;
00456         rightpix = 0;
00457         toppix = (vsize + 1) / 2;
00458         bottompix = (3 * vsize + 1) / 2;
00459     }
00460     else {
00461         leftpix = (hsize + 1) / 2;
00462         rightpix = (3 * hsize + 1) / 2;
00463         toppix = (vsize + 1) / 2;
00464         bottompix = (3 * vsize + 1) / 2;
00465     }
00466 
00467     if ((pixb = pixAddBorderGeneral(pixs,
00468                 leftpix, rightpix, toppix, bottompix, 0)) == NULL)
00469         return (PIX *)ERROR_PTR("pixb not made", procName, NULL);
00470     if ((pixt = pixCreateTemplate(pixb)) == NULL)
00471         return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
00472     
00473     pixGetDimensions(pixt, &w, &h, NULL);
00474     datab = pixGetData(pixb);
00475     datat = pixGetData(pixt);
00476     wplb = pixGetWpl(pixb);
00477     wplt = pixGetWpl(pixt);
00478 
00479     if ((buffer = (l_uint8 *)CALLOC(L_MAX(w, h), sizeof(l_uint8))) == NULL)
00480         return (PIX *)ERROR_PTR("buffer not made", procName, NULL);
00481     maxsize = L_MAX(hsize, vsize);
00482     if ((array = (l_uint8 *)CALLOC(2 * maxsize, sizeof(l_uint8))) == NULL)
00483         return (PIX *)ERROR_PTR("array not made", procName, NULL);
00484 
00485     if (vsize == 1) {
00486         dilateGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
00487                      buffer, array);
00488         pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
00489                             PIX_SET);
00490         erodeGrayLow(datab, w, h, wplb, datat, wplt, hsize, L_HORIZ,
00491                       buffer, array);
00492     }
00493     else if (hsize == 1) {
00494         dilateGrayLow(datat, w, h, wplt, datab, wplb, vsize, L_VERT,
00495                      buffer, array);
00496         pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
00497                             PIX_SET);
00498         erodeGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
00499                       buffer, array);
00500     }
00501     else {
00502         dilateGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
00503                       buffer, array);
00504         pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
00505                             PIX_CLR);
00506         dilateGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
00507                       buffer, array);
00508         pixSetOrClearBorder(pixb, leftpix, rightpix, toppix, bottompix,
00509                             PIX_SET);
00510         erodeGrayLow(datat, w, h, wplt, datab, wplb, hsize, L_HORIZ,
00511                      buffer, array);
00512         pixSetOrClearBorder(pixt, leftpix, rightpix, toppix, bottompix,
00513                             PIX_SET);
00514         erodeGrayLow(datab, w, h, wplb, datat, wplt, vsize, L_VERT,
00515                      buffer, array);
00516     }
00517 
00518     if ((pixd = pixRemoveBorderGeneral(pixb,
00519                 leftpix, rightpix, toppix, bottompix)) == NULL)
00520         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00521 
00522     FREE(buffer);
00523     FREE(array);
00524     pixDestroy(&pixb);
00525     pixDestroy(&pixt);
00526     return pixd;
00527 }
00528 
00529 
00530 /*-----------------------------------------------------------------*
00531  *           Special operations for 1x3, 3x1 and 3x3 Sels          *
00532  *-----------------------------------------------------------------*/
00533 /*!
00534  *  pixErodeGray3()
00535  *
00536  *      Input:  pixs (8 bpp, not cmapped)
00537  *              hsize  (1 or 3)
00538  *              vsize  (1 or 3)
00539  *      Return: pixd, or null on error
00540  *
00541  *  Notes:
00542  *      (1) Special case for 1x3, 3x1 or 3x3 brick sel (all hits)
00543  *      (2) If hsize = vsize = 1, just returns a copy.
00544  *      (3) It would be nice not to add a border, but it is required
00545  *          if we want the same results as from the general case.
00546  *          We add 4 bytes on the left to speed up the copying, and
00547  *          8 bytes at the right and bottom to allow unrolling of
00548  *          the computation of 8 pixels.
00549  */
00550 PIX *
00551 pixErodeGray3(PIX     *pixs,
00552               l_int32  hsize,
00553               l_int32  vsize)
00554 {
00555 PIX  *pixt, *pixb, *pixbd, *pixd;
00556 
00557     PROCNAME("pixErodeGray3");
00558 
00559     if (!pixs)
00560         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00561     if (pixGetDepth(pixs) != 8)
00562         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00563     if (pixGetColormap(pixs))
00564         return (PIX *)ERROR_PTR("pix has colormap", procName, NULL);
00565     if ((hsize != 1 && hsize != 3) ||
00566         (vsize != 1 && vsize != 3))
00567         return (PIX *)ERROR_PTR("invalid size: must be 1 or 3", procName, NULL);
00568 
00569     if (hsize == 1 && vsize == 1)
00570         return pixCopy(NULL, pixs);
00571 
00572     pixb = pixAddBorderGeneral(pixs, 4, 8, 2, 8, 255);
00573 
00574     if (vsize == 1)
00575         pixbd = pixErodeGray3h(pixb);
00576     else if (hsize == 1)
00577         pixbd = pixErodeGray3v(pixb);
00578     else {  /* vize == hsize == 3 */
00579         pixt = pixErodeGray3h(pixb);
00580         pixbd = pixErodeGray3v(pixt);
00581         pixDestroy(&pixt);
00582     }
00583 
00584     pixd = pixRemoveBorderGeneral(pixbd, 4, 8, 2, 8);
00585     pixDestroy(&pixb);
00586     pixDestroy(&pixbd);
00587     return pixd;
00588 }
00589 
00590 
00591 /*!
00592  *  pixErodeGray3h()
00593  *
00594  *      Input:  pixs (8 bpp, not cmapped)
00595  *      Return: pixd, or null on error
00596  *
00597  *  Notes:
00598  *      (1) Special case for horizontal 3x1 brick Sel;
00599  *          also used as the first step for the 3x3 brick Sel.
00600  */
00601 static PIX *
00602 pixErodeGray3h(PIX  *pixs)
00603 {
00604 l_uint32  *datas, *datad, *lines, *lined;
00605 l_int32    w, h, wpl, i, j;
00606 l_int32    val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, minval;
00607 PIX       *pixd;
00608 
00609     PROCNAME("pixErodeGray3h");
00610 
00611     if (!pixs)
00612         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00613     if (pixGetDepth(pixs) != 8)
00614         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00615 
00616     pixd = pixCreateTemplateNoInit(pixs);
00617     pixSetBorderVal(pixd, 4, 8, 2, 8, 0);  /* only to silence valgrind */
00618     pixGetDimensions(pixs, &w, &h, NULL);
00619     datas = pixGetData(pixs);
00620     datad = pixGetData(pixd);
00621     wpl = pixGetWpl(pixs);
00622     for (i = 0; i < h; i++) {
00623         lines = datas + i * wpl;
00624         lined = datad + i * wpl;
00625         for (j = 1; j < w - 8; j += 8) {
00626             val0 = GET_DATA_BYTE(lines, j - 1);
00627             val1 = GET_DATA_BYTE(lines, j);
00628             val2 = GET_DATA_BYTE(lines, j + 1);
00629             val3 = GET_DATA_BYTE(lines, j + 2);
00630             val4 = GET_DATA_BYTE(lines, j + 3);
00631             val5 = GET_DATA_BYTE(lines, j + 4);
00632             val6 = GET_DATA_BYTE(lines, j + 5);
00633             val7 = GET_DATA_BYTE(lines, j + 6);
00634             val8 = GET_DATA_BYTE(lines, j + 7);
00635             val9 = GET_DATA_BYTE(lines, j + 8);
00636             minval = L_MIN(val1, val2);
00637             SET_DATA_BYTE(lined, j, L_MIN(val0, minval));
00638             SET_DATA_BYTE(lined, j + 1, L_MIN(minval, val3));
00639             minval = L_MIN(val3, val4);
00640             SET_DATA_BYTE(lined, j + 2, L_MIN(val2, minval));
00641             SET_DATA_BYTE(lined, j + 3, L_MIN(minval, val5));
00642             minval = L_MIN(val5, val6);
00643             SET_DATA_BYTE(lined, j + 4, L_MIN(val4, minval));
00644             SET_DATA_BYTE(lined, j + 5, L_MIN(minval, val7));
00645             minval = L_MIN(val7, val8);
00646             SET_DATA_BYTE(lined, j + 6, L_MIN(val6, minval));
00647             SET_DATA_BYTE(lined, j + 7, L_MIN(minval, val9));
00648         }
00649     }
00650     return pixd;
00651 }
00652 
00653 
00654 /*!
00655  *  pixErodeGray3v()
00656  *
00657  *      Input:  pixs (8 bpp, not cmapped)
00658  *      Return: pixd, or null on error
00659  *
00660  *  Notes:
00661  *      (1) Special case for vertical 1x3 brick Sel;
00662  *          also used as the second step for the 3x3 brick Sel.
00663  *      (2) Surprisingly, this is faster than setting up the
00664  *          lineptrs array and accessing into it; e.g.,
00665  *              val4 = GET_DATA_BYTE(lines8[i + 3], j);
00666  */
00667 static PIX *
00668 pixErodeGray3v(PIX  *pixs)
00669 {
00670 l_uint32  *datas, *datad, *linesi, *linedi;
00671 l_int32    w, h, wpl, i, j;
00672 l_int32    val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, minval;
00673 PIX       *pixd;
00674 
00675     PROCNAME("pixErodeGray3v");
00676 
00677     if (!pixs)
00678         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00679     if (pixGetDepth(pixs) != 8)
00680         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00681 
00682     pixd = pixCreateTemplateNoInit(pixs);
00683     pixGetDimensions(pixs, &w, &h, NULL);
00684     datas = pixGetData(pixs);
00685     datad = pixGetData(pixd);
00686     wpl = pixGetWpl(pixs);
00687     for (j = 0; j < w; j++) {
00688         for (i = 1; i < h - 8; i += 8) {
00689             linesi = datas + i * wpl;
00690             linedi = datad + i * wpl;
00691             val0 = GET_DATA_BYTE(linesi - wpl, j);
00692             val1 = GET_DATA_BYTE(linesi, j);
00693             val2 = GET_DATA_BYTE(linesi + wpl, j);
00694             val3 = GET_DATA_BYTE(linesi + 2 * wpl, j);
00695             val4 = GET_DATA_BYTE(linesi + 3 * wpl, j);
00696             val5 = GET_DATA_BYTE(linesi + 4 * wpl, j);
00697             val6 = GET_DATA_BYTE(linesi + 5 * wpl, j);
00698             val7 = GET_DATA_BYTE(linesi + 6 * wpl, j);
00699             val8 = GET_DATA_BYTE(linesi + 7 * wpl, j);
00700             val9 = GET_DATA_BYTE(linesi + 8 * wpl, j);
00701             minval = L_MIN(val1, val2);
00702             SET_DATA_BYTE(linedi, j, L_MIN(val0, minval));
00703             SET_DATA_BYTE(linedi + wpl, j, L_MIN(minval, val3));
00704             minval = L_MIN(val3, val4);
00705             SET_DATA_BYTE(linedi + 2 * wpl, j, L_MIN(val2, minval));
00706             SET_DATA_BYTE(linedi + 3 * wpl, j, L_MIN(minval, val5));
00707             minval = L_MIN(val5, val6);
00708             SET_DATA_BYTE(linedi + 4 * wpl, j, L_MIN(val4, minval));
00709             SET_DATA_BYTE(linedi + 5 * wpl, j, L_MIN(minval, val7));
00710             minval = L_MIN(val7, val8);
00711             SET_DATA_BYTE(linedi + 6 * wpl, j, L_MIN(val6, minval));
00712             SET_DATA_BYTE(linedi + 7 * wpl, j, L_MIN(minval, val9));
00713         }
00714     }
00715     return pixd;
00716 }
00717 
00718 
00719 /*!
00720  *  pixDilateGray3()
00721  *
00722  *      Input:  pixs (8 bpp, not cmapped)
00723  *              hsize  (1 or 3)
00724  *              vsize  (1 or 3)
00725  *      Return: pixd, or null on error
00726  *
00727  *  Notes:
00728  *      (1) Special case for 1x3, 3x1 or 3x3 brick sel (all hits)
00729  *      (2) If hsize = vsize = 1, just returns a copy.
00730  */
00731 PIX *
00732 pixDilateGray3(PIX     *pixs,
00733                l_int32  hsize,
00734                l_int32  vsize)
00735 {
00736 PIX  *pixt, *pixb, *pixbd, *pixd;
00737 
00738     PROCNAME("pixDilateGray3");
00739 
00740     if (!pixs)
00741         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00742     if (pixGetDepth(pixs) != 8)
00743         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00744     if (pixGetColormap(pixs))
00745         return (PIX *)ERROR_PTR("pix has colormap", procName, NULL);
00746     if ((hsize != 1 && hsize != 3) ||
00747         (vsize != 1 && vsize != 3))
00748         return (PIX *)ERROR_PTR("invalid size: must be 1 or 3", procName, NULL);
00749 
00750     if (hsize == 1 && vsize == 1)
00751         return pixCopy(NULL, pixs);
00752 
00753     pixb = pixAddBorderGeneral(pixs, 4, 8, 2, 8, 0);
00754 
00755     if (vsize == 1)
00756         pixbd = pixDilateGray3h(pixb);
00757     else if (hsize == 1)
00758         pixbd = pixDilateGray3v(pixb);
00759     else {  /* vize == hsize == 3 */
00760         pixt = pixDilateGray3h(pixb);
00761         pixbd = pixDilateGray3v(pixt);
00762         pixDestroy(&pixt);
00763     }
00764 
00765     pixd = pixRemoveBorderGeneral(pixbd, 4, 8, 2, 8);
00766     pixDestroy(&pixb);
00767     pixDestroy(&pixbd);
00768     return pixd;
00769 }
00770 
00771 
00772 /*!
00773  *  pixDilateGray3h()
00774  *
00775  *      Input:  pixs (8 bpp, not cmapped)
00776  *      Return: pixd, or null on error
00777  *
00778  *  Notes:
00779  *      (1) Special case for horizontal 3x1 brick Sel;
00780  *          also used as the first step for the 3x3 brick Sel.
00781  */
00782 static PIX *
00783 pixDilateGray3h(PIX  *pixs)
00784 {
00785 l_uint32  *datas, *datad, *lines, *lined;
00786 l_int32    w, h, wpl, i, j;
00787 l_int32    val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, maxval;
00788 PIX       *pixd;
00789 
00790     PROCNAME("pixDilateGray3h");
00791 
00792     if (!pixs)
00793         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00794     if (pixGetDepth(pixs) != 8)
00795         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00796 
00797     pixd = pixCreateTemplateNoInit(pixs);
00798     pixSetBorderVal(pixd, 4, 8, 2, 8, 0);  /* only to silence valgrind */
00799     pixGetDimensions(pixs, &w, &h, NULL);
00800     datas = pixGetData(pixs);
00801     datad = pixGetData(pixd);
00802     wpl = pixGetWpl(pixs);
00803     for (i = 0; i < h; i++) {
00804         lines = datas + i * wpl;
00805         lined = datad + i * wpl;
00806         for (j = 1; j < w - 8; j += 8) {
00807             val0 = GET_DATA_BYTE(lines, j - 1);
00808             val1 = GET_DATA_BYTE(lines, j);
00809             val2 = GET_DATA_BYTE(lines, j + 1);
00810             val3 = GET_DATA_BYTE(lines, j + 2);
00811             val4 = GET_DATA_BYTE(lines, j + 3);
00812             val5 = GET_DATA_BYTE(lines, j + 4);
00813             val6 = GET_DATA_BYTE(lines, j + 5);
00814             val7 = GET_DATA_BYTE(lines, j + 6);
00815             val8 = GET_DATA_BYTE(lines, j + 7);
00816             val9 = GET_DATA_BYTE(lines, j + 8);
00817             maxval = L_MAX(val1, val2);
00818             SET_DATA_BYTE(lined, j, L_MAX(val0, maxval));
00819             SET_DATA_BYTE(lined, j + 1, L_MAX(maxval, val3));
00820             maxval = L_MAX(val3, val4);
00821             SET_DATA_BYTE(lined, j + 2, L_MAX(val2, maxval));
00822             SET_DATA_BYTE(lined, j + 3, L_MAX(maxval, val5));
00823             maxval = L_MAX(val5, val6);
00824             SET_DATA_BYTE(lined, j + 4, L_MAX(val4, maxval));
00825             SET_DATA_BYTE(lined, j + 5, L_MAX(maxval, val7));
00826             maxval = L_MAX(val7, val8);
00827             SET_DATA_BYTE(lined, j + 6, L_MAX(val6, maxval));
00828             SET_DATA_BYTE(lined, j + 7, L_MAX(maxval, val9));
00829         }
00830     }
00831     return pixd;
00832 }
00833 
00834 
00835 /*!
00836  *  pixDilateGray3v()
00837  *
00838  *      Input:  pixs (8 bpp, not cmapped)
00839  *      Return: pixd, or null on error
00840  *
00841  *  Notes:
00842  *      (1) Special case for vertical 1x3 brick Sel;
00843  *          also used as the second step for the 3x3 brick Sel.
00844  */
00845 static PIX *
00846 pixDilateGray3v(PIX  *pixs)
00847 {
00848 l_uint32  *datas, *datad, *linesi, *linedi;
00849 l_int32    w, h, wpl, i, j;
00850 l_int32    val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, maxval;
00851 PIX       *pixd;
00852 
00853     PROCNAME("pixDilateGray3v");
00854 
00855     if (!pixs)
00856         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00857     if (pixGetDepth(pixs) != 8)
00858         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00859 
00860     pixd = pixCreateTemplateNoInit(pixs);
00861     pixGetDimensions(pixs, &w, &h, NULL);
00862     datas = pixGetData(pixs);
00863     datad = pixGetData(pixd);
00864     wpl = pixGetWpl(pixs);
00865     for (j = 0; j < w; j++) {
00866         for (i = 1; i < h - 8; i += 8) {
00867             linesi = datas + i * wpl;
00868             linedi = datad + i * wpl;
00869             val0 = GET_DATA_BYTE(linesi - wpl, j);
00870             val1 = GET_DATA_BYTE(linesi, j);
00871             val2 = GET_DATA_BYTE(linesi + wpl, j);
00872             val3 = GET_DATA_BYTE(linesi + 2 * wpl, j);
00873             val4 = GET_DATA_BYTE(linesi + 3 * wpl, j);
00874             val5 = GET_DATA_BYTE(linesi + 4 * wpl, j);
00875             val6 = GET_DATA_BYTE(linesi + 5 * wpl, j);
00876             val7 = GET_DATA_BYTE(linesi + 6 * wpl, j);
00877             val8 = GET_DATA_BYTE(linesi + 7 * wpl, j);
00878             val9 = GET_DATA_BYTE(linesi + 8 * wpl, j);
00879             maxval = L_MAX(val1, val2);
00880             SET_DATA_BYTE(linedi, j, L_MAX(val0, maxval));
00881             SET_DATA_BYTE(linedi + wpl, j, L_MAX(maxval, val3));
00882             maxval = L_MAX(val3, val4);
00883             SET_DATA_BYTE(linedi + 2 * wpl, j, L_MAX(val2, maxval));
00884             SET_DATA_BYTE(linedi + 3 * wpl, j, L_MAX(maxval, val5));
00885             maxval = L_MAX(val5, val6);
00886             SET_DATA_BYTE(linedi + 4 * wpl, j, L_MAX(val4, maxval));
00887             SET_DATA_BYTE(linedi + 5 * wpl, j, L_MAX(maxval, val7));
00888             maxval = L_MAX(val7, val8);
00889             SET_DATA_BYTE(linedi + 6 * wpl, j, L_MAX(val6, maxval));
00890             SET_DATA_BYTE(linedi + 7 * wpl, j, L_MAX(maxval, val9));
00891         }
00892     }
00893     return pixd;
00894 }
00895 
00896 
00897 /*!
00898  *  pixOpenGray3()
00899  *
00900  *      Input:  pixs (8 bpp, not cmapped)
00901  *              hsize  (1 or 3)
00902  *              vsize  (1 or 3)
00903  *      Return: pixd, or null on error
00904  *
00905  *  Notes:
00906  *      (1) Special case for 1x3, 3x1 or 3x3 brick sel (all hits)
00907  *      (2) If hsize = vsize = 1, just returns a copy.
00908  *      (3) It would be nice not to add a border, but it is required
00909  *          to get the same results as for the general case.
00910  */
00911 PIX *
00912 pixOpenGray3(PIX     *pixs,
00913              l_int32  hsize,
00914              l_int32  vsize)
00915 {
00916 PIX  *pixt, *pixb, *pixbd, *pixd;
00917 
00918     PROCNAME("pixOpenGray3");
00919 
00920     if (!pixs)
00921         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00922     if (pixGetDepth(pixs) != 8)
00923         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00924     if (pixGetColormap(pixs))
00925         return (PIX *)ERROR_PTR("pix has colormap", procName, NULL);
00926     if ((hsize != 1 && hsize != 3) ||
00927         (vsize != 1 && vsize != 3))
00928         return (PIX *)ERROR_PTR("invalid size: must be 1 or 3", procName, NULL);
00929 
00930     if (hsize == 1 && vsize == 1)
00931         return pixCopy(NULL, pixs);
00932 
00933     pixb = pixAddBorderGeneral(pixs, 4, 8, 2, 8, 255);  /* set to max */
00934 
00935     if (vsize == 1) {
00936         pixt = pixErodeGray3h(pixb);
00937         pixSetBorderVal(pixt, 4, 8, 2, 8, 0);  /* set to min */
00938         pixbd = pixDilateGray3h(pixt);
00939         pixDestroy(&pixt);
00940     }
00941     else if (hsize == 1) {
00942         pixt = pixErodeGray3v(pixb);
00943         pixSetBorderVal(pixt, 4, 8, 2, 8, 0);
00944         pixbd = pixDilateGray3v(pixt);
00945         pixDestroy(&pixt);
00946     }
00947     else {  /* vize == hsize == 3 */
00948         pixt = pixErodeGray3h(pixb);
00949         pixbd = pixErodeGray3v(pixt);
00950         pixDestroy(&pixt);
00951         pixSetBorderVal(pixbd, 4, 8, 2, 8, 0);
00952         pixt = pixDilateGray3h(pixbd);
00953         pixDestroy(&pixbd);
00954         pixbd = pixDilateGray3v(pixt);
00955         pixDestroy(&pixt);
00956     }
00957 
00958     pixd = pixRemoveBorderGeneral(pixbd, 4, 8, 2, 8);
00959     pixDestroy(&pixb);
00960     pixDestroy(&pixbd);
00961     return pixd;
00962 }
00963 
00964 
00965 /*!
00966  *  pixCloseGray3()
00967  *
00968  *      Input:  pixs (8 bpp, not cmapped)
00969  *              hsize  (1 or 3)
00970  *              vsize  (1 or 3)
00971  *      Return: pixd, or null on error
00972  *
00973  *  Notes:
00974  *      (1) Special case for 1x3, 3x1 or 3x3 brick sel (all hits)
00975  *      (2) If hsize = vsize = 1, just returns a copy.
00976  */
00977 PIX *
00978 pixCloseGray3(PIX     *pixs,
00979               l_int32  hsize,
00980               l_int32  vsize)
00981 {
00982 PIX  *pixt, *pixb, *pixbd, *pixd;
00983 
00984     PROCNAME("pixCloseGray3");
00985 
00986     if (!pixs)
00987         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00988     if (pixGetDepth(pixs) != 8)
00989         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00990     if (pixGetColormap(pixs))
00991         return (PIX *)ERROR_PTR("pix has colormap", procName, NULL);
00992     if ((hsize != 1 && hsize != 3) ||
00993         (vsize != 1 && vsize != 3))
00994         return (PIX *)ERROR_PTR("invalid size: must be 1 or 3", procName, NULL);
00995 
00996     if (hsize == 1 && vsize == 1)
00997         return pixCopy(NULL, pixs);
00998 
00999     pixb = pixAddBorderGeneral(pixs, 4, 8, 2, 8, 0);  /* set to min */
01000 
01001     if (vsize == 1) {
01002         pixt = pixDilateGray3h(pixb);
01003         pixSetBorderVal(pixt, 4, 8, 2, 8, 255);  /* set to max */
01004         pixbd = pixErodeGray3h(pixt);
01005         pixDestroy(&pixt);
01006     }
01007     else if (hsize == 1) {
01008         pixt = pixDilateGray3v(pixb);
01009         pixSetBorderVal(pixt, 4, 8, 2, 8, 255);
01010         pixbd = pixErodeGray3v(pixt);
01011         pixDestroy(&pixt);
01012     }
01013     else {  /* vize == hsize == 3 */
01014         pixt = pixDilateGray3h(pixb);
01015         pixbd = pixDilateGray3v(pixt);
01016         pixDestroy(&pixt);
01017         pixSetBorderVal(pixbd, 4, 8, 2, 8, 255);
01018         pixt = pixErodeGray3h(pixbd);
01019         pixDestroy(&pixbd);
01020         pixbd = pixErodeGray3v(pixt);
01021         pixDestroy(&pixt);
01022     }
01023 
01024     pixd = pixRemoveBorderGeneral(pixbd, 4, 8, 2, 8);
01025     pixDestroy(&pixb);
01026     pixDestroy(&pixbd);
01027     return pixd;
01028 }
01029 
01030 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines