The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Image::Leptonica::Func::morphdwa

VERSION

version 0.04

morphdwa.c

morphdwa.c

  Binary morphological (dwa) ops with brick Sels
       PIX     *pixDilateBrickDwa()
       PIX     *pixErodeBrickDwa()
       PIX     *pixOpenBrickDwa()
       PIX     *pixCloseBrickDwa()

  Binary composite morphological (dwa) ops with brick Sels
       PIX     *pixDilateCompBrickDwa()
       PIX     *pixErodeCompBrickDwa()
       PIX     *pixOpenCompBrickDwa()
       PIX     *pixCloseCompBrickDwa()

  Binary extended composite morphological (dwa) ops with brick Sels
       PIX     *pixDilateCompBrickExtendDwa()
       PIX     *pixErodeCompBrickExtendDwa()
       PIX     *pixOpenCompBrickExtendDwa()
       PIX     *pixCloseCompBrickExtendDwa()
       l_int32  getExtendedCompositeParameters()

  These are higher-level interfaces for dwa morphology with brick Sels.
  Because many morphological operations are performed using
  separable brick Sels, it is useful to have a simple interface
  for this.

  We have included all 58 of the brick Sels that are generated
  by selaAddBasic().  These are sufficient for all the decomposable
  bricks up to size 63, which is the limit for dwa Sels with
  origins at the center of the Sel.

  All three sets can be used as the basic interface for general
  brick operations.  Here are the internal calling sequences:

    (1) If you try to apply a non-decomposable operation, such as
        pixErodeBrickDwa(), with a Sel size that doesn't exist,
        this calls a decomposable operation, pixErodeCompBrickDwa(),
        instead.  This can differ in linear Sel size by up to
        2 pixels from the request.

    (2) If either Sel brick dimension is greater than 63, the extended
        composite function is called.

    (3) The extended composite function calls the composite function
        a number of times with size 63, and once with size < 63.
        Because each operation with a size of 63 is done compositely
        with 7 x 9 (exactly 63), the net result is correct in
        length to within 2 pixels.

  For composite operations, both using a comb and extended (beyond 63),
  horizontal and vertical operations are composed separately
  and sequentially.

  We have also included use of all the 76 comb Sels that are generated
  by selaAddDwaCombs().  The generated code is in dwacomb.2.c
  and dwacomblow.2.c.  These are used for the composite dwa
  brick operations.

  The non-composite brick operations, such as pixDilateBrickDwa(),
  will call the associated composite operation in situations where
  the requisite brick Sel has not been compiled into fmorphgen*.1.c.

  If you want to use brick Sels that are not represented in the
  basic set of 58, you must generate the dwa code to implement them.
  You have three choices for how to use these:

  (1) Add both the new Sels and the dwa code to the library:
      - For simplicity, add your new brick Sels to those defined
        in selaAddBasic().
      - Recompile the library.
      - Make prog/fmorphautogen.
      - Run prog/fmorphautogen, to generate new versions of the
        dwa code in fmorphgen.1.c and fmorphgenlow.1.c.
      - Copy these two files to src.
      - Recompile the library again.
      - Use the new brick Sels in your program and compile it.

  (2) Make both the new Sels and dwa code outside the library,
      and link it directly to an executable:
      - Write a function to generate the new Sels in a Sela, and call
        fmorphautogen(sela, <N>, filename) to generate the code.
      - Compile your program that uses the newly generated function
        pixMorphDwa_<N>(), and link to the two new C files.

  (3) Make the new Sels in the library and use the dwa code outside it:
      - Add code in the library to generate your new brick Sels.
        (It is suggested that you NOT add these Sels to the
        selaAddBasic() function; write a new function that generates
        a new Sela.)
      - Recompile the library.
      - Write a small program that generates the Sela and calls
        fmorphautogen(sela, <N>, filename) to generate the code.
      - Compile your program that uses the newly generated function
        pixMorphDwa_<N>(), and link to the two new C files.
     As an example of this approach, see prog/dwamorph*_reg.c:
      - added selaAddDwaLinear() to sel2.c
      - wrote dwamorph1_reg.c, to generate the dwa code.
      - compiled and linked the generated code with the application,
        dwamorph2_reg.c.  (Note: because this was a regression test,
        dwamorph1_reg also builds and runs the application program.)

FUNCTIONS

getExtendedCompositeParameters

l_int32 getExtendedCompositeParameters ( l_int32 size, l_int32 *pn, l_int32 *pextra, l_int32 *pactualsize )

getExtendedCompositeParameters()

    Input:  size (of linear Sel)
            &pn (<return> number of 63 wide convolutions)
            &pextra (<return> size of extra Sel)
            &actualsize (<optional return> actual size used in operation)
    Return: 0 if OK, 1 on error

Notes:
    (1) The DWA implementation allows Sels to be used with hits
        up to 31 pixels from the origin, either horizontally or
        vertically.  Larger Sels can be used if decomposed into
        a set of operations with Sels not exceeding 63 pixels
        in either width or height (and with the origin as close
        to the center of the Sel as possible).
    (2) This returns the decomposition of a linear Sel of length
        @size into a set of @n Sels of length 63 plus an extra
        Sel of length @extra.
    (3) For notation, let w == @size, n == @n, and e == @extra.
        We have 1 < e < 63.

        Then if w < 64, we have n = 0 and e = w.
        The general formula for w > 63 is:
           w = 63 + (n - 1) * 62 + (e - 1)

        Where did this come from?  Each successive convolution with
        a Sel of length L adds a total length (L - 1) to w.
        This accounts for using 62 for each additional Sel of size 63,
        and using (e - 1) for the additional Sel of size e.

        Solving for n and e for w > 63:
           n = 1 + Int((w - 63) / 62)
           e = w - 63 - (n - 1) * 62 + 1

        The extra part is decomposed into two factors f1 and f2,
        and the actual size of the extra part is
           e' = f1 * f2
        Then the actual width is:
           w' = 63 + (n - 1) * 62 + f1 * f2 - 1

pixCloseBrickDwa

PIX * pixCloseBrickDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixCloseBrickDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

Notes:
    (1) This is a 'safe' closing; we add an extra border of 32 OFF
        pixels for the standard asymmetric b.c.
    (2) These implement 2D brick Sels, using linear Sels generated
        with selaAddBasic().
    (3) A brick Sel has hits for all elements.
    (4) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
    (5) Do separably if both hsize and vsize are > 1.
    (6) It is necessary that both horizontal and vertical Sels
        of the input size are defined in the basic sela.
    (7) Note that we must always set or clear the border pixels
        before each operation, depending on the the b.c.
        (symmetric or asymmetric).
    (8) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (9) For clarity, if the case is known, use these patterns:
        (a) pixd = pixCloseBrickDwa(NULL, pixs, ...);
        (b) pixCloseBrickDwa(pixs, pixs, ...);
        (c) pixCloseBrickDwa(pixd, pixs, ...);
    (10) The size of the result is determined by pixs.
    (11) If either linear Sel is not found, this calls
         the appropriate decomposible function.

pixCloseCompBrickDwa

PIX * pixCloseCompBrickDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixCloseCompBrickDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

Notes:
    (1) This implements a separable composite safe closing with 2D
        brick Sels.
    (2) For efficiency, it may decompose each linear morphological
        operation into two (brick + comb).
    (3) A brick Sel has hits for all elements.
    (4) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
    (5) Do separably if both hsize and vsize are > 1.
    (6) It is necessary that both horizontal and vertical Sels
        of the input size are defined in the basic sela.
    (7) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (8) For clarity, if the case is known, use these patterns:
        (a) pixd = pixCloseCompBrickDwa(NULL, pixs, ...);
        (b) pixCloseCompBrickDwa(pixs, pixs, ...);
        (c) pixCloseCompBrickDwa(pixd, pixs, ...);
    (9) The size of pixd is determined by pixs.
    (10) CAUTION: both hsize and vsize are being decomposed.
        The decomposer chooses a product of sizes (call them
        'terms') for each that is close to the input size,
         but not necessarily equal to it.  It attempts to optimize:
            (a) for consistency with the input values: the product
                of terms is close to the input size
            (b) for efficiency of the operation: the sum of the
                terms is small; ideally about twice the square
                 root of the input size.
         So, for example, if the input hsize = 37, which is
         a prime number, the decomposer will break this into two
         terms, 6 and 6, so that the net result is a dilation
         with hsize = 36.

pixCloseCompBrickExtendDwa

PIX * pixCloseCompBrickExtendDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixCloseCompBrickExtendDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

    (1) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (2) There is no need to call this directly:  pixCloseCompBrickDwa()
        calls this function if either brick dimension exceeds 63.

pixDilateBrickDwa

PIX * pixDilateBrickDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixDilateBrickDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

Notes:
    (1) These implement 2D brick Sels, using linear Sels generated
        with selaAddBasic().
    (2) A brick Sel has hits for all elements.
    (3) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
    (4) Do separably if both hsize and vsize are > 1.
    (5) It is necessary that both horizontal and vertical Sels
        of the input size are defined in the basic sela.
    (6) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (7) For clarity, if the case is known, use these patterns:
        (a) pixd = pixDilateBrickDwa(NULL, pixs, ...);
        (b) pixDilateBrickDwa(pixs, pixs, ...);
        (c) pixDilateBrickDwa(pixd, pixs, ...);
    (8) The size of pixd is determined by pixs.
    (9) If either linear Sel is not found, this calls
        the appropriate decomposible function.

pixDilateCompBrickDwa

PIX * pixDilateCompBrickDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixDilateCompBrickDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

Notes:
    (1) These implement a separable composite dilation with 2D brick Sels.
    (2) For efficiency, it may decompose each linear morphological
        operation into two (brick + comb).
    (3) A brick Sel has hits for all elements.
    (4) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
    (5) Do separably if both hsize and vsize are > 1.
    (6) It is necessary that both horizontal and vertical Sels
        of the input size are defined in the basic sela.
    (7) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (8) For clarity, if the case is known, use these patterns:
        (a) pixd = pixDilateCompBrickDwa(NULL, pixs, ...);
        (b) pixDilateCompBrickDwa(pixs, pixs, ...);
        (c) pixDilateCompBrickDwa(pixd, pixs, ...);
    (9) The size of pixd is determined by pixs.
    (10) CAUTION: both hsize and vsize are being decomposed.
        The decomposer chooses a product of sizes (call them
        'terms') for each that is close to the input size,
         but not necessarily equal to it.  It attempts to optimize:
            (a) for consistency with the input values: the product
                of terms is close to the input size
            (b) for efficiency of the operation: the sum of the
                terms is small; ideally about twice the square
                 root of the input size.
         So, for example, if the input hsize = 37, which is
         a prime number, the decomposer will break this into two
         terms, 6 and 6, so that the net result is a dilation
         with hsize = 36.

pixDilateCompBrickExtendDwa

PIX * pixDilateCompBrickExtendDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixDilateCompBrickExtendDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

Notes:
    (1) Ankur Jain suggested and implemented extending the composite
        DWA operations beyond the 63 pixel limit.  This is a
        simplified and approximate implementation of the extension.
        This allows arbitrary Dwa morph operations using brick Sels,
        by decomposing the horizontal and vertical dilations into
        a sequence of 63-element dilations plus a dilation of size
        between 3 and 62.
    (2) The 63-element dilations are exact, whereas the extra dilation
        is approximate, because the underlying decomposition is
        in pixDilateCompBrickDwa().  See there for further details.
    (3) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (4) There is no need to call this directly:  pixDilateCompBrickDwa()
        calls this function if either brick dimension exceeds 63.

pixErodeBrickDwa

PIX * pixErodeBrickDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixErodeBrickDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

Notes:
    (1) These implement 2D brick Sels, using linear Sels generated
        with selaAddBasic().
    (2) A brick Sel has hits for all elements.
    (3) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
    (4) Do separably if both hsize and vsize are > 1.
    (5) It is necessary that both horizontal and vertical Sels
        of the input size are defined in the basic sela.
    (6) Note that we must always set or clear the border pixels
        before each operation, depending on the the b.c.
        (symmetric or asymmetric).
    (7) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (8) For clarity, if the case is known, use these patterns:
        (a) pixd = pixErodeBrickDwa(NULL, pixs, ...);
        (b) pixErodeBrickDwa(pixs, pixs, ...);
        (c) pixErodeBrickDwa(pixd, pixs, ...);
    (9) The size of the result is determined by pixs.
    (10) If either linear Sel is not found, this calls
         the appropriate decomposible function.

pixErodeCompBrickDwa

PIX * pixErodeCompBrickDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixErodeCompBrickDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

