Leptonica 1.68
C Image Processing Library

morphdwa.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  *  morphdwa.c
00018  *
00019  *    Binary morphological (dwa) ops with brick Sels
00020  *         PIX     *pixDilateBrickDwa()
00021  *         PIX     *pixErodeBrickDwa()
00022  *         PIX     *pixOpenBrickDwa()
00023  *         PIX     *pixCloseBrickDwa()
00024  *
00025  *    Binary composite morphological (dwa) ops with brick Sels
00026  *         PIX     *pixDilateCompBrickDwa()
00027  *         PIX     *pixErodeCompBrickDwa()
00028  *         PIX     *pixOpenCompBrickDwa()
00029  *         PIX     *pixCloseCompBrickDwa()
00030  *
00031  *    Binary extended composite morphological (dwa) ops with brick Sels
00032  *         PIX     *pixDilateCompBrickExtendDwa()
00033  *         PIX     *pixErodeCompBrickExtendDwa()
00034  *         PIX     *pixOpenCompBrickExtendDwa()
00035  *         PIX     *pixCloseCompBrickExtendDwa()
00036  *         l_int32  getExtendedCompositeParameters()
00037  *
00038  *    These are higher-level interfaces for dwa morphology with brick Sels.
00039  *    Because many morphological operations are performed using
00040  *    separable brick Sels, it is useful to have a simple interface
00041  *    for this.
00042  *
00043  *    We have included all 58 of the brick Sels that are generated
00044  *    by selaAddBasic().  These are sufficient for all the decomposable
00045  *    bricks up to size 63, which is the limit for dwa Sels with
00046  *    origins at the center of the Sel.
00047  *
00048  *    All three sets can be used as the basic interface for general
00049  *    brick operations.  Here are the internal calling sequences:
00050  *
00051  *      (1) If you try to apply a non-decomposable operation, such as
00052  *          pixErodeBrickDwa(), with a Sel size that doesn't exist,
00053  *          this calls a decomposable operation, pixErodeCompBrickDwa(),
00054  *          instead.  This can differ in linear Sel size by up to
00055  *          2 pixels from the request.
00056  *
00057  *      (2) If either Sel brick dimension is greater than 63, the extended
00058  *          composite function is called.
00059  *
00060  *      (3) The extended composite function calls the composite function
00061  *          a number of times with size 63, and once with size < 63.
00062  *          Because each operation with a size of 63 is done compositely
00063  *          with 7 x 9 (exactly 63), the net result is correct in
00064  *          length to within 2 pixels.
00065  *
00066  *    For composite operations, both using a comb and extended (beyond 63),
00067  *    horizontal and vertical operations are composed separately
00068  *    and sequentially.
00069  *
00070  *    We have also included use of all the 76 comb Sels that are generated
00071  *    by selaAddDwaCombs().  The generated code is in dwacomb.2.c
00072  *    and dwacomblow.2.c.  These are used for the composite dwa
00073  *    brick operations.
00074  *
00075  *    The non-composite brick operations, such as pixDilateBrickDwa(),
00076  *    will call the associated composite operation in situations where
00077  *    the requisite brick Sel has not been compiled into fmorphgen*.1.c.
00078  *
00079  *    If you want to use brick Sels that are not represented in the
00080  *    basic set of 58, you must generate the dwa code to implement them.
00081  *    You have three choices for how to use these:
00082  *
00083  *    (1) Add both the new Sels and the dwa code to the library:
00084  *        - For simplicity, add your new brick Sels to those defined
00085  *          in selaAddBasic().
00086  *        - Recompile the library.
00087  *        - Make prog/fmorphautogen.
00088  *        - Run prog/fmorphautogen, to generate new versions of the
00089  *          dwa code in fmorphgen.1.c and fmorphgenlow.1.c.
00090  *        - Copy these two files to src.
00091  *        - Recompile the library again.
00092  *        - Use the new brick Sels in your program and compile it.
00093  *
00094  *    (2) Make both the new Sels and dwa code outside the library,
00095  *        and link it directly to an executable:
00096  *        - Write a function to generate the new Sels in a Sela, and call
00097  *          fmorphautogen(sela, <N>, filename) to generate the code.
00098  *        - Compile your program that uses the newly generated function
00099  *          pixMorphDwa_<N>(), and link to the two new C files.
00100  *
00101  *    (3) Make the new Sels in the library and use the dwa code outside it:
00102  *        - Add code in the library to generate your new brick Sels.
00103  *          (It is suggested that you NOT add these Sels to the
00104  *          selaAddBasic() function; write a new function that generates
00105  *          a new Sela.)
00106  *        - Recompile the library.
00107  *        - Write a small program that generates the Sela and calls
00108  *          fmorphautogen(sela, <N>, filename) to generate the code.
00109  *        - Compile your program that uses the newly generated function
00110  *          pixMorphDwa_<N>(), and link to the two new C files.
00111  *       As an example of this approach, see prog/dwamorph*_reg.c:
00112  *        - added selaAddDwaLinear() to sel2.c
00113  *        - wrote dwamorph1_reg.c, to generate the dwa code.
00114  *        - compiled and linked the generated code with the application,
00115  *          dwamorph2_reg.c.  (Note: because this was a regression test,
00116  *          dwamorph1_reg also builds and runs the application program.)
00117  */
00118 
00119 #include <stdio.h>
00120 #include <stdlib.h>
00121 #include "allheaders.h"
00122 
00123 #ifndef  NO_CONSOLE_IO
00124 #define  DEBUG_SEL_LOOKUP   0
00125 #endif  /* ~NO_CONSOLE_IO */
00126 
00127 
00128 /*-----------------------------------------------------------------*
00129  *           Binary morphological (dwa) ops with brick Sels        *
00130  *-----------------------------------------------------------------*/
00131 /*!
00132  *  pixDilateBrickDwa()
00133  *
00134  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
00135  *                     or different from pixs)
00136  *              pixs (1 bpp)
00137  *              hsize (width of brick Sel)
00138  *              vsize (height of brick Sel)
00139  *      Return: pixd
00140  * 
00141  *  Notes:
00142  *      (1) These implement 2D brick Sels, using linear Sels generated
00143  *          with selaAddBasic().
00144  *      (2) A brick Sel has hits for all elements.
00145  *      (3) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
00146  *      (4) Do separably if both hsize and vsize are > 1.
00147  *      (5) It is necessary that both horizontal and vertical Sels
00148  *          of the input size are defined in the basic sela.
00149  *      (6) There are three cases:
00150  *          (a) pixd == null   (result into new pixd)
00151  *          (b) pixd == pixs   (in-place; writes result back to pixs)
00152  *          (c) pixd != pixs   (puts result into existing pixd)
00153  *      (7) For clarity, if the case is known, use these patterns:
00154  *          (a) pixd = pixDilateBrickDwa(NULL, pixs, ...);
00155  *          (b) pixDilateBrickDwa(pixs, pixs, ...);
00156  *          (c) pixDilateBrickDwa(pixd, pixs, ...);
00157  *      (8) The size of pixd is determined by pixs.
00158  *      (9) If either linear Sel is not found, this calls
00159  *          the appropriate decomposible function.
00160  */
00161 PIX *
00162 pixDilateBrickDwa(PIX     *pixd,
00163                   PIX     *pixs,
00164                   l_int32  hsize,
00165                   l_int32  vsize)
00166 {
00167 l_int32  found;
00168 char    *selnameh, *selnamev;
00169 SELA    *sela;
00170 PIX     *pixt1, *pixt2, *pixt3;
00171 
00172     PROCNAME("pixDilateBrickDwa");
00173 
00174     if (!pixs)
00175         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00176     if (pixGetDepth(pixs) != 1)
00177         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
00178     if (hsize < 1 || vsize < 1)
00179         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
00180 
00181     if (hsize == 1 && vsize == 1)
00182         return pixCopy(pixd, pixs);
00183 
00184     sela = selaAddBasic(NULL);
00185     found = TRUE;
00186     selnameh = selnamev = NULL;
00187     if (hsize > 1) {
00188         selnameh = selaGetBrickName(sela, hsize, 1);
00189         if (!selnameh) found = FALSE;
00190     }
00191     if (vsize > 1) {
00192         selnamev = selaGetBrickName(sela, 1, vsize);
00193         if (!selnamev) found = FALSE;
00194     }
00195     selaDestroy(&sela);
00196     if (!found) {
00197         L_INFO("Calling the decomposable dwa function", procName);
00198         if (selnameh) FREE(selnameh);
00199         if (selnamev) FREE(selnamev);
00200         return pixDilateCompBrickDwa(pixd, pixs, hsize, vsize);
00201     }
00202 
00203     if (vsize == 1) {
00204         pixt2 = pixMorphDwa_1(NULL, pixs, L_MORPH_DILATE, selnameh);
00205         FREE(selnameh);
00206     }
00207     else if (hsize == 1) {
00208         pixt2 = pixMorphDwa_1(NULL, pixs, L_MORPH_DILATE, selnamev);
00209         FREE(selnamev);
00210     }
00211     else {
00212         pixt1 = pixAddBorder(pixs, 32, 0);
00213         pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh);
00214         pixFMorphopGen_1(pixt1, pixt3, L_MORPH_DILATE, selnamev);
00215         pixt2 = pixRemoveBorder(pixt1, 32);
00216         pixDestroy(&pixt1);
00217         pixDestroy(&pixt3);
00218         FREE(selnameh);
00219         FREE(selnamev);
00220     }
00221 
00222     if (!pixd)
00223         return pixt2;
00224 
00225     pixTransferAllData(pixd, &pixt2, 0, 0);
00226     return pixd;
00227 }
00228 
00229 
00230 /*!
00231  *  pixErodeBrickDwa()
00232  *
00233  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
00234  *                     or different from pixs)
00235  *              pixs (1 bpp)
00236  *              hsize (width of brick Sel)
00237  *              vsize (height of brick Sel)
00238  *      Return: pixd
00239  * 
00240  *  Notes:
00241  *      (1) These implement 2D brick Sels, using linear Sels generated
00242  *          with selaAddBasic().
00243  *      (2) A brick Sel has hits for all elements.
00244  *      (3) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
00245  *      (4) Do separably if both hsize and vsize are > 1.
00246  *      (5) It is necessary that both horizontal and vertical Sels
00247  *          of the input size are defined in the basic sela.
00248  *      (6) Note that we must always set or clear the border pixels
00249  *          before each operation, depending on the the b.c.
00250  *          (symmetric or asymmetric).
00251  *      (7) There are three cases:
00252  *          (a) pixd == null   (result into new pixd)
00253  *          (b) pixd == pixs   (in-place; writes result back to pixs)
00254  *          (c) pixd != pixs   (puts result into existing pixd)
00255  *      (8) For clarity, if the case is known, use these patterns:
00256  *          (a) pixd = pixErodeBrickDwa(NULL, pixs, ...);
00257  *          (b) pixErodeBrickDwa(pixs, pixs, ...);
00258  *          (c) pixErodeBrickDwa(pixd, pixs, ...);
00259  *      (9) The size of the result is determined by pixs.
00260  *      (10) If either linear Sel is not found, this calls
00261  *           the appropriate decomposible function.
00262  */
00263 PIX *
00264 pixErodeBrickDwa(PIX     *pixd,
00265                  PIX     *pixs,
00266                  l_int32  hsize,
00267                  l_int32  vsize)
00268 {
00269 l_int32  found;
00270 char    *selnameh, *selnamev;
00271 SELA    *sela;
00272 PIX     *pixt1, *pixt2, *pixt3;
00273 
00274     PROCNAME("pixErodeBrickDwa");
00275 
00276     if (!pixs)
00277         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00278     if (pixGetDepth(pixs) != 1)
00279         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
00280     if (hsize < 1 || vsize < 1)
00281         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
00282 
00283     if (hsize == 1 && vsize == 1)
00284         return pixCopy(pixd, pixs);
00285 
00286     sela = selaAddBasic(NULL);
00287     found = TRUE;
00288     selnameh = selnamev = NULL;
00289     if (hsize > 1) {
00290         selnameh = selaGetBrickName(sela, hsize, 1);
00291         if (!selnameh) found = FALSE;
00292     }
00293     if (vsize > 1) {
00294         selnamev = selaGetBrickName(sela, 1, vsize);
00295         if (!selnamev) found = FALSE;
00296     }
00297     selaDestroy(&sela);
00298     if (!found) {
00299         L_INFO("Calling the decomposable dwa function", procName);
00300         if (selnameh) FREE(selnameh);
00301         if (selnamev) FREE(selnamev);
00302         return pixErodeCompBrickDwa(pixd, pixs, hsize, vsize);
00303     }
00304 
00305     if (vsize == 1) {
00306         pixt2 = pixMorphDwa_1(NULL, pixs, L_MORPH_ERODE, selnameh);
00307         FREE(selnameh);
00308     }
00309     else if (hsize == 1) {
00310         pixt2 = pixMorphDwa_1(NULL, pixs, L_MORPH_ERODE, selnamev);
00311         FREE(selnamev);
00312     }
00313     else {
00314         pixt1 = pixAddBorder(pixs, 32, 0);
00315         pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh);
00316         pixFMorphopGen_1(pixt1, pixt3, L_MORPH_ERODE, selnamev);
00317         pixt2 = pixRemoveBorder(pixt1, 32);
00318         pixDestroy(&pixt1);
00319         pixDestroy(&pixt3);
00320         FREE(selnameh);
00321         FREE(selnamev);
00322     }
00323 
00324     if (!pixd)
00325         return pixt2;
00326 
00327     pixTransferAllData(pixd, &pixt2, 0, 0);
00328     return pixd;
00329 }
00330 
00331 
00332 /*!
00333  *  pixOpenBrickDwa()
00334  *
00335  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
00336  *                     or different from pixs)
00337  *              pixs (1 bpp)
00338  *              hsize (width of brick Sel)
00339  *              vsize (height of brick Sel)
00340  *      Return: pixd
00341  * 
00342  *  Notes:
00343  *      (1) These implement 2D brick Sels, using linear Sels generated
00344  *          with selaAddBasic().
00345  *      (2) A brick Sel has hits for all elements.
00346  *      (3) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
00347  *      (4) Do separably if both hsize and vsize are > 1.
00348  *      (5) It is necessary that both horizontal and vertical Sels
00349  *          of the input size are defined in the basic sela.
00350  *      (6) Note that we must always set or clear the border pixels
00351  *          before each operation, depending on the the b.c.
00352  *          (symmetric or asymmetric).
00353  *      (7) There are three cases:
00354  *          (a) pixd == null   (result into new pixd)
00355  *          (b) pixd == pixs   (in-place; writes result back to pixs)
00356  *          (c) pixd != pixs   (puts result into existing pixd)
00357  *      (8) For clarity, if the case is known, use these patterns:
00358  *          (a) pixd = pixOpenBrickDwa(NULL, pixs, ...);
00359  *          (b) pixOpenBrickDwa(pixs, pixs, ...);
00360  *          (c) pixOpenBrickDwa(pixd, pixs, ...);
00361  *      (9) The size of the result is determined by pixs.
00362  *      (10) If either linear Sel is not found, this calls
00363  *           the appropriate decomposible function.
00364  */
00365 PIX *
00366 pixOpenBrickDwa(PIX     *pixd,
00367                 PIX     *pixs,
00368                 l_int32  hsize,
00369                 l_int32  vsize)
00370 {
00371 l_int32  found;
00372 char    *selnameh, *selnamev;
00373 SELA    *sela;
00374 PIX     *pixt1, *pixt2, *pixt3;
00375 
00376     PROCNAME("pixOpenBrickDwa");
00377 
00378     if (!pixs)
00379         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00380     if (pixGetDepth(pixs) != 1)
00381         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
00382     if (hsize < 1 || vsize < 1)
00383         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
00384 
00385     if (hsize == 1 && vsize == 1)
00386         return pixCopy(pixd, pixs);
00387 
00388     sela = selaAddBasic(NULL);
00389     found = TRUE;
00390     selnameh = selnamev = NULL;
00391     if (hsize > 1) {
00392         selnameh = selaGetBrickName(sela, hsize, 1);
00393         if (!selnameh) found = FALSE;
00394     }
00395     if (vsize > 1) {
00396         selnamev = selaGetBrickName(sela, 1, vsize);
00397         if (!selnamev) found = FALSE;
00398     }
00399     selaDestroy(&sela);
00400     if (!found) {
00401         L_INFO("Calling the decomposable dwa function", procName);
00402         if (selnameh) FREE(selnameh);
00403         if (selnamev) FREE(selnamev);
00404         return pixOpenCompBrickDwa(pixd, pixs, hsize, vsize);
00405     }
00406 
00407     pixt1 = pixAddBorder(pixs, 32, 0);
00408     if (vsize == 1) {   /* horizontal only */
00409         pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_OPEN, selnameh);
00410         FREE(selnameh);
00411     }
00412     else if (hsize == 1) {   /* vertical only */
00413         pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_OPEN, selnamev);
00414         FREE(selnamev);
00415     }
00416     else {  /* do separable */
00417         pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh);
00418         pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_ERODE, selnamev);
00419         pixFMorphopGen_1(pixt3, pixt2, L_MORPH_DILATE, selnameh);
00420         pixFMorphopGen_1(pixt2, pixt3, L_MORPH_DILATE, selnamev);
00421         FREE(selnameh);
00422         FREE(selnamev);
00423         pixDestroy(&pixt3);
00424     }
00425     pixt3 = pixRemoveBorder(pixt2, 32);
00426     pixDestroy(&pixt1);
00427     pixDestroy(&pixt2);
00428 
00429     if (!pixd)
00430         return pixt3;
00431 
00432     pixTransferAllData(pixd, &pixt3, 0, 0);
00433     return pixd;
00434 }
00435 
00436 
00437 /*!
00438  *  pixCloseBrickDwa()
00439  *
00440  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
00441  *                     or different from pixs)
00442  *              pixs (1 bpp)
00443  *              hsize (width of brick Sel)
00444  *              vsize (height of brick Sel)
00445  *      Return: pixd
00446  * 
00447  *  Notes:
00448  *      (1) This is a 'safe' closing; we add an extra border of 32 OFF
00449  *          pixels for the standard asymmetric b.c.
00450  *      (2) These implement 2D brick Sels, using linear Sels generated
00451  *          with selaAddBasic().
00452  *      (3) A brick Sel has hits for all elements.
00453  *      (4) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
00454  *      (5) Do separably if both hsize and vsize are > 1.
00455  *      (6) It is necessary that both horizontal and vertical Sels
00456  *          of the input size are defined in the basic sela.
00457  *      (7) Note that we must always set or clear the border pixels
00458  *          before each operation, depending on the the b.c.
00459  *          (symmetric or asymmetric).
00460  *      (8) There are three cases:
00461  *          (a) pixd == null   (result into new pixd)
00462  *          (b) pixd == pixs   (in-place; writes result back to pixs)
00463  *          (c) pixd != pixs   (puts result into existing pixd)
00464  *      (9) For clarity, if the case is known, use these patterns:
00465  *          (a) pixd = pixCloseBrickDwa(NULL, pixs, ...);
00466  *          (b) pixCloseBrickDwa(pixs, pixs, ...);
00467  *          (c) pixCloseBrickDwa(pixd, pixs, ...);
00468  *      (10) The size of the result is determined by pixs.
00469  *      (11) If either linear Sel is not found, this calls
00470  *           the appropriate decomposible function.
00471  */
00472 PIX *
00473 pixCloseBrickDwa(PIX     *pixd,
00474                  PIX     *pixs,
00475                  l_int32  hsize,
00476                  l_int32  vsize)
00477 {
00478 l_int32  bordercolor, bordersize, found;
00479 char    *selnameh, *selnamev;
00480 SELA    *sela;
00481 PIX     *pixt1, *pixt2, *pixt3;
00482 
00483     PROCNAME("pixCloseBrickDwa");
00484 
00485     if (!pixs)
00486         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00487     if (pixGetDepth(pixs) != 1)
00488         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
00489     if (hsize < 1 || vsize < 1)
00490         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
00491 
00492     if (hsize == 1 && vsize == 1)
00493         return pixCopy(pixd, pixs);
00494 
00495     sela = selaAddBasic(NULL);
00496     found = TRUE;
00497     selnameh = selnamev = NULL;
00498     if (hsize > 1) {
00499         selnameh = selaGetBrickName(sela, hsize, 1);
00500         if (!selnameh) found = FALSE;
00501     }
00502     if (vsize > 1) {
00503         selnamev = selaGetBrickName(sela, 1, vsize);
00504         if (!selnamev) found = FALSE;
00505     }
00506     selaDestroy(&sela);
00507     if (!found) {
00508         L_INFO("Calling the decomposable dwa function", procName);
00509         if (selnameh) FREE(selnameh);
00510         if (selnamev) FREE(selnamev);
00511         return pixCloseCompBrickDwa(pixd, pixs, hsize, vsize);
00512     }
00513 
00514         /* For "safe closing" with ASYMMETRIC_MORPH_BC, we always need
00515          * an extra 32 OFF pixels around the image (in addition to 
00516          * the 32 added pixels for all dwa operations), whereas with
00517          * SYMMETRIC_MORPH_BC this is not necessary. */
00518     bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1);
00519     if (bordercolor == 0)   /* asymmetric b.c. */
00520         bordersize = 64;
00521     else   /* symmetric b.c. */
00522         bordersize = 32;
00523     pixt1 = pixAddBorder(pixs, bordersize, 0);
00524 
00525     if (vsize == 1) {   /* horizontal only */
00526         pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_CLOSE, selnameh);
00527         FREE(selnameh);
00528     }
00529     else if (hsize == 1) {   /* vertical only */
00530         pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_CLOSE, selnamev);
00531         FREE(selnamev);
00532     }
00533     else {  /* do separable */
00534         pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh);
00535         pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_DILATE, selnamev);
00536         pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnameh);
00537         pixFMorphopGen_1(pixt2, pixt3, L_MORPH_ERODE, selnamev);
00538         FREE(selnameh);
00539         FREE(selnamev);
00540         pixDestroy(&pixt3);
00541     }
00542     pixt3 = pixRemoveBorder(pixt2, bordersize);
00543     pixDestroy(&pixt1);
00544     pixDestroy(&pixt2);
00545 
00546     if (!pixd)
00547         return pixt3;
00548 
00549     pixTransferAllData(pixd, &pixt3, 0, 0);
00550     return pixd;
00551 }
00552 
00553 
00554 /*-----------------------------------------------------------------*
00555  *    Binary composite morphological (dwa) ops with brick Sels     *
00556  *-----------------------------------------------------------------*/
00557 /*!
00558  *  pixDilateCompBrickDwa()
00559  *
00560  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
00561  *                     or different from pixs)
00562  *              pixs (1 bpp)
00563  *              hsize (width of brick Sel)
00564  *              vsize (height of brick Sel)
00565  *      Return: pixd
00566  * 
00567  *  Notes:
00568  *      (1) These implement a separable composite dilation with 2D brick Sels.
00569  *      (2) For efficiency, it may decompose each linear morphological
00570  *          operation into two (brick + comb).
00571  *      (3) A brick Sel has hits for all elements.
00572  *      (4) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
00573  *      (5) Do separably if both hsize and vsize are > 1.
00574  *      (6) It is necessary that both horizontal and vertical Sels
00575  *          of the input size are defined in the basic sela.
00576  *      (7) There are three cases:
00577  *          (a) pixd == null   (result into new pixd)
00578  *          (b) pixd == pixs   (in-place; writes result back to pixs)
00579  *          (c) pixd != pixs   (puts result into existing pixd)
00580  *      (8) For clarity, if the case is known, use these patterns:
00581  *          (a) pixd = pixDilateCompBrickDwa(NULL, pixs, ...);
00582  *          (b) pixDilateCompBrickDwa(pixs, pixs, ...);
00583  *          (c) pixDilateCompBrickDwa(pixd, pixs, ...);
00584  *      (9) The size of pixd is determined by pixs.
00585  *      (10) CAUTION: both hsize and vsize are being decomposed.
00586  *          The decomposer chooses a product of sizes (call them
00587  *          'terms') for each that is close to the input size,
00588  *           but not necessarily equal to it.  It attempts to optimize:
00589  *              (a) for consistency with the input values: the product
00590  *                  of terms is close to the input size
00591  *              (b) for efficiency of the operation: the sum of the
00592  *                  terms is small; ideally about twice the square
00593  *                   root of the input size.
00594  *           So, for example, if the input hsize = 37, which is
00595  *           a prime number, the decomposer will break this into two
00596  *           terms, 6 and 6, so that the net result is a dilation
00597  *           with hsize = 36.
00598  */
00599 PIX *
00600 pixDilateCompBrickDwa(PIX     *pixd,
00601                       PIX     *pixs,
00602                       l_int32  hsize,
00603                       l_int32  vsize)
00604 {
00605 char    *selnameh1, *selnameh2, *selnamev1, *selnamev2;
00606 l_int32  hsize1, hsize2, vsize1, vsize2;
00607 PIX     *pixt1, *pixt2, *pixt3;
00608 
00609     PROCNAME("pixDilateCompBrickDwa");
00610 
00611     if (!pixs)
00612         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00613     if (pixGetDepth(pixs) != 1)
00614         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
00615     if (hsize < 1 || vsize < 1)
00616         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
00617     if (hsize > 63 || vsize > 63)
00618         return pixDilateCompBrickExtendDwa(pixd, pixs, hsize, vsize);
00619 
00620     if (hsize == 1 && vsize == 1)
00621         return pixCopy(pixd, pixs);
00622 
00623     hsize1 = hsize2 = vsize1 = vsize2 = 1;
00624     selnameh1 = selnameh2 = selnamev1 = selnamev2 = NULL;
00625     if (hsize > 1)
00626         getCompositeParameters(hsize, &hsize1, &hsize2, &selnameh1,
00627                                &selnameh2, NULL, NULL);
00628     if (vsize > 1)
00629         getCompositeParameters(vsize, &vsize1, &vsize2, NULL, NULL,
00630                                &selnamev1, &selnamev2);
00631 
00632 #if DEBUG_SEL_LOOKUP
00633     fprintf(stderr, "nameh1=%s, nameh2=%s, namev1=%s, namev2=%s\n",
00634                     selnameh1, selnameh2, selnamev1, selnamev2);
00635     fprintf(stderr, "hsize1=%d, hsize2=%d, vsize1=%d, vsize2=%d\n",
00636                     hsize1, hsize2, vsize1, vsize2);
00637 #endif  /* DEBUG_SEL_LOOKUP */
00638 
00639     pixt1 = pixAddBorder(pixs, 64, 0);
00640     if (vsize == 1) {
00641         if (hsize2 == 1) 
00642             pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh1);
00643         else {
00644             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh1);
00645             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_DILATE, selnameh2);
00646             pixDestroy(&pixt3);
00647         }
00648     }
00649     else if (hsize == 1) {
00650         if (vsize2 == 1) 
00651             pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnamev1);
00652         else {
00653             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnamev1);
00654             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_DILATE, selnamev2);
00655             pixDestroy(&pixt3);
00656         }
00657     }
00658     else {  /* vsize and hsize both > 1 */
00659         if (hsize2 == 1) 
00660             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh1);
00661         else {
00662             pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh1);
00663             pixt3 = pixFMorphopGen_2(NULL, pixt2, L_MORPH_DILATE, selnameh2);
00664             pixDestroy(&pixt2);
00665         }
00666         if (vsize2 == 1) 
00667             pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_DILATE, selnamev1);
00668         else {
00669             pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_DILATE, selnamev1);
00670             pixFMorphopGen_2(pixt2, pixt2, L_MORPH_DILATE, selnamev2);
00671         }
00672         pixDestroy(&pixt3);
00673     }
00674     pixDestroy(&pixt1);
00675     pixt1 = pixRemoveBorder(pixt2, 64);
00676     pixDestroy(&pixt2);
00677     if (selnameh1) FREE(selnameh1);
00678     if (selnameh2) FREE(selnameh2);
00679     if (selnamev1) FREE(selnamev1);
00680     if (selnamev2) FREE(selnamev2);
00681 
00682     if (!pixd)
00683         return pixt1;
00684 
00685     pixTransferAllData(pixd, &pixt1, 0, 0);
00686     return pixd;
00687 }
00688 
00689 
00690 /*!
00691  *  pixErodeCompBrickDwa()
00692  *
00693  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
00694  *                     or different from pixs)
00695  *              pixs (1 bpp)
00696  *              hsize (width of brick Sel)
00697  *              vsize (height of brick Sel)
00698  *      Return: pixd
00699  * 
00700  *  Notes:
00701  *      (1) These implement a separable composite erosion with 2D brick Sels.
00702  *      (2) For efficiency, it may decompose each linear morphological
00703  *          operation into two (brick + comb).
00704  *      (3) A brick Sel has hits for all elements.
00705  *      (4) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
00706  *      (5) Do separably if both hsize and vsize are > 1.
00707  *      (6) It is necessary that both horizontal and vertical Sels
00708  *          of the input size are defined in the basic sela.
00709  *      (7) There are three cases:
00710  *          (a) pixd == null   (result into new pixd)
00711  *          (b) pixd == pixs   (in-place; writes result back to pixs)
00712  *          (c) pixd != pixs   (puts result into existing pixd)
00713  *      (8) For clarity, if the case is known, use these patterns:
00714  *          (a) pixd = pixErodeCompBrickDwa(NULL, pixs, ...);
00715  *          (b) pixErodeCompBrickDwa(pixs, pixs, ...);
00716  *          (c) pixErodeCompBrickDwa(pixd, pixs, ...);
00717  *      (9) The size of pixd is determined by pixs.
00718  *      (10) CAUTION: both hsize and vsize are being decomposed.
00719  *          The decomposer chooses a product of sizes (call them
00720  *          'terms') for each that is close to the input size,
00721  *           but not necessarily equal to it.  It attempts to optimize:
00722  *              (a) for consistency with the input values: the product
00723  *                  of terms is close to the input size
00724  *              (b) for efficiency of the operation: the sum of the
00725  *                  terms is small; ideally about twice the square
00726  *                   root of the input size.
00727  *           So, for example, if the input hsize = 37, which is
00728  *           a prime number, the decomposer will break this into two
00729  *           terms, 6 and 6, so that the net result is a dilation
00730  *           with hsize = 36.
00731  */
00732 PIX *
00733 pixErodeCompBrickDwa(PIX     *pixd,
00734                      PIX     *pixs,
00735                      l_int32  hsize,
00736                      l_int32  vsize)
00737 {
00738 char    *selnameh1, *selnameh2, *selnamev1, *selnamev2;
00739 l_int32  hsize1, hsize2, vsize1, vsize2, bordercolor;
00740 PIX     *pixt1, *pixt2, *pixt3;
00741 
00742     PROCNAME("pixErodeCompBrickDwa");
00743 
00744     if (!pixs)
00745         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00746     if (pixGetDepth(pixs) != 1)
00747         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
00748     if (hsize < 1 || vsize < 1)
00749         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
00750     if (hsize > 63 || vsize > 63)
00751         return pixErodeCompBrickExtendDwa(pixd, pixs, hsize, vsize);
00752 
00753     if (hsize == 1 && vsize == 1)
00754         return pixCopy(pixd, pixs);
00755 
00756     hsize1 = hsize2 = vsize1 = vsize2 = 1;
00757     selnameh1 = selnameh2 = selnamev1 = selnamev2 = NULL;
00758     if (hsize > 1)
00759         getCompositeParameters(hsize, &hsize1, &hsize2, &selnameh1,
00760                                &selnameh2, NULL, NULL);
00761     if (vsize > 1)
00762         getCompositeParameters(vsize, &vsize1, &vsize2, NULL, NULL,
00763                                &selnamev1, &selnamev2);
00764 
00765         /* For symmetric b.c., bordercolor == 1 for erosion */
00766     bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1);
00767     pixt1 = pixAddBorder(pixs, 64, bordercolor);
00768 
00769     if (vsize == 1) {
00770         if (hsize2 == 1) 
00771             pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh1);
00772         else {
00773             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh1);
00774             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_ERODE, selnameh2);
00775             pixDestroy(&pixt3);
00776         }
00777     }
00778     else if (hsize == 1) {
00779         if (vsize2 == 1) 
00780             pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnamev1);
00781         else {
00782             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnamev1);
00783             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_ERODE, selnamev2);
00784             pixDestroy(&pixt3);
00785         }
00786     }
00787     else {  /* vsize and hsize both > 1 */
00788         if (hsize2 == 1) 
00789             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh1);
00790         else {
00791             pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh1);
00792             pixt3 = pixFMorphopGen_2(NULL, pixt2, L_MORPH_ERODE, selnameh2);
00793             pixDestroy(&pixt2);
00794         }
00795         if (vsize2 == 1) 
00796             pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_ERODE, selnamev1);
00797         else {
00798             pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_ERODE, selnamev1);
00799             pixFMorphopGen_2(pixt2, pixt2, L_MORPH_ERODE, selnamev2);
00800         }
00801         pixDestroy(&pixt3);
00802     }
00803     pixDestroy(&pixt1);
00804     pixt1 = pixRemoveBorder(pixt2, 64);
00805     pixDestroy(&pixt2);
00806     if (selnameh1) FREE(selnameh1);
00807     if (selnameh2) FREE(selnameh2);
00808     if (selnamev1) FREE(selnamev1);
00809     if (selnamev2) FREE(selnamev2);
00810 
00811     if (!pixd)
00812         return pixt1;
00813 
00814     pixTransferAllData(pixd, &pixt1, 0, 0);
00815     return pixd;
00816 }
00817 
00818 
00819 /*!
00820  *  pixOpenCompBrickDwa()
00821  *
00822  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
00823  *                     or different from pixs)
00824  *              pixs (1 bpp)
00825  *              hsize (width of brick Sel)
00826  *              vsize (height of brick Sel)
00827  *      Return: pixd
00828  * 
00829  *  Notes:
00830  *      (1) These implement a separable composite opening with 2D brick Sels.
00831  *      (2) For efficiency, it may decompose each linear morphological
00832  *          operation into two (brick + comb).
00833  *      (3) A brick Sel has hits for all elements.
00834  *      (4) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
00835  *      (5) Do separably if both hsize and vsize are > 1.
00836  *      (6) It is necessary that both horizontal and vertical Sels
00837  *          of the input size are defined in the basic sela.
00838  *      (7) There are three cases:
00839  *          (a) pixd == null   (result into new pixd)
00840  *          (b) pixd == pixs   (in-place; writes result back to pixs)
00841  *          (c) pixd != pixs   (puts result into existing pixd)
00842  *      (8) For clarity, if the case is known, use these patterns:
00843  *          (a) pixd = pixOpenCompBrickDwa(NULL, pixs, ...);
00844  *          (b) pixOpenCompBrickDwa(pixs, pixs, ...);
00845  *          (c) pixOpenCompBrickDwa(pixd, pixs, ...);
00846  *      (9) The size of pixd is determined by pixs.
00847  *      (10) CAUTION: both hsize and vsize are being decomposed.
00848  *          The decomposer chooses a product of sizes (call them
00849  *          'terms') for each that is close to the input size,
00850  *           but not necessarily equal to it.  It attempts to optimize:
00851  *              (a) for consistency with the input values: the product
00852  *                  of terms is close to the input size
00853  *              (b) for efficiency of the operation: the sum of the
00854  *                  terms is small; ideally about twice the square
00855  *                   root of the input size.
00856  *           So, for example, if the input hsize = 37, which is
00857  *           a prime number, the decomposer will break this into two
00858  *           terms, 6 and 6, so that the net result is a dilation
00859  *           with hsize = 36.
00860  */
00861 PIX *
00862 pixOpenCompBrickDwa(PIX     *pixd,
00863                     PIX     *pixs,
00864                     l_int32  hsize,
00865                     l_int32  vsize)
00866 {
00867 char    *selnameh1, *selnameh2, *selnamev1, *selnamev2;
00868 l_int32  hsize1, hsize2, vsize1, vsize2, bordercolor;
00869 PIX     *pixt1, *pixt2, *pixt3;
00870 
00871     PROCNAME("pixOpenCompBrickDwa");
00872 
00873     if (!pixs)
00874         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
00875     if (pixGetDepth(pixs) != 1)
00876         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
00877     if (hsize < 1 || vsize < 1)
00878         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
00879     if (hsize > 63 || vsize > 63)
00880         return pixOpenCompBrickExtendDwa(pixd, pixs, hsize, vsize);
00881 
00882     if (hsize == 1 && vsize == 1)
00883         return pixCopy(pixd, pixs);
00884 
00885     hsize1 = hsize2 = vsize1 = vsize2 = 1;
00886     selnameh1 = selnameh2 = selnamev1 = selnamev2 = NULL;
00887     if (hsize > 1)
00888         getCompositeParameters(hsize, &hsize1, &hsize2, &selnameh1,
00889                                &selnameh2, NULL, NULL);
00890     if (vsize > 1)
00891         getCompositeParameters(vsize, &vsize1, &vsize2, NULL, NULL,
00892                                &selnamev1, &selnamev2);
00893 
00894         /* For symmetric b.c., initialize erosion with bordercolor == 1 */
00895     bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1);
00896     pixt1 = pixAddBorder(pixs, 64, bordercolor);
00897 
00898     if (vsize == 1) {
00899         if (hsize2 == 1) {
00900             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh1);
00901             if (bordercolor == 1)
00902                 pixSetOrClearBorder(pixt3, 64, 64, 64, 64, PIX_CLR);
00903             pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_DILATE, selnameh1);
00904         }
00905         else {
00906             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh1);
00907             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_ERODE, selnameh2);
00908             if (bordercolor == 1)
00909                 pixSetOrClearBorder(pixt2, 64, 64, 64, 64, PIX_CLR);
00910             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_DILATE, selnameh1);
00911             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_DILATE, selnameh2);
00912         }
00913     }
00914     else if (hsize == 1) {
00915         if (vsize2 == 1)  {
00916             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnamev1);
00917             if (bordercolor == 1)
00918                 pixSetOrClearBorder(pixt3, 64, 64, 64, 64, PIX_CLR);
00919             pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_DILATE, selnamev1);
00920         }
00921         else {
00922             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnamev1);
00923             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_ERODE, selnamev2);
00924             if (bordercolor == 1)
00925                 pixSetOrClearBorder(pixt2, 64, 64, 64, 64, PIX_CLR);
00926             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_DILATE, selnamev1);
00927             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_DILATE, selnamev2);
00928         }
00929     }
00930     else {  /* vsize and hsize both > 1 */
00931         if (hsize2 == 1 && vsize2 == 1) {
00932             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh1);
00933             pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_ERODE, selnamev1);
00934             if (bordercolor == 1)
00935                 pixSetOrClearBorder(pixt2, 64, 64, 64, 64, PIX_CLR);
00936             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_DILATE, selnameh1);
00937             pixFMorphopGen_1(pixt2, pixt3, L_MORPH_DILATE, selnamev1);
00938         }
00939         else if (vsize2 == 1) {
00940             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh1);
00941             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_ERODE, selnameh2);
00942             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnamev1);
00943             if (bordercolor == 1)
00944                 pixSetOrClearBorder(pixt3, 64, 64, 64, 64, PIX_CLR);
00945             pixFMorphopGen_1(pixt2, pixt3, L_MORPH_DILATE, selnameh1);
00946             pixFMorphopGen_2(pixt3, pixt2, L_MORPH_DILATE, selnameh2);
00947             pixFMorphopGen_1(pixt2, pixt3, L_MORPH_DILATE, selnamev1);
00948         }
00949         else if (hsize2 == 1) {
00950             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh1);
00951             pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_ERODE, selnamev1);
00952             pixFMorphopGen_2(pixt3, pixt2, L_MORPH_ERODE, selnamev2);
00953             if (bordercolor == 1)
00954                 pixSetOrClearBorder(pixt3, 64, 64, 64, 64, PIX_CLR);
00955             pixFMorphopGen_1(pixt2, pixt3, L_MORPH_DILATE, selnameh1);
00956             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_DILATE, selnamev1);
00957             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_DILATE, selnamev2);
00958         }
00959         else {   /* both directions are combed */
00960             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_ERODE, selnameh1);
00961             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_ERODE, selnameh2);
00962             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnamev1);
00963             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_ERODE, selnamev2);
00964             if (bordercolor == 1)
00965                 pixSetOrClearBorder(pixt2, 64, 64, 64, 64, PIX_CLR);
00966             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_DILATE, selnameh1);
00967             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_DILATE, selnameh2);
00968             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_DILATE, selnamev1);
00969             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_DILATE, selnamev2);
00970         }
00971     }
00972     pixDestroy(&pixt3);
00973 
00974     pixDestroy(&pixt1);
00975     pixt1 = pixRemoveBorder(pixt2, 64);
00976     pixDestroy(&pixt2);
00977     if (selnameh1) FREE(selnameh1);
00978     if (selnameh2) FREE(selnameh2);
00979     if (selnamev1) FREE(selnamev1);
00980     if (selnamev2) FREE(selnamev2);
00981 
00982     if (!pixd)
00983         return pixt1;
00984 
00985     pixTransferAllData(pixd, &pixt1, 0, 0);
00986     return pixd;
00987 }
00988 
00989 
00990 /*!
00991  *  pixCloseCompBrickDwa()
00992  *
00993  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
00994  *                     or different from pixs)
00995  *              pixs (1 bpp)
00996  *              hsize (width of brick Sel)
00997  *              vsize (height of brick Sel)
00998  *      Return: pixd
00999  * 
01000  *  Notes:
01001  *      (1) This implements a separable composite safe closing with 2D
01002  *          brick Sels.
01003  *      (2) For efficiency, it may decompose each linear morphological
01004  *          operation into two (brick + comb).
01005  *      (3) A brick Sel has hits for all elements.
01006  *      (4) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
01007  *      (5) Do separably if both hsize and vsize are > 1.
01008  *      (6) It is necessary that both horizontal and vertical Sels
01009  *          of the input size are defined in the basic sela.
01010  *      (7) There are three cases:
01011  *          (a) pixd == null   (result into new pixd)
01012  *          (b) pixd == pixs   (in-place; writes result back to pixs)
01013  *          (c) pixd != pixs   (puts result into existing pixd)
01014  *      (8) For clarity, if the case is known, use these patterns:
01015  *          (a) pixd = pixCloseCompBrickDwa(NULL, pixs, ...);
01016  *          (b) pixCloseCompBrickDwa(pixs, pixs, ...);
01017  *          (c) pixCloseCompBrickDwa(pixd, pixs, ...);
01018  *      (9) The size of pixd is determined by pixs.
01019  *      (10) CAUTION: both hsize and vsize are being decomposed.
01020  *          The decomposer chooses a product of sizes (call them
01021  *          'terms') for each that is close to the input size,
01022  *           but not necessarily equal to it.  It attempts to optimize:
01023  *              (a) for consistency with the input values: the product
01024  *                  of terms is close to the input size
01025  *              (b) for efficiency of the operation: the sum of the
01026  *                  terms is small; ideally about twice the square
01027  *                   root of the input size.
01028  *           So, for example, if the input hsize = 37, which is
01029  *           a prime number, the decomposer will break this into two
01030  *           terms, 6 and 6, so that the net result is a dilation
01031  *           with hsize = 36.
01032  */
01033 PIX *
01034 pixCloseCompBrickDwa(PIX     *pixd,
01035                      PIX     *pixs,
01036                      l_int32  hsize,
01037                      l_int32  vsize)
01038 {
01039 char    *selnameh1, *selnameh2, *selnamev1, *selnamev2;
01040 l_int32  hsize1, hsize2, vsize1, vsize2, setborder;
01041 PIX     *pixt1, *pixt2, *pixt3;
01042 
01043     PROCNAME("pixCloseCompBrickDwa");
01044 
01045     if (!pixs)
01046         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
01047     if (pixGetDepth(pixs) != 1)
01048         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
01049     if (hsize < 1 || vsize < 1)
01050         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
01051     if (hsize > 63 || vsize > 63)
01052         return pixCloseCompBrickExtendDwa(pixd, pixs, hsize, vsize);
01053 
01054     if (hsize == 1 && vsize == 1)
01055         return pixCopy(pixd, pixs);
01056 
01057     hsize1 = hsize2 = vsize1 = vsize2 = 1;
01058     selnameh1 = selnameh2 = selnamev1 = selnamev2 = NULL;
01059     if (hsize > 1)
01060         getCompositeParameters(hsize, &hsize1, &hsize2, &selnameh1,
01061                                &selnameh2, NULL, NULL);
01062     if (vsize > 1)
01063         getCompositeParameters(vsize, &vsize1, &vsize2, NULL, NULL,
01064                                &selnamev1, &selnamev2);
01065 
01066     pixt3 = NULL;
01067         /* For symmetric b.c., PIX_SET border for erosions */
01068     setborder = getMorphBorderPixelColor(L_MORPH_ERODE, 1);
01069     pixt1 = pixAddBorder(pixs, 64, 0);
01070 
01071     if (vsize == 1) {
01072         if (hsize2 == 1)
01073             pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_CLOSE, selnameh1);
01074         else {
01075             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh1);
01076             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_DILATE, selnameh2);
01077             if (setborder == 1)
01078                 pixSetOrClearBorder(pixt2, 64, 64, 64, 64, PIX_SET);
01079             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnameh1);
01080             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_ERODE, selnameh2);
01081         }
01082     }
01083     else if (hsize == 1) {
01084         if (vsize2 == 1)
01085             pixt2 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_CLOSE, selnamev1);
01086         else {
01087             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnamev1);
01088             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_DILATE, selnamev2);
01089             if (setborder == 1)
01090                 pixSetOrClearBorder(pixt2, 64, 64, 64, 64, PIX_SET);
01091             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnamev1);
01092             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_ERODE, selnamev2);
01093         }
01094     }
01095     else {  /* vsize and hsize both > 1 */
01096         if (hsize2 == 1 && vsize2 == 1) {
01097             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh1);
01098             pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_DILATE, selnamev1);
01099             if (setborder == 1)
01100                 pixSetOrClearBorder(pixt2, 64, 64, 64, 64, PIX_SET);
01101             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnameh1);
01102             pixFMorphopGen_1(pixt2, pixt3, L_MORPH_ERODE, selnamev1);
01103         }
01104         else if (vsize2 == 1) {
01105             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh1);
01106             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_DILATE, selnameh2);
01107             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_DILATE, selnamev1);
01108             if (setborder == 1)
01109                 pixSetOrClearBorder(pixt3, 64, 64, 64, 64, PIX_SET);
01110             pixFMorphopGen_1(pixt2, pixt3, L_MORPH_ERODE, selnameh1);
01111             pixFMorphopGen_2(pixt3, pixt2, L_MORPH_ERODE, selnameh2);
01112             pixFMorphopGen_1(pixt2, pixt3, L_MORPH_ERODE, selnamev1);
01113         }
01114         else if (hsize2 == 1) {
01115             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh1);
01116             pixt2 = pixFMorphopGen_1(NULL, pixt3, L_MORPH_DILATE, selnamev1);
01117             pixFMorphopGen_2(pixt3, pixt2, L_MORPH_DILATE, selnamev2);
01118             if (setborder == 1)
01119                 pixSetOrClearBorder(pixt3, 64, 64, 64, 64, PIX_SET);
01120             pixFMorphopGen_1(pixt2, pixt3, L_MORPH_ERODE, selnameh1);
01121             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnamev1);
01122             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_ERODE, selnamev2);
01123         }
01124         else {   /* both directions are combed */
01125             pixt3 = pixFMorphopGen_1(NULL, pixt1, L_MORPH_DILATE, selnameh1);
01126             pixt2 = pixFMorphopGen_2(NULL, pixt3, L_MORPH_DILATE, selnameh2);
01127             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_DILATE, selnamev1);
01128             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_DILATE, selnamev2);
01129             if (setborder == 1)
01130                 pixSetOrClearBorder(pixt2, 64, 64, 64, 64, PIX_SET);
01131             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnameh1);
01132             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_ERODE, selnameh2);
01133             pixFMorphopGen_1(pixt3, pixt2, L_MORPH_ERODE, selnamev1);
01134             pixFMorphopGen_2(pixt2, pixt3, L_MORPH_ERODE, selnamev2);
01135         }
01136     }
01137     pixDestroy(&pixt3);
01138 
01139     pixDestroy(&pixt1);
01140     pixt1 = pixRemoveBorder(pixt2, 64);
01141     pixDestroy(&pixt2);
01142     if (selnameh1) FREE(selnameh1);
01143     if (selnameh2) FREE(selnameh2);
01144     if (selnamev1) FREE(selnamev1);
01145     if (selnamev2) FREE(selnamev2);
01146 
01147     if (!pixd)
01148         return pixt1;
01149 
01150     pixTransferAllData(pixd, &pixt1, 0, 0);
01151     return pixd;
01152 }
01153 
01154 
01155 /*--------------------------------------------------------------------------*
01156  *    Binary expanded composite morphological (dwa) ops with brick Sels     *
01157  *--------------------------------------------------------------------------*/
01158 /*!
01159  *  pixDilateCompBrickExtendDwa()
01160  *
01161  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
01162  *                     or different from pixs)
01163  *              pixs (1 bpp)
01164  *              hsize (width of brick Sel)
01165  *              vsize (height of brick Sel)
01166  *      Return: pixd
01167  * 
01168  *  Notes:
01169  *      (1) Ankur Jain suggested and implemented extending the composite
01170  *          DWA operations beyond the 63 pixel limit.  This is a
01171  *          simplified and approximate implementation of the extension.
01172  *          This allows arbitrary Dwa morph operations using brick Sels,
01173  *          by decomposing the horizontal and vertical dilations into
01174  *          a sequence of 63-element dilations plus a dilation of size
01175  *          between 3 and 62.
01176  *      (2) The 63-element dilations are exact, whereas the extra dilation
01177  *          is approximate, because the underlying decomposition is
01178  *          in pixDilateCompBrickDwa().  See there for further details.
01179  *      (3) There are three cases:
01180  *          (a) pixd == null   (result into new pixd)
01181  *          (b) pixd == pixs   (in-place; writes result back to pixs)
01182  *          (c) pixd != pixs   (puts result into existing pixd)
01183  *      (4) There is no need to call this directly:  pixDilateCompBrickDwa()
01184  *          calls this function if either brick dimension exceeds 63.
01185  */
01186 PIX *
01187 pixDilateCompBrickExtendDwa(PIX     *pixd,
01188                             PIX     *pixs,
01189                             l_int32  hsize,
01190                             l_int32  vsize)
01191 {
01192 l_int32  i, nops, nh, extrah, nv, extrav;
01193 PIX     *pixt1, *pixt2, *pixt3;
01194 
01195     PROCNAME("pixDilateCompBrickExtendDwa");
01196 
01197     if (!pixs)
01198         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
01199     if (pixGetDepth(pixs) != 1)
01200         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
01201     if (hsize < 1 || vsize < 1)
01202         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
01203 
01204     if (hsize < 64 && vsize < 64)
01205         return pixDilateCompBrickDwa(pixd, pixs, hsize, vsize);
01206 
01207     if (hsize > 63)
01208         getExtendedCompositeParameters(hsize, &nh, &extrah, NULL);
01209     if (vsize > 63)
01210         getExtendedCompositeParameters(vsize, &nv, &extrav, NULL);
01211 
01212         /* Horizontal dilation first: pixs --> pixt2.  Do not alter pixs. */
01213     pixt1 = pixCreateTemplateNoInit(pixs);  /* temp image */
01214     if (hsize == 1)
01215         pixt2 = pixClone(pixs);
01216     else if (hsize < 64)
01217         pixt2 = pixDilateCompBrickDwa(NULL, pixs, hsize, 1);
01218     else if (hsize == 64)  /* approximate */
01219         pixt2 = pixDilateCompBrickDwa(NULL, pixs, 63, 1);
01220     else {
01221         nops = (extrah < 3) ? nh : nh + 1;
01222         if (nops & 1) {  /* odd */
01223             if (extrah > 2)
01224                 pixt2 = pixDilateCompBrickDwa(NULL, pixs, extrah, 1);
01225             else
01226                 pixt2 = pixDilateCompBrickDwa(NULL, pixs, 63, 1);
01227             for (i = 0; i < nops / 2; i++) {
01228                 pixDilateCompBrickDwa(pixt1, pixt2, 63, 1);
01229                 pixDilateCompBrickDwa(pixt2, pixt1, 63, 1);
01230             }
01231         }
01232         else {  /* nops even */
01233             if (extrah > 2) {
01234                 pixDilateCompBrickDwa(pixt1, pixs, extrah, 1);
01235                 pixt2 = pixDilateCompBrickDwa(NULL, pixt1, 63, 1);
01236             }
01237             else {  /* they're all 63s */
01238                 pixDilateCompBrickDwa(pixt1, pixs, 63, 1);
01239                 pixt2 = pixDilateCompBrickDwa(NULL, pixt1, 63, 1);
01240             }
01241             for (i = 0; i < nops / 2 - 1; i++) {
01242                 pixDilateCompBrickDwa(pixt1, pixt2, 63, 1);
01243                 pixDilateCompBrickDwa(pixt2, pixt1, 63, 1);
01244             }
01245         }
01246     }
01247 
01248         /* Vertical dilation: pixt2 --> pixt3.  */
01249     if (vsize == 1)
01250         pixt3 = pixClone(pixt2);
01251     else if (vsize < 64)
01252         pixt3 = pixDilateCompBrickDwa(NULL, pixt2, 1, vsize);
01253     else if (vsize == 64)  /* approximate */
01254         pixt3 = pixDilateCompBrickDwa(NULL, pixt2, 1, 63);
01255     else {
01256         nops = (extrav < 3) ? nv : nv + 1;
01257         if (nops & 1) {  /* odd */
01258             if (extrav > 2)
01259                 pixt3 = pixDilateCompBrickDwa(NULL, pixt2, 1, extrav);
01260             else
01261                 pixt3 = pixDilateCompBrickDwa(NULL, pixt2, 1, 63);
01262             for (i = 0; i < nops / 2; i++) {
01263                 pixDilateCompBrickDwa(pixt1, pixt3, 1, 63);
01264                 pixDilateCompBrickDwa(pixt3, pixt1, 1, 63);
01265             }
01266         }
01267         else {  /* nops even */
01268             if (extrav > 2) {
01269                 pixDilateCompBrickDwa(pixt1, pixt2, 1, extrav);
01270                 pixt3 = pixDilateCompBrickDwa(NULL, pixt1, 1, 63);
01271             }
01272             else {  /* they're all 63s */
01273                 pixDilateCompBrickDwa(pixt1, pixt2, 1, 63);
01274                 pixt3 = pixDilateCompBrickDwa(NULL, pixt1, 1, 63);
01275             }
01276             for (i = 0; i < nops / 2 - 1; i++) {
01277                 pixDilateCompBrickDwa(pixt1, pixt3, 1, 63);
01278                 pixDilateCompBrickDwa(pixt3, pixt1, 1, 63);
01279             }
01280         }
01281     }
01282     pixDestroy(&pixt1);
01283     pixDestroy(&pixt2);
01284 
01285     if (!pixd)
01286         return pixt3;
01287 
01288     pixTransferAllData(pixd, &pixt3, 0, 0);
01289     return pixd;
01290 }
01291 
01292 
01293 /*!
01294  *  pixErodeCompBrickExtendDwa()
01295  *
01296  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
01297  *                     or different from pixs)
01298  *              pixs (1 bpp)
01299  *              hsize (width of brick Sel)
01300  *              vsize (height of brick Sel)
01301  *      Return: pixd
01302  * 
01303  *  Notes:
01304  *      (1) See pixDilateCompBrickExtendDwa() for usage.
01305  *      (2) There is no need to call this directly:  pixErodeCompBrickDwa()
01306  *          calls this function if either brick dimension exceeds 63.
01307  */
01308 PIX *
01309 pixErodeCompBrickExtendDwa(PIX     *pixd,
01310                            PIX     *pixs,
01311                            l_int32  hsize,
01312                            l_int32  vsize)
01313 {
01314 l_int32  i, nops, nh, extrah, nv, extrav;
01315 PIX     *pixt1, *pixt2, *pixt3;
01316 
01317     PROCNAME("pixErodeCompBrickExtendDwa");
01318 
01319     if (!pixs)
01320         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
01321     if (pixGetDepth(pixs) != 1)
01322         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
01323     if (hsize < 1 || vsize < 1)
01324         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
01325 
01326     if (hsize < 64 && vsize < 64)
01327         return pixErodeCompBrickDwa(pixd, pixs, hsize, vsize);
01328 
01329     if (hsize > 63)
01330         getExtendedCompositeParameters(hsize, &nh, &extrah, NULL);
01331     if (vsize > 63)
01332         getExtendedCompositeParameters(vsize, &nv, &extrav, NULL);
01333 
01334         /* Horizontal erosion first: pixs --> pixt2.  Do not alter pixs. */
01335     pixt1 = pixCreateTemplateNoInit(pixs);  /* temp image */
01336     if (hsize == 1)
01337         pixt2 = pixClone(pixs);
01338     else if (hsize < 64)
01339         pixt2 = pixErodeCompBrickDwa(NULL, pixs, hsize, 1);
01340     else if (hsize == 64)  /* approximate */
01341         pixt2 = pixErodeCompBrickDwa(NULL, pixs, 63, 1);
01342     else {
01343         nops = (extrah < 3) ? nh : nh + 1;
01344         if (nops & 1) {  /* odd */
01345             if (extrah > 2)
01346                 pixt2 = pixErodeCompBrickDwa(NULL, pixs, extrah, 1);
01347             else
01348                 pixt2 = pixErodeCompBrickDwa(NULL, pixs, 63, 1);
01349             for (i = 0; i < nops / 2; i++) {
01350                 pixErodeCompBrickDwa(pixt1, pixt2, 63, 1);
01351                 pixErodeCompBrickDwa(pixt2, pixt1, 63, 1);
01352             }
01353         }
01354         else {  /* nops even */
01355             if (extrah > 2) {
01356                 pixErodeCompBrickDwa(pixt1, pixs, extrah, 1);
01357                 pixt2 = pixErodeCompBrickDwa(NULL, pixt1, 63, 1);
01358             }
01359             else {  /* they're all 63s */
01360                 pixErodeCompBrickDwa(pixt1, pixs, 63, 1);
01361                 pixt2 = pixErodeCompBrickDwa(NULL, pixt1, 63, 1);
01362             }
01363             for (i = 0; i < nops / 2 - 1; i++) {
01364                 pixErodeCompBrickDwa(pixt1, pixt2, 63, 1);
01365                 pixErodeCompBrickDwa(pixt2, pixt1, 63, 1);
01366             }
01367         }
01368     }
01369 
01370         /* Vertical erosion: pixt2 --> pixt3.  */
01371     if (vsize == 1)
01372         pixt3 = pixClone(pixt2);
01373     else if (vsize < 64)
01374         pixt3 = pixErodeCompBrickDwa(NULL, pixt2, 1, vsize);
01375     else if (vsize == 64)  /* approximate */
01376         pixt3 = pixErodeCompBrickDwa(NULL, pixt2, 1, 63);
01377     else {
01378         nops = (extrav < 3) ? nv : nv + 1;
01379         if (nops & 1) {  /* odd */
01380             if (extrav > 2)
01381                 pixt3 = pixErodeCompBrickDwa(NULL, pixt2, 1, extrav);
01382             else
01383                 pixt3 = pixErodeCompBrickDwa(NULL, pixt2, 1, 63);
01384             for (i = 0; i < nops / 2; i++) {
01385                 pixErodeCompBrickDwa(pixt1, pixt3, 1, 63);
01386                 pixErodeCompBrickDwa(pixt3, pixt1, 1, 63);
01387             }
01388         }
01389         else {  /* nops even */
01390             if (extrav > 2) {
01391                 pixErodeCompBrickDwa(pixt1, pixt2, 1, extrav);
01392                 pixt3 = pixErodeCompBrickDwa(NULL, pixt1, 1, 63);
01393             }
01394             else {  /* they're all 63s */
01395                 pixErodeCompBrickDwa(pixt1, pixt2, 1, 63);
01396                 pixt3 = pixErodeCompBrickDwa(NULL, pixt1, 1, 63);
01397             }
01398             for (i = 0; i < nops / 2 - 1; i++) {
01399                 pixErodeCompBrickDwa(pixt1, pixt3, 1, 63);
01400                 pixErodeCompBrickDwa(pixt3, pixt1, 1, 63);
01401             }
01402         }
01403     }
01404     pixDestroy(&pixt1);
01405     pixDestroy(&pixt2);
01406 
01407     if (!pixd)
01408         return pixt3;
01409 
01410     pixTransferAllData(pixd, &pixt3, 0, 0);
01411     return pixd;
01412 }
01413 
01414 
01415 /*!
01416  *  pixOpenCompBrickExtendDwa()
01417  *
01418  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
01419  *                     or different from pixs)
01420  *              pixs (1 bpp)
01421  *              hsize (width of brick Sel)
01422  *              vsize (height of brick Sel)
01423  *      Return: pixd
01424  * 
01425  *      (1) There are three cases:
01426  *          (a) pixd == null   (result into new pixd)
01427  *          (b) pixd == pixs   (in-place; writes result back to pixs)
01428  *          (c) pixd != pixs   (puts result into existing pixd)
01429  *      (2) There is no need to call this directly:  pixOpenCompBrickDwa()
01430  *          calls this function if either brick dimension exceeds 63.
01431  */
01432 PIX *
01433 pixOpenCompBrickExtendDwa(PIX     *pixd,
01434                           PIX     *pixs,
01435                           l_int32  hsize,
01436                           l_int32  vsize)
01437 {
01438 PIX     *pixt;
01439 
01440     PROCNAME("pixOpenCompBrickExtendDwa");
01441 
01442     if (!pixs)
01443         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
01444     if (pixGetDepth(pixs) != 1)
01445         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
01446     if (hsize < 1 || vsize < 1)
01447         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
01448 
01449     pixt = pixErodeCompBrickExtendDwa(NULL, pixs, hsize, vsize);
01450     pixd = pixDilateCompBrickExtendDwa(pixd, pixt, hsize, vsize);
01451     pixDestroy(&pixt);
01452     return pixd;
01453 }
01454 
01455 
01456 /*!
01457  *  pixCloseCompBrickExtendDwa()
01458  *
01459  *      Input:  pixd  (<optional>; this can be null, equal to pixs,
01460  *                     or different from pixs)
01461  *              pixs (1 bpp)
01462  *              hsize (width of brick Sel)
01463  *              vsize (height of brick Sel)
01464  *      Return: pixd
01465  * 
01466  *      (1) There are three cases:
01467  *          (a) pixd == null   (result into new pixd)
01468  *          (b) pixd == pixs   (in-place; writes result back to pixs)
01469  *          (c) pixd != pixs   (puts result into existing pixd)
01470  *      (2) There is no need to call this directly:  pixCloseCompBrickDwa()
01471  *          calls this function if either brick dimension exceeds 63.
01472  */
01473 PIX *
01474 pixCloseCompBrickExtendDwa(PIX     *pixd,
01475                            PIX     *pixs,
01476                            l_int32  hsize,
01477                            l_int32  vsize)
01478 {
01479 l_int32  bordercolor, borderx, bordery;
01480 PIX     *pixt1, *pixt2, *pixt3;
01481 
01482     PROCNAME("pixCloseCompBrickExtendDwa");
01483 
01484     if (!pixs)
01485         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
01486     if (pixGetDepth(pixs) != 1)
01487         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
01488     if (hsize < 1 || vsize < 1)
01489         return (PIX *)ERROR_PTR("hsize and vsize not >= 1", procName, pixd);
01490 
01491         /* For "safe closing" with ASYMMETRIC_MORPH_BC, we always need
01492          * an extra 32 OFF pixels around the image (in addition to 
01493          * the 32 added pixels for all dwa operations), whereas with
01494          * SYMMETRIC_MORPH_BC this is not necessary. */
01495     bordercolor = getMorphBorderPixelColor(L_MORPH_ERODE, 1);
01496     if (bordercolor == 0) {  /* asymmetric b.c. */
01497         borderx = 32 + (hsize / 64) * 32;
01498         bordery = 32 + (vsize / 64) * 32;
01499     }
01500     else   /* symmetric b.c. */
01501         borderx = bordery = 32;
01502     pixt1 = pixAddBorderGeneral(pixs, borderx, borderx, bordery, bordery, 0);
01503 
01504     pixt2 = pixDilateCompBrickExtendDwa(NULL, pixt1, hsize, vsize);
01505     pixErodeCompBrickExtendDwa(pixt1, pixt2, hsize, vsize);
01506 
01507     pixt3 = pixRemoveBorderGeneral(pixt1, borderx, borderx, bordery, bordery);
01508     pixDestroy(&pixt1);
01509     pixDestroy(&pixt2);
01510 
01511     if (!pixd)
01512         return pixt3;
01513 
01514     pixTransferAllData(pixd, &pixt3, 0, 0);
01515     return pixd;
01516 }
01517 
01518 
01519 /*!
01520  *  getExtendedCompositeParameters()
01521  *
01522  *      Input:  size (of linear Sel)
01523  *              &pn (<return> number of 63 wide convolutions)
01524  *              &pextra (<return> size of extra Sel)
01525  *              &actualsize (<optional return> actual size used in operation)
01526  *      Return: 0 if OK, 1 on error
01527  *
01528  *  Notes:
01529  *      (1) The DWA implementation allows Sels to be used with hits
01530  *          up to 31 pixels from the origin, either horizontally or
01531  *          vertically.  Larger Sels can be used if decomposed into
01532  *          a set of operations with Sels not exceeding 63 pixels
01533  *          in either width or height (and with the origin as close
01534  *          to the center of the Sel as possible).
01535  *      (2) This returns the decomposition of a linear Sel of length
01536  *          @size into a set of @n Sels of length 63 plus an extra
01537  *          Sel of length @extra.
01538  *      (3) For notation, let w == @size, n == @n, and e == @extra.
01539  *          We have 1 < e < 63.
01540  *
01541  *          Then if w < 64, we have n = 0 and e = w.
01542  *          The general formula for w > 63 is:
01543  *             w = 63 + (n - 1) * 62 + (e - 1)
01544  *
01545  *          Where did this come from?  Each successive convolution with
01546  *          a Sel of length L adds a total length (L - 1) to w.
01547  *          This accounts for using 62 for each additional Sel of size 63,
01548  *          and using (e - 1) for the additional Sel of size e.
01549  *
01550  *          Solving for n and e for w > 63:
01551  *             n = 1 + Int((w - 63) / 62)
01552  *             e = w - 63 - (n - 1) * 62 + 1
01553  *
01554  *          The extra part is decomposed into two factors f1 and f2,
01555  *          and the actual size of the extra part is
01556  *             e' = f1 * f2
01557  *          Then the actual width is:
01558  *             w' = 63 + (n - 1) * 62 + f1 * f2 - 1
01559  */
01560 l_int32
01561 getExtendedCompositeParameters(l_int32   size,
01562                                l_int32  *pn,
01563                                l_int32  *pextra,
01564                                l_int32  *pactualsize)
01565 {
01566 l_int32  n, extra, fact1, fact2;
01567 
01568     PROCNAME("getExtendedCompositeParameters");
01569 
01570     if (!pn || !pextra)
01571         return ERROR_INT("&n and &extra not both defined", procName, 1);
01572 
01573     if (size <= 63) {
01574         n = 0;
01575         extra = L_MIN(1, size);
01576     }
01577     else {  /* size > 63 */
01578         n = 1 + (l_int32)((size - 63) / 62);
01579         extra = size - 63 - (n - 1) * 62 + 1;
01580     }
01581 
01582     if (pactualsize) {
01583         selectComposableSizes(extra, &fact1, &fact2);
01584         *pactualsize = 63 + (n - 1) * 62 + fact1 * fact2 - 1;
01585     }
01586 
01587     *pn = n;
01588     *pextra = extra;
01589     return 0;
01590 }
01591 
01592 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines