Logo Search packages:      
Sourcecode: leptonlib version File versions  Download package

fmorph.c

/*====================================================================*
 -  Copyright (C) 2001 Leptonica.  All rights reserved.
 -  This software is distributed in the hope that it will be
 -  useful, but with NO WARRANTY OF ANY KIND.
 -  No author or distributor accepts responsibility to anyone for the
 -  consequences of using this software, or for whether it serves any
 -  particular purpose or works at all, unless he or she says so in
 -  writing.  Everyone is granted permission to copy, modify and
 -  redistribute this source code, for commercial or non-commercial
 -  purposes, with the following restrictions: (1) the origin of this
 -  source code must not be misrepresented; (2) modified versions must
 -  be plainly marked as such; and (3) this notice may not be removed
 -  or altered from any source or modified source distribution.
 *====================================================================*/


/*
 *  fmorph.c
 *
 *      Top-level fast binary morphological operations
 *
 *            PIX      *pixDilateFast()
 *            PIX      *pixErodeFast()
 *            PIX      *pixOpenFast()
 *            PIX      *pixCloseFast()
 *
 *      Top-level iterative fast binary morphological operations
 *
 *            PIX      *pixDilateIterFast()
 *            PIX      *pixErodeIterFast()
 *            PIX      *pixOpenIterFast()
 *            PIX      *pixCloseIterFast()
 *
 *      Note:  These routines require, at a minimum, a 32 pixel border
 *             of 0s.  For horizontal SEL displacements, all words
 *             in a scanline are read, but the first and last are not
 *             written to.  For vertical SEL displacements, the first
 *             and last 32 scanlines are not written to.  In order to
 *             get correct results for pixels within 32 pixels of
 *             the boundary, we add a 32 pixel border (of ADDED_BORDER = 32)
 *             pixels around the entire image.  Then, for any aggregate
 *             dilation, erosion, or opening of not more than 32 pixels on
 *             any side of the SEL center, we get no boundary effects.
 *             But for closings, we can still get boundary effects.
 *             The closing is a dilation followed by an erosion. 
 *             In order to avoid boundary effects, we must put enough
 *             border around the image so that after the dilation step
 *             of the closing, no pixels would have expanded into
 *             the outermost 32 pixel border.  If any ON pixels should
 *             have been written into the outermost 32 pixel border,
 *             then because they haven't actually been written, we get
 *             a boundary anomaly whereby ON pixels near the boundary
 *             are removed on the erosion step.
 */

#include <stdio.h>

#include "allheaders.h"

#define  SWAP(a,b)   { temp = (a); (a) = (b); (b) = temp; }



/*---------------------------------------------------------------------*
 *                        Top level fast morph ops                     *
 *---------------------------------------------------------------------*/
/*!
 *  pixDilateFast()
 *
 *      Input:  pixd (<optional> -- usual 3 choices: null, == pixs, != pixs)
 *              pixs 
 *              setype (MORPH_HORIZ, MORPH_VERT, MORPH_DIAGONAL,
 *                      MORPH_SQUARE, MORPH_SEPARABLE)
 *              size of se (restricted set) or index
 *      Return: prd, or NULL on error.
 *
 *  Action: dilates pixs by the se.
 *
 *  Note: The src (and dst if defined) must have an added border,
 *        of size ADDED_BORDER = 32, on all sides!  This is assumed
 *        for efficiency by the low-level code, which reads from
 *        32-bit words in the border but never writes into the border.
 */
PIX *
pixDilateFast(PIX    *pixd,
              PIX    *pixs,
              l_int32   setype,
            l_int32   size)
{
l_int32      w, h, wpls, wpld;
l_uint32    *datad, *datas, *datat;
PIX       *pixt;

    PROCNAME("pixDilateFast");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
    if (pixGetDepth(pixs) != 1)
      return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);

    if (pixd) {
      if (!pixSizesEqual(pixs, pixd))
          return (PIX *)ERROR_PTR("sizes not equal", procName, pixd);
    }
    else {
      if ((pixd = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    }

    wpls = pixGetWpl(pixs);
    wpld = pixGetWpl(pixd);

      /*  The images must be surrounded with ADDED_BORDER white pixels,
       *  that we'll read from.  We fabricate a "proper"
       *  image as the subimage within the border, having the 
       *  following parameters:  */
    w = pixGetWidth(pixs) - 2 * ADDED_BORDER;
    h = pixGetHeight(pixs) - 2 * ADDED_BORDER;
    datas = pixGetData(pixs) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
    datad = pixGetData(pixd) + ADDED_BORDER * wpld + ADDED_BORDER / 32;


      /*-------------------------------------------------*
       * We need a temp image if separable or in-place   *
       *-------------------------------------------------*/
    if (setype == MORPH_SEPARABLE) {
      if ((pixt = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
      datat = pixGetData(pixt) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
      morphop_low(datat, w, h, wpld, datas, wpls,
                    MORPH_DILATION, MORPH_HORIZ, size);
      morphop_low(datad, w, h, wpld, datat, wpls,
                    MORPH_DILATION, MORPH_VERT, size);
      pixDestroy(&pixt);
    }
    else if (pixd == pixs) {  /* in-place */
        if ((pixt = pixCopy(NULL, pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
      datat = pixGetData(pixt) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
      morphop_low(datad, w, h, wpld, datat, wpls,
                    MORPH_DILATION, setype, size);
      pixDestroy(&pixt);
    }
    else {  /* simple and not in-place */
      morphop_low(datad, w, h, wpld, datas, wpls,
                    MORPH_DILATION, setype, size);
    }

    return pixd;
}



/*!
 *  pixErodeFast()
 *
 *      Input:  pixd (<optional> -- usual 3 choices: null, == pixs, != pixs)
 *              pixs 
 *              setype (MORPH_HORIZ, MORPH_VERT, MORPH_DIAGONAL,
 *                      MORPH_SQUARE, MORPH_SEPARABLE)
 *              size of se (restricted set)
 *      Return: pixd, or NULL on error.
 *
 *  Action: erodes pixs by the se.
 *
 *  Note: The src (and dst if defined) must have an added border,
 *        of size ADDED_BORDER = 32, on all sides!   This is assumed for
 *        efficiency by the low-level code,  which reads from 32-bit
 *        words in the border but never writes into the border.
 */
PIX *
pixErodeFast(PIX    *pixd,
             PIX    *pixs,
             l_int32   setype,
           l_int32   size)
{
l_int32    w, h, wpls, wpld;
l_uint32  *datad, *datas, *datat;
PIX     *pixt;

    PROCNAME("pixErodeFast");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
    if (pixGetDepth(pixs) != 1)
      return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);

    if (pixd) {
      if (!pixSizesEqual(pixs, pixd))
          return (PIX *)ERROR_PTR("sizes not equal", procName, pixd);
    }
    else {
      if ((pixd = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    }

    wpls = pixGetWpl(pixs);
    wpld = pixGetWpl(pixd);

      /*  The images must be surrounded with ADDED_BORDER white pixels,
       *  that we'll read from.  We fabricate a "proper"
       *  image as the subimage within the border, having the 
       *  following parameters:  */
    w = pixGetWidth(pixs) - 2 * ADDED_BORDER;
    h = pixGetHeight(pixs) - 2 * ADDED_BORDER;
    datas = pixGetData(pixs) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
    datad = pixGetData(pixd) + ADDED_BORDER * wpld + ADDED_BORDER / 32;


      /*-------------------------------------------------*
       * We need a temp image if separable or in-place   *
       *-------------------------------------------------*/
    if (setype == MORPH_SEPARABLE) {
      if ((pixt = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
      datat = pixGetData(pixt) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
      morphop_low(datat, w, h, wpld, datas, wpls,
                    MORPH_EROSION, MORPH_HORIZ, size);
      morphop_low(datad, w, h, wpld, datat, wpls,
                    MORPH_EROSION, MORPH_VERT, size);
      pixDestroy(&pixt);
    }
    else if (pixd == pixs) {  /* in-place */
        if ((pixt = pixCopy(NULL, pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
      datat = pixGetData(pixt) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
      morphop_low(datad, w, h, wpld, datat, wpls,
                    MORPH_EROSION, setype, size);
      pixDestroy(&pixt);
    }
    else {  /* simple and not in-place */
      morphop_low(datad, w, h, wpld, datas, wpls,
                    MORPH_EROSION, setype, size);
    }

    return pixd;
}



/*!
 *  pixOpenFast()
 *
 *      Input:  pixd (<optional> -- usual 3 choices: null, == pixs, != pixs)
 *              pixs 
 *              setype (MORPH_HORIZ, MORPH_VERT, MORPH_DIAGONAL,
 *                      MORPH_SQUARE, MORPH_SEPARABLE)
 *              size of se (restricted set)
 *      Return: pixd, or NULL on error.
 *
 * Action: opens pixs by the se.
 *
 * Note: The src (and dst if defined) must have an added border,
 *       of size ADDED_BORDER = 32, on all sides!   This is assumed for
 *       efficiency by the low-level code, which reads from
 *       32-bit words in the border but never writes into the border.
 */
PIX *
pixOpenFast(PIX    *pixd,
            PIX    *pixs,
            l_int32   setype,
          l_int32   size)
{
l_int32    w, h, wpls, wpld;
l_uint32  *datad, *datas, *datat1, *datat2;
PIX     *pixt1, *pixt2;

    PROCNAME("pixOpenFast");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
    if (pixGetDepth(pixs) != 1)
      return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);

    if (pixd) {
      if (!pixSizesEqual(pixs, pixd))
          return (PIX *)ERROR_PTR("sizes not equal", procName, pixd);
    }
    else {
      if ((pixd = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    }

    if ((pixt1 = pixCreateTemplate(pixs)) == NULL)
      return (PIX *)ERROR_PTR("pixt not made", procName, pixd);
    
    wpls = pixGetWpl(pixs);
    wpld = pixGetWpl(pixd);

      /*  The images must be surrounded with ADDED_BORDER white pixels,
       *  that we'll read from.  We fabricate a "proper"
       *  image as the subimage within the border, having the 
       *  following parameters:  */
    w = pixGetWidth(pixs) - 2 * ADDED_BORDER;
    h = pixGetHeight(pixs) - 2 * ADDED_BORDER;
    datas = pixGetData(pixs) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
    datat1 = pixGetData(pixt1) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
    datad = pixGetData(pixd) + ADDED_BORDER * wpld + ADDED_BORDER / 32;

    if (setype == MORPH_SEPARABLE) {
      if ((pixt2 = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixt2 not made", procName, pixd);
      datat2 = pixGetData(pixt2) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
      morphop_low(datat1, w, h, wpls, datas, wpls,
                    MORPH_EROSION, MORPH_HORIZ, size);
      morphop_low(datat2, w, h, wpls, datat1, wpls,
                    MORPH_EROSION, MORPH_VERT, size);
      morphop_low(datat1, w, h, wpls, datat2, wpls,
                    MORPH_DILATION, MORPH_HORIZ, size);
      morphop_low(datad, w, h, wpld, datat1, wpls,
                    MORPH_DILATION, MORPH_VERT, size);
      pixDestroy(&pixt2);
    }
    else {
      morphop_low(datat1, w, h, wpls, datas, wpls,
                    MORPH_EROSION, setype, size);
      morphop_low(datad, w, h, wpld, datat1, wpls,
                    MORPH_DILATION, setype, size);
    }

    pixDestroy(&pixt1);

    return pixd;
}



/*!
 *  pixCloseFast()
 *
 *      Input:  pixd (<optional> -- usual 3 choices: null, == pixs, != pixs)
 *              pixs 
 *              setype (MORPH_HORIZ, MORPH_VERT, MORPH_DIAGONAL,
 *                      MORPH_SQUARE, MORPH_SEPARABLE)
 *              size of se (restricted set)
 *      Return: pixd, or NULL on error.
 *
 *  Action: closes pixs by the se.
 *
 *  Note: The src (and dst if defined) must have an added border,
 *        of size ADDED_BORDER = 32, on all sides!   This is assumed for
 *        efficiency by the low-level code, which reads from
 *        32-bit words in the border but never writes into the border.
 */
PIX *
pixCloseFast(PIX    *pixd,
             PIX    *pixs,
             l_int32   setype,
           l_int32   size)
{
l_int32    w, h, wpls, wpld;
l_uint32  *datad, *datas, *datat1, *datat2;
PIX     *pixt1, *pixt2;

    PROCNAME("pixCloseFast");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
    if (pixGetDepth(pixs) != 1)
      return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);

    if (pixd) {
      if (!pixSizesEqual(pixs, pixd))
          return (PIX *)ERROR_PTR("sizes not equal", procName, pixd);
    }
    else {
      if ((pixd = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    }

    if ((pixt1 = pixCreateTemplate(pixs)) == NULL)
      return (PIX *)ERROR_PTR("pixt not made", procName, pixd);

    wpls = pixGetWpl(pixs);
    wpld = pixGetWpl(pixd);

      /*  The images must be surrounded with ADDED_BORDER white pixels,
       *  that we'll read from.  We fabricate a "proper"
       *  image as the subimage within the border, having the 
       *  following parameters:  */
    w = pixGetWidth(pixs) - 2 * ADDED_BORDER;
    h = pixGetHeight(pixs) - 2 * ADDED_BORDER;
    datas = pixGetData(pixs) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
    datat1 = pixGetData(pixt1) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
    datad = pixGetData(pixd) + ADDED_BORDER * wpld + ADDED_BORDER / 32;

    if (setype == MORPH_SEPARABLE) {
      if ((pixt2 = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixt2 not made", procName, pixd);
      datat2 = pixGetData(pixt2) + ADDED_BORDER * wpls + ADDED_BORDER / 32;
      morphop_low(datat1, w, h, wpls, datas, wpls,
                    MORPH_DILATION, MORPH_HORIZ, size);
      morphop_low(datat2, w, h, wpls, datat1, wpls,
                    MORPH_DILATION, MORPH_VERT, size);
      morphop_low(datat1, w, h, wpls, datat2, wpls,
                    MORPH_EROSION, MORPH_HORIZ, size);
      morphop_low(datad, w, h, wpld, datat1, wpls,
                    MORPH_EROSION, MORPH_VERT, size);
      pixDestroy(&pixt2);
    }
    else {
      morphop_low(datat1, w, h, wpls, datas, wpls,
                    MORPH_DILATION, setype, size);
      morphop_low(datad, w, h, wpld, datat1, wpls,
                    MORPH_EROSION, setype, size);
    }

    pixDestroy(&pixt1);

    return pixd;
}



/*---------------------------------------------------------------------*
 *                  Top level iterative fast morph ops                 *
 *---------------------------------------------------------------------*/
/*!
 *  pixDilateIterFast()
 *
 *      Input:  pixd (<optional> -- usual 3 choices: null, == pixs, != pixs)
 *              pixs 
 *              setype (MORPH_HORIZ, MORPH_VERT, MORPH_DIAGONAL,
 *                      MORPH_SQUARE, MORPH_SEPARABLE)
 *              size of se (restricted set)
 *              iteration count
 *      Return: pixd, or NULL on error.
 *
 * Action: dilates pixs by the se.
 */
PIX *
pixDilateIterFast(PIX    *pixd,
                  PIX    *pixs,
                  l_int32   setype,
                l_int32   size,
                l_int32   iters)
{
l_int32    i, maxextension, nits;
PIX     *pixts, *pixtd, *temp;

    PROCNAME("pixDilateIterFast");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
    if (pixGetDepth(pixs) != 1)
      return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);

    if (iters < 1) {
      L_WARNING("iters must be >= 1; setting to 1", procName);
      iters = 1;
    }

    if (pixd) {
      if (!pixSizesEqual(pixs, pixd))
          return (PIX *)ERROR_PTR("sizes not equal", procName, pixd);
    }
    else {
      if ((pixd = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    }

    maxextension = iters * (size / 2);
    if (maxextension > 32)
      L_WARNING_INT("maxextension %d; exceeds 32", procName, maxextension);
    
    if (iters % 2 == 1) {
      pixDilateFast(pixd, pixs, setype, size);
      pixts = pixd;
      pixtd = pixts;
      nits = iters - 1;
    }
    else {
      pixts = pixs;
      nits = iters;
    }

    if (nits == 0)
      return pixd;

    for (i = 0; i < nits; i++) {
      if (i == 0) {
          pixtd = pixDilateFast(NULL, pixts, setype, size);
          pixts = pixd;
      }
      else
          pixDilateFast(pixtd, pixts, setype, size);
      SWAP(pixts, pixtd)
    }
    SWAP(pixts, pixtd)   /* resets after last swap */

    pixDestroy(&pixts);
    return pixtd;
}


/*!
 *  pixErodeIterFast()
 *
 *      Input:  pixd (<optional> -- usual 3 choices: null, == pixs, != pixs)
 *              pixs 
 *              setype (MORPH_HORIZ, MORPH_VERT, MORPH_DIAGONAL,
 *                      MORPH_SQUARE, MORPH_SEPARABLE)
 *              size of se (restricted set)
 *              iteration count
 *      Return: pixd, or NULL on error.
 *
 *  Action: erodes pixs by the se.
 */
PIX *
pixErodeIterFast(PIX    *pixd,
                 PIX    *pixs,
                 l_int32   setype,
               l_int32   size,
               l_int32   iters)
{
l_int32    i, maxextension, nits;
PIX     *pixts, *pixtd, *temp;

    PROCNAME("pixErodeIterFast");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
    if (pixGetDepth(pixs) != 1)
      return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);

    if (iters < 1) {
      L_WARNING("iters must be >= 1; setting to 1", procName);
      iters = 1;
    }

    if (pixd) {
      if (!pixSizesEqual(pixs, pixd))
          return (PIX *)ERROR_PTR("sizes not equal", procName, pixd);
    }
    else {
      if ((pixd = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    }

    maxextension = iters * (size / 2);
    if (maxextension > 32)
      L_WARNING_INT("maxextension %d; exceeds 32", procName, maxextension);
    
    if (iters % 2 == 1) {
      pixErodeFast(pixd, pixs, setype, size);
      pixts = pixd;
      pixtd = pixts;
      nits = iters - 1;
    }
    else {
      pixts = pixs;
      nits = iters;
    }

    if (nits == 0)
      return pixd;

    for (i = 0; i < nits; i++) {
      if (i == 0) {
          pixtd = pixErodeFast(NULL, pixts, setype, size);
          pixts = pixd;
      }
      else
          pixErodeFast(pixtd, pixts, setype, size);
      SWAP(pixts, pixtd)
    }
    SWAP(pixts, pixtd)   /* resets after last swap */

    pixDestroy(&pixts);
    return pixtd;
}


/*!
 *  pixOpenIterFast()
 *
 *      Input:  pixd (<optional> -- usual 3 choices: null, == pixs, != pixs)
 *              pixs 
 *              setype (MORPH_HORIZ, MORPH_VERT, MORPH_DIAGONAL,
 *                      MORPH_SQUARE, MORPH_SEPARABLE)
 *              size of se (restricted set)
 *              iteration count
 *      Return: pixd, or NULL on error.
 *
 *  Action: opens pixs by the se.
 */
PIX *
pixOpenIterFast(PIX    *pixd,
                PIX    *pixs,
                l_int32   setype,
              l_int32   size,
              l_int32   iters)
{
l_int32    i, maxextension;
PIX     *pixt, *temp;

    PROCNAME("pixOpenIterFast");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
    if (pixGetDepth(pixs) != 1)
      return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);

    if (iters < 1) {
      L_WARNING("iters must be >= 1; setting to 1", procName);
      iters = 1;
    }

    if (pixd) {
      if (!pixSizesEqual(pixs, pixd))
          return (PIX *)ERROR_PTR("sizes not equal", procName, pixd);
    }
    else {
      if ((pixd = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    }

    maxextension = iters * (size / 2);
    if (maxextension > 32)
      L_WARNING_INT("maxextension %d; exceeds 32", procName, maxextension);
    
    if (iters == 1) {
      pixt = pixErodeFast(NULL, pixs, setype, size);
      pixDilateFast(pixd, pixt, setype, size);
      pixDestroy(&pixt);
      return pixd;
    }

      /* Do all erosions first, and then do all dilations.
       * Because the number of operations is 2 * iters, which is
       * even, we always finish with the result in pixd. */
    pixt = pixErodeFast(NULL, pixs, setype, size);
    for (i = 0; i < iters - 1; i++) {
      pixErodeFast(pixd, pixt, setype, size);
      SWAP(pixt, pixd)
    }
    for (i = 0; i < iters; i++) {
      pixDilateFast(pixd, pixt, setype, size);
      SWAP(pixt, pixd)
    }
    SWAP(pixt, pixd)  /* cancels the last swap */

    pixDestroy(&pixt);
    return pixd;
}


/*!
 *  pixCloseIterFast()
 *
 *      Input:  pixd (<optional> -- usual 3 choices: null, == pixs, != pixs)
 *              pixs 
 *              setype (MORPH_HORIZ, MORPH_VERT, MORPH_DIAGONAL,
 *                      MORPH_SQUARE, MORPH_SEPARABLE)
 *              size of se (restricted set)
 *              iteration count
 *      Return: pixd, or NULL on error.
 *
 *  Action: closes pixs by the se.
 */
PIX *
pixCloseIterFast(PIX    *pixd,
                 PIX    *pixs,
                 l_int32   setype,
               l_int32   size,
               l_int32   iters)
{
l_int32    i, maxextension;
PIX     *pixt, *temp;

    PROCNAME("pixCloseIterFast");

    if (!pixs)
      return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
    if (pixGetDepth(pixs) != 1)
      return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd);

    if (iters < 1) {
      L_WARNING("iters must be >= 1; setting to 1", procName);
      iters = 1;
    }

    if (pixd) {
      if (!pixSizesEqual(pixs, pixd))
          return (PIX *)ERROR_PTR("sizes not equal", procName, pixd);
    }
    else {
      if ((pixd = pixCreateTemplate(pixs)) == NULL)
          return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    }

    maxextension = iters * (size / 2);
    if (maxextension > 32)
      L_WARNING_INT("maxextension %d; exceeds 32", procName, maxextension);
    
    if (iters == 1) {
      pixt = pixDilateFast(NULL, pixs, setype, size);
      pixErodeFast(pixd, pixt, setype, size);
      pixDestroy(&pixt);
      return pixd;
    }

      /* Do all dilations first, and then do all erosions.
       * Because the number of operations is 2 * iters, which is
       * even, we always finish with the result in pixd. */
    pixt = pixDilateFast(NULL, pixs, setype, size);
    for (i = 0; i < iters - 1; i++) {
      pixDilateFast(pixd, pixt, setype, size);
      SWAP(pixt, pixd)
    }
    for (i = 0; i < iters; i++) {
      pixErodeFast(pixd, pixt, setype, size);
      SWAP(pixt, pixd)
    }
    SWAP(pixt, pixd)  /* cancels the last swap */

    pixDestroy(&pixt);
    return pixd;
}


Generated by  Doxygen 1.6.0   Back to index