Notes:
    (1) These implement a separable composite erosion with 2D brick Sels.
    (2) For efficiency, it may decompose each linear morphological
        operation into two (brick + comb).
    (3) A brick Sel has hits for all elements.
    (4) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
    (5) Do separably if both hsize and vsize are > 1.
    (6) It is necessary that both horizontal and vertical Sels
        of the input size are defined in the basic sela.
    (7) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (8) For clarity, if the case is known, use these patterns:
        (a) pixd = pixErodeCompBrickDwa(NULL, pixs, ...);
        (b) pixErodeCompBrickDwa(pixs, pixs, ...);
        (c) pixErodeCompBrickDwa(pixd, pixs, ...);
    (9) The size of pixd is determined by pixs.
    (10) CAUTION: both hsize and vsize are being decomposed.
        The decomposer chooses a product of sizes (call them
        'terms') for each that is close to the input size,
         but not necessarily equal to it.  It attempts to optimize:
            (a) for consistency with the input values: the product
                of terms is close to the input size
            (b) for efficiency of the operation: the sum of the
                terms is small; ideally about twice the square
                 root of the input size.
         So, for example, if the input hsize = 37, which is
         a prime number, the decomposer will break this into two
         terms, 6 and 6, so that the net result is a dilation
         with hsize = 36.

pixErodeCompBrickExtendDwa

PIX * pixErodeCompBrickExtendDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixErodeCompBrickExtendDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

Notes:
    (1) See pixDilateCompBrickExtendDwa() for usage.
    (2) There is no need to call this directly:  pixErodeCompBrickDwa()
        calls this function if either brick dimension exceeds 63.

pixOpenBrickDwa

PIX * pixOpenBrickDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixOpenBrickDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

Notes:
    (1) These implement 2D brick Sels, using linear Sels generated
        with selaAddBasic().
    (2) A brick Sel has hits for all elements.
    (3) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
    (4) Do separably if both hsize and vsize are > 1.
    (5) It is necessary that both horizontal and vertical Sels
        of the input size are defined in the basic sela.
    (6) Note that we must always set or clear the border pixels
        before each operation, depending on the the b.c.
        (symmetric or asymmetric).
    (7) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (8) For clarity, if the case is known, use these patterns:
        (a) pixd = pixOpenBrickDwa(NULL, pixs, ...);
        (b) pixOpenBrickDwa(pixs, pixs, ...);
        (c) pixOpenBrickDwa(pixd, pixs, ...);
    (9) The size of the result is determined by pixs.
    (10) If either linear Sel is not found, this calls
         the appropriate decomposible function.

pixOpenCompBrickDwa

PIX * pixOpenCompBrickDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixOpenCompBrickDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

Notes:
    (1) These implement a separable composite opening with 2D brick Sels.
    (2) For efficiency, it may decompose each linear morphological
        operation into two (brick + comb).
    (3) A brick Sel has hits for all elements.
    (4) The origin of the Sel is at (x, y) = (hsize/2, vsize/2)
    (5) Do separably if both hsize and vsize are > 1.
    (6) It is necessary that both horizontal and vertical Sels
        of the input size are defined in the basic sela.
    (7) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (8) For clarity, if the case is known, use these patterns:
        (a) pixd = pixOpenCompBrickDwa(NULL, pixs, ...);
        (b) pixOpenCompBrickDwa(pixs, pixs, ...);
        (c) pixOpenCompBrickDwa(pixd, pixs, ...);
    (9) The size of pixd is determined by pixs.
    (10) CAUTION: both hsize and vsize are being decomposed.
        The decomposer chooses a product of sizes (call them
        'terms') for each that is close to the input size,
         but not necessarily equal to it.  It attempts to optimize:
            (a) for consistency with the input values: the product
                of terms is close to the input size
            (b) for efficiency of the operation: the sum of the
                terms is small; ideally about twice the square
                 root of the input size.
         So, for example, if the input hsize = 37, which is
         a prime number, the decomposer will break this into two
         terms, 6 and 6, so that the net result is a dilation
         with hsize = 36.

pixOpenCompBrickExtendDwa

PIX * pixOpenCompBrickExtendDwa ( PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize )

pixOpenCompBrickExtendDwa()

    Input:  pixd  (<optional>; this can be null, equal to pixs,
                   or different from pixs)
            pixs (1 bpp)
            hsize (width of brick Sel)
            vsize (height of brick Sel)
    Return: pixd

    (1) There are three cases:
        (a) pixd == null   (result into new pixd)
        (b) pixd == pixs   (in-place; writes result back to pixs)
        (c) pixd != pixs   (puts result into existing pixd)
    (2) There is no need to call this directly:  pixOpenCompBrickDwa()
        calls this function if either brick dimension exceeds 63.

AUTHOR

Zakariyya Mughal <zmughal@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Zakariyya Mughal.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.