コード例 #1
0
def infClose(imIn, imOut, n, grid=mamba.DEFAULT_GRID):
    """
    Performs the infimum of directional closings. A black particle is preserved
    if its length is larger than 'n' in at least one direction.
    
    This operator is a closing. The image edge is set to 'FILLED' in order to 
    take into account particles touching the edge (they are supposed not to 
    extend outside the image window).
    
    When square grid is used, the size in oblique directions are reduced to be
    similar to the horizontal and vertical size.    
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk1.fill(mamba.computeMaxRange(imIn)[1])
    if grid == mamba.SQUARE:
        size = int((1.4142 * n + 1) / 2)
        linearClose(imIn, imWrk2, 2, size, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "inf")
        linearClose(imIn, imWrk2, 4, size, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "inf")
        d = 4
    else:
        d = 6
    for i in range(1, d, 2):
        linearClose(imIn, imWrk2, i, n, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "inf")
    mamba.copy(imWrk1, imOut)
コード例 #2
0
def rotatingThin(imIn, imOut, dse, edge=mamba.FILLED):
    """
    Performs a complete rotation of thinnings , the initial 'dse' double
    structuring element being turned one step clockwise after each thinning.
    At each rotation step, the previous result is used as input for the next
    thinning (chained thinnings). Depending on the grid where 'dse' is defined,
    6 or 8 rotations are performed.
    
    'imIn' and 'imOut' are binary images.
    
    'edge' is set to FILLED by default (default value is EMPTY in simple thin).
    """

    imWrk = mamba.imageMb(imIn)
    if edge == mamba.FILLED:
        mamba.negate(imIn, imOut)
        for d in mamba.getDirections(dse.getGrid(), True):
            hitOrMiss(imOut, imWrk, dse.flip(), edge=mamba.EMPTY)
            mamba.logic(imWrk, imOut, imOut, "sup")
            dse = dse.rotate()
        mamba.negate(imOut, imOut)
    else:
        mamba.copy(imIn, imOut)
        for d in mamba.getDirections(dse.getGrid(), True):
            hitOrMiss(imOut, imWrk, dse, edge=mamba.EMPTY)
            mamba.diff(imOut, imWrk, imOut)
            dse = dse.rotate()
コード例 #3
0
def infClose(imIn, imOut, n, grid=mamba.DEFAULT_GRID):
    """
    Performs the infimum of directional closings. A black particle is preserved
    if its length is larger than 'n' in at least one direction.
    
    This operator is a closing. The image edge is set to 'FILLED' in order to 
    take into account particles touching the edge (they are supposed not to 
    extend outside the image window).
    
    When square grid is used, the size in oblique directions are reduced to be
    similar to the horizontal and vertical size.    
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk1.fill(mamba.computeMaxRange(imIn)[1])
    if grid == mamba.SQUARE:
        size = int((1.4142 * n + 1)/2)
        linearClose(imIn, imWrk2, 2, size, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "inf")
        linearClose(imIn, imWrk2, 4, size, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "inf")
        d = 4
    else:
        d = 6
    for i in range(1, d, 2):
        linearClose(imIn, imWrk2, i, n, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "inf")
    mamba.copy(imWrk1, imOut)
コード例 #4
0
ファイル: segment.py プロジェクト: nicolasBeucher/mamba-image
def mosaic(imIn, imOut, imWts, grid=mamba.DEFAULT_GRID):
    """
    Builds the mosaic image of 'imIn' and puts the results into 'imOut'.
    The watershed line (pixel values set to 255) is stored in the 
    greytone image 'imWts'. A mosaic image is a simple image made of various 
    tiles of uniform grey values. It is built using the watershed of 'imIn' 
    gradient and original markers made of gradient minima which are labelled by
    the maximum value of 'imIn' pixels inside them.
    """

    imWrk1 = mamba.imageMb(imIn, 1)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk2)
    im_mark = mamba.imageMb(imIn, 32)
    se = mamba.structuringElement(mamba.getDirections(grid), grid)
    mamba.gradient(imIn, imOut, se=se)
    mamba.minima(imOut, imWrk1, grid=grid)
    mamba.add(im_mark, imWrk1, im_mark)
    imWrk1.convert(8)
    mamba.build(imWrk1, imWrk2, grid=grid)
    mamba.add(im_mark, imWrk2, im_mark)
    watershedSegment(imOut, im_mark, grid=grid)
    mamba.copyBytePlane(im_mark, 3, imWts)
    mamba.subConst(im_mark, 1, im_mark)
    mamba.copyBytePlane(im_mark, 0, imOut)
コード例 #5
0
def nonEqualNeighbors(imIn,
                      imOut,
                      nb,
                      grid=mamba.DEFAULT_GRID,
                      edge=mamba.FILLED):
    """
    This operator compares the value of each pixel of image 'imIn'
    with the value of its neighbors encoded in 'nb'.
    If all the neighbor values are different, the pixel is unchanged.
    Otherwise, it takes value 0.
    This operator works on hexagonal or square 'grid' and
    'edge' is set to FILLED by default.
    This operator works for 8-bit and 32-bit images.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn, 1)
    imWrk4 = mamba.imageMb(imIn, 1)
    for d in mamba.getDirections(grid):
        ed = 1 << d
        if (nb & ed):
            mamba.copy(imIn, imWrk1)
            mamba.copy(imIn, imWrk2)
            mamba.supNeighbor(imWrk1, imWrk1, ed, grid=grid, edge=edge)
            mamba.infNeighbor(imWrk2, imWrk2, ed, grid=grid, edge=edge)
            mamba.generateSupMask(imWrk2, imWrk1, imWrk3, False)
            mamba.logic(imWrk4, imWrk3, imWrk4, "or")
    mamba.convertByMask(imWrk4, imWrk1, mamba.computeMaxRange(imIn)[1], 0)
    mamba.logic(imIn, imWrk1, imOut, "inf")
コード例 #6
0
def _sparseConjugateHexagonDilate(imIn, imOut, size, edge=mamba.EMPTY):
    """
    Dilation by a conjugate hexagon. The structuring element used by this operation
    is not complete. Some holes appear inside the structuring element. Therefore, this
    operation should not be used to obtain true conjugate hexagons dilations (for
    internal use only).
    """   

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    val = mamba.computeMaxRange(imIn)[1]*int(edge!=mamba.EMPTY)
    for i in _sizeSplit(size):
        mamba.copy(imOut, imWrk1)
        j = 2*i
        supFarNeighbor(imWrk1, imOut, 1, j, grid=mamba.SQUARE, edge=edge)
        mamba.shift(imWrk1, imWrk2, 2, i, val, grid=mamba.HEXAGONAL)
        supFarNeighbor(imWrk2, imOut, 4, i, grid=mamba.HEXAGONAL, edge=edge)
        supFarNeighbor(imWrk2, imOut, 6, i, grid=mamba.HEXAGONAL, edge=edge)
        supFarNeighbor(imWrk1, imOut, 5, j, grid=mamba.SQUARE, edge=edge)
        mamba.shift(imWrk1, imWrk2, 5, i, val, grid=mamba.HEXAGONAL)
        supFarNeighbor(imWrk2, imOut, 1, i, grid=mamba.HEXAGONAL, edge=edge)
        supFarNeighbor(imWrk2, imOut, 3, i, grid=mamba.HEXAGONAL, edge=edge)
        j = 3*i//2
        supFarNeighbor(imWrk1, imOut, 2, j, grid=mamba.HEXAGONAL, edge=edge)
        supFarNeighbor(imWrk1, imOut, 5, j, grid=mamba.HEXAGONAL, edge=edge)
コード例 #7
0
ファイル: measure.py プロジェクト: nicolasBeucher/mamba-image
def computeDiameter(imIn, dir, scale=(1.0, 1.0), grid=mamba.DEFAULT_GRID):
    """
    Computes the diameter (diametral variation) of binary image 'imIn' in 
    direction 'dir'. 'scale' is a tuple defining the horizontal and vertical
    scale factors (default is 1.0).
    
    Beware, if the input image 'imIn' is not a binary image, the function raises
    an error.
    """
    
    if imIn.getDepth() != 1:
        mamba.raiseExceptionOnError(core.MB_ERR_BAD_DEPTH)
    if dir == 0:
        return 0.0
    dir = ((dir - 1)%(mamba.gridNeighbors(grid)//2)) +1
    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk)
    mamba.diffNeighbor(imIn, imWrk, 1<<dir, grid=grid)
    if grid == mamba.HEXAGONAL:
        l = scale[1]
        if dir != 2:
            l = 2*l*scale[0]/math.sqrt(scale[0]*scale[0] + 4*scale[1]*scale[1])
    else:
        if dir == 1:
            l = scale[0]
        elif dir == 3:
            l = scale[1]
        else:
            l = scale[0]*scale[1]/math.sqrt(scale[0]*scale[0] + scale[1]*scale[1])
    l = l*mamba.computeVolume(imWrk)
    return l
コード例 #8
0
def largeHexagonalErode(imIn, imOut, size, edge=mamba.FILLED):
    """
    Erosion by large hexagons using erosions by large segments and the Steiner
    decomposition property of the hexagon.
    Edge effects are corrected by erosions with transposed decompositions
    combined with inf operations (see documentation for further details).
    
    This operator is quite complex to avoid edge effects.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    sizemax = min(imIn.getSize())//2
    # If size larger than sizemax, the operation must be iterated to prevent edge effects.
    n = size
    mamba.copy(imIn, imOut)
    while n > 0:
        s = min(n, sizemax)
        largeLinearErode(imOut, imWrk1, 6, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imWrk1, imWrk1, 4, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imOut, imWrk2, 4, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imWrk2, imWrk2, 6, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imWrk1, imWrk2, imWrk1, "inf")
        largeLinearErode(imWrk1, imWrk2, 2, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imOut, imWrk1, 1, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imWrk1, imWrk1, 3, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imOut, imOut, 3, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imOut, imOut, 1, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imWrk1, imOut, imWrk1, "inf")
        largeLinearErode(imWrk1, imOut, 5, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imOut, imWrk2, imOut, "inf")
        n = n - s
コード例 #9
0
def _sparseConjugateHexagonDilate(imIn, imOut, size, edge=mamba.EMPTY):
    """
    Dilation by a conjugate hexagon. The structuring element used by this operation
    is not complete. Some holes appear inside the structuring element. Therefore, this
    operation should not be used to obtain true conjugate hexagons dilations (for
    internal use only).
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    val = mamba.computeMaxRange(imIn)[1] * int(edge != mamba.EMPTY)
    for i in _sizeSplit(size):
        mamba.copy(imOut, imWrk1)
        j = 2 * i
        supFarNeighbor(imWrk1, imOut, 1, j, grid=mamba.SQUARE, edge=edge)
        mamba.shift(imWrk1, imWrk2, 2, i, val, grid=mamba.HEXAGONAL)
        supFarNeighbor(imWrk2, imOut, 4, i, grid=mamba.HEXAGONAL, edge=edge)
        supFarNeighbor(imWrk2, imOut, 6, i, grid=mamba.HEXAGONAL, edge=edge)
        supFarNeighbor(imWrk1, imOut, 5, j, grid=mamba.SQUARE, edge=edge)
        mamba.shift(imWrk1, imWrk2, 5, i, val, grid=mamba.HEXAGONAL)
        supFarNeighbor(imWrk2, imOut, 1, i, grid=mamba.HEXAGONAL, edge=edge)
        supFarNeighbor(imWrk2, imOut, 3, i, grid=mamba.HEXAGONAL, edge=edge)
        j = 3 * i // 2
        supFarNeighbor(imWrk1, imOut, 2, j, grid=mamba.HEXAGONAL, edge=edge)
        supFarNeighbor(imWrk1, imOut, 5, j, grid=mamba.HEXAGONAL, edge=edge)
コード例 #10
0
def largeHexagonalErode(imIn, imOut, size, edge=mamba.FILLED):
    """
    Erosion by large hexagons using erosions by large segments and the Steiner
    decomposition property of the hexagon.
    Edge effects are corrected by erosions with transposed decompositions
    combined with inf operations (see documentation for further details).
    
    This operator is quite complex to avoid edge effects.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    sizemax = min(imIn.getSize()) // 2
    # If size larger than sizemax, the operation must be iterated to prevent edge effects.
    n = size
    mamba.copy(imIn, imOut)
    while n > 0:
        s = min(n, sizemax)
        largeLinearErode(imOut, imWrk1, 6, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imWrk1, imWrk1, 4, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imOut, imWrk2, 4, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imWrk2, imWrk2, 6, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imWrk1, imWrk2, imWrk1, "inf")
        largeLinearErode(imWrk1, imWrk2, 2, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imOut, imWrk1, 1, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imWrk1, imWrk1, 3, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imOut, imOut, 3, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearErode(imOut, imOut, 1, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imWrk1, imOut, imWrk1, "inf")
        largeLinearErode(imWrk1, imOut, 5, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imOut, imWrk2, imOut, "inf")
        n = n - s
コード例 #11
0
def supOpen(imIn, imOut, n, grid=mamba.DEFAULT_GRID):
    """
    Performs the supremum of directional openings. A white particle is preserved
    (but not entirely) if its length is larger than 'n' in at least one direction.
    
    This operator is an opening. The image edge is set to 'EMPTY' in order to 
    take into account particles touching the edge (they are considered as entirely
    included in the image window).

    When square grid is used, the size in oblique directions are reduced to be
    similar to the horizontal and vertical size.    
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk1.reset()
    if grid == mamba.SQUARE:
        size = int((1.4142 * n + 1)/2)
        linearOpen(imIn, imWrk2, 2, size, edge=mamba.EMPTY, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
        linearOpen(imIn, imWrk2, 4, size, edge=mamba.EMPTY, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
        d = 4
    else:
        d = 6
    for i in range(1, d, 2):
        linearOpen(imIn, imWrk2, i, n, edge=mamba.EMPTY, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
    mamba.copy(imWrk1, imOut)
コード例 #12
0
ファイル: script.py プロジェクト: nicolasBeucher/mamba-image
def vectorGradient(imIn, imModul, imAzim, size=1):
    """
    Computes modulus (result in 'imModul') and azimut (in 'imAzim') of image
    'imIn'. The 'size' of each directional gradient is set to 1 by default.
    This operator is defined on the hexagonal grid (12 directions are used).
    Note that this operator belongs to the residual operators class.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn)
    imWrk4 = mamba.imageMb(imIn, 1)

    mamba.copy(imIn, imWrk1)
    imModul.reset()
    imAzim.reset()
    for i in range(12):
        d = i + 1
        # Directional gradient obtained with linear erosions and dilations.
        directionalDilate(imWrk1, imWrk2, d, size)
        directionalErode(imWrk1, imWrk3, d, size)
        mamba.sub(imWrk2, imWrk3, imWrk2)
        # For each direction, maximal pixels are indexed in a mask image.
        mamba.generateSupMask(imWrk2, imModul, imWrk4, True)
        mamba.convertByMask(imWrk4, imWrk3, 0, d)
        # Modulus and azimut are calculated.
        mamba.logic(imWrk2, imModul, imModul, "sup")
        mamba.logic(imWrk3, imAzim, imAzim, "sup")
コード例 #13
0
def mulRealConst(imIn, v, imOut, nearest=False, precision=2):
    """
    Multiplies image 'imIn' by a real positive constant value 'v' and puts the 
    result in image 'imOut'. 'imIn' and 'imOut' can be 8-bit or 32-bit images.
    If 'imOut' is greyscale (8-bit), the result is saturated (results
    of the multiplication greater than 255 are limited to this value).
    'precision' indicates the number of decimal digits taken into account for
    the constant 'v' (default is 2).
    If 'nearest' is true, the result is rounded to the nearest integer value.
    If not (default), the result is simply truncated.
    """
    
    if imIn.getDepth()==1 or imOut.getDepth()==1:
        mamba.raiseExceptionOnError(core.MB_ERR_BAD_DEPTH)
    imWrk1 = mamba.imageMb(imIn, 32)
    imWrk2 = mamba.imageMb(imIn, 1)
    precVal = (10 ** precision)
    v1 = int(v * precVal)
    if imIn.getDepth()==8:
        imWrk1.reset()
        mamba.copyBytePlane(imIn, 0, imWrk1)
    else:
        mamba.copy(imIn, imWrk1)
    mulConst(imWrk1, v1, imWrk1)
    if nearest:
        adjVal = int(5 * (10 ** (precision - 1)))
        addConst(imWrk1, adjVal , imWrk1)
    divConst(imWrk1, precVal, imWrk1)
    if imOut.getDepth()==8:
        mamba.threshold(imWrk1, imWrk2, 255, mamba.computeMaxRange(imWrk1)[1])
        mamba.copyBytePlane(imWrk1, 0, imOut)
        imWrk2.convert(8)
        mamba.logic(imOut, imWrk2, imOut, "sup")
    else:
        mamba.copy(imWrk1, imOut)
コード例 #14
0
def cellsBuild(imIn, imInOut, grid=mamba.DEFAULT_GRID):
    """
    Geodesic reconstruction of the cells of the partition image 'imIn' which
    are marked by the image 'imInOut'. The marked cells take the value of
    their corresponding marker. Note that the background cells (labelled by 0)
    are also modified if they are marked.
    The result is stored in 'imInOut'.
    The images can be 8-bit or 32-bit images.
    'grid' can be set to HEXAGONAL or SQUARE.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn, 1)
    vol = 0
    prec_vol = -1
    dirs = mamba.getDirections(grid)[1:]
    while (prec_vol!=vol):
        prec_vol = vol
        for d in dirs:
            ed = 1<<d
            mamba.copy(imIn, imWrk1)
            mamba.copy(imIn, imWrk2)
            mamba.supNeighbor(imWrk1, imWrk1, ed, grid=grid)
            mamba.infNeighbor(imWrk2, imWrk2, ed, grid=grid)
            mamba.generateSupMask(imWrk2, imWrk1, imWrk3, False)
            mamba.convertByMask(imWrk3, imWrk1, 0, mamba.computeMaxRange(imIn)[1])
            mamba.linearDilate(imInOut, imWrk2, d, 1, grid=grid)
            mamba.logic(imWrk2, imWrk1, imWrk2, "inf")
            v = mamba.buildNeighbor(imWrk1, imWrk2, d, grid=grid)
            mamba.logic(imWrk2, imInOut, imInOut, "sup")
        vol = mamba.computeVolume(imInOut)
コード例 #15
0
def _initialQuasiDist_(imIn, imOut1, imOut2, grid=mamba.DEFAULT_GRID):
    """
    Computes the initial quasi-distance. For internal use only. The resulting
    quasi-distance is not lipchitzian (see MM documentation for details).
    """
    
    maskIm = mamba.imageMb(imIn, 1)
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn, 32)
    se = mamba.structuringElement(mamba.getDirections(grid), grid)
    i = 0
    mamba.copy(imIn, imWrk1)
    v2 = mamba.computeVolume(imWrk1)
    v1 = v2 + 1
    imOut1.reset()
    imOut2.reset()
    while v1 > v2:
        i += 1
        v1 = v2
        mamba.erode(imWrk1, imWrk2, se=se)
        mamba.sub(imWrk1, imWrk2, imWrk1)
        _generateMask_(imWrk1, imOut1, maskIm)
        mamba.convertByMask(maskIm, imWrk3, 0, i)
        mamba.logic(imOut1, imWrk1, imOut1, "sup")
        mamba.logic(imOut2, imWrk3, imOut2, "sup")
        mamba.copy(imWrk2, imWrk1)
        v2 = mamba.computeVolume(imWrk1)
コード例 #16
0
def largeSquareAlternateFilter(imIn, imOut, start, end, step, openFirst):
    """
    Fast full alternate square filter of image 'imIn'. The initial size
    is equal to 'start', the final one is bounded by 'end' (this size is not
    taken into account), the increment of size is 'step'. If 'openFirst' is
    true, the filter starts with on opening. It starts with a closing otherwise.
    The result is put in 'imOut'.
    This operation is efficient if most of the sizes used in the filter are
    greater than 5. If it is not the case, the 'fullAlternateFilter' should
    be used instead (with a SQUARE structuring element).    
    """
    
    prev = 0
    mamba.copy(imIn, imOut)
    if openFirst:
        for i in range(start, end, step):
            t1 = i + prev
            t2 = 2 * i
            mamba.largeSquareErode(imOut, imOut, t1)
            mamba.largeSquareDilate(imOut, imOut, t2)
            prev = i
        mamba.largeSquareErode(imOut, imOut, prev)
    else:
        for i in range(start, end, step):
            t1 = i + prev
            t2 = 2 * i
            mamba.largeSquareDilate(imOut, imOut, t1)
            mamba.largeSquareErode(imOut, imOut, t2)
            prev = i
        mamba.largeSquareDilate(imOut, imOut, prev)
コード例 #17
0
def computeDiameter(imIn, dir, scale=(1.0, 1.0), grid=mamba.DEFAULT_GRID):
    """
    Computes the diameter (diametral variation) of binary image 'imIn' in 
    direction 'dir'. 'scale' is a tuple defining the horizontal and vertical
    scale factors (default is 1.0).
    
    Beware, if the input image 'imIn' is not a binary image, the function raises
    an error.
    """

    if imIn.getDepth() != 1:
        mamba.raiseExceptionOnError(core.MB_ERR_BAD_DEPTH)
    if dir == 0:
        return 0.0
    dir = ((dir - 1) % (mamba.gridNeighbors(grid) // 2)) + 1
    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk)
    mamba.diffNeighbor(imIn, imWrk, 1 << dir, grid=grid)
    if grid == mamba.HEXAGONAL:
        l = scale[1]
        if dir != 2:
            l = 2 * l * scale[0] / math.sqrt(scale[0] * scale[0] +
                                             4 * scale[1] * scale[1])
    else:
        if dir == 1:
            l = scale[0]
        elif dir == 3:
            l = scale[1]
        else:
            l = scale[0] * scale[1] / math.sqrt(scale[0] * scale[0] +
                                                scale[1] * scale[1])
    l = l * mamba.computeVolume(imWrk)
    return l
コード例 #18
0
def cellsBuild(imIn, imInOut, grid=mamba.DEFAULT_GRID):
    """
    Geodesic reconstruction of the cells of the partition image 'imIn' which
    are marked by the image 'imInOut'. The marked cells take the value of
    their corresponding marker. Note that the background cells (labelled by 0)
    are also modified if they are marked.
    The result is stored in 'imInOut'.
    The images can be 8-bit or 32-bit images.
    'grid' can be set to HEXAGONAL or SQUARE.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn, 1)
    vol = 0
    prec_vol = -1
    dirs = mamba.getDirections(grid)[1:]
    while (prec_vol != vol):
        prec_vol = vol
        for d in dirs:
            ed = 1 << d
            mamba.copy(imIn, imWrk1)
            mamba.copy(imIn, imWrk2)
            mamba.supNeighbor(imWrk1, imWrk1, ed, grid=grid)
            mamba.infNeighbor(imWrk2, imWrk2, ed, grid=grid)
            mamba.generateSupMask(imWrk2, imWrk1, imWrk3, False)
            mamba.convertByMask(imWrk3, imWrk1, 0,
                                mamba.computeMaxRange(imIn)[1])
            mamba.linearDilate(imInOut, imWrk2, d, 1, grid=grid)
            mamba.logic(imWrk2, imWrk1, imWrk2, "inf")
            v = mamba.buildNeighbor(imWrk1, imWrk2, d, grid=grid)
            mamba.logic(imWrk2, imInOut, imInOut, "sup")
        vol = mamba.computeVolume(imInOut)
コード例 #19
0
def supOpen(imIn, imOut, n, grid=mamba.DEFAULT_GRID):
    """
    Performs the supremum of directional openings. A white particle is preserved
    (but not entirely) if its length is larger than 'n' in at least one direction.
    
    This operator is an opening. The image edge is set to 'EMPTY' in order to 
    take into account particles touching the edge (they are considered as entirely
    included in the image window).

    When square grid is used, the size in oblique directions are reduced to be
    similar to the horizontal and vertical size.    
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk1.reset()
    if grid == mamba.SQUARE:
        size = int((1.4142 * n + 1) / 2)
        linearOpen(imIn, imWrk2, 2, size, edge=mamba.EMPTY, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
        linearOpen(imIn, imWrk2, 4, size, edge=mamba.EMPTY, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
        d = 4
    else:
        d = 6
    for i in range(1, d, 2):
        linearOpen(imIn, imWrk2, i, n, edge=mamba.EMPTY, grid=grid)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
    mamba.copy(imWrk1, imOut)
コード例 #20
0
def fullThin(imIn, imOut, dse, edge=mamba.EMPTY):
    """
    Performs a complete thinning of 'imIn' with the successive rotations of 'dse'
    (until idempotence) and puts the result in 'imOut'.
    
    'imIn' and 'imOut' are binary images.
    
    'edge' is set to EMPTY by default.
    """

    if edge == mamba.EMPTY:
        imWrk = mamba.imageMb(imIn)
        mamba.copy(imIn, imOut)
        v1 = mamba.computeVolume(imOut)
        v2 = 0
        while v1 != v2:
            v2 = v1
            for i in range(mamba.gridNeighbors(dse.getGrid())):
                hitOrMiss(imOut, imWrk, dse)
                mamba.diff(imOut, imWrk, imOut)
                dse = dse.rotate()
            v1 = mamba.computeVolume(imOut)
    else:
        mamba.negate(imIn, imOut)
        v1 = mamba.computeVolume(imOut)
        v2 = 0
        while v1 != v2:
            v2 = v1
            rotatingThick(imOut, imOut, dse.flip())
            v1 = mamba.computeVolume(imOut)
        mamba.negate(imOut, imOut)
コード例 #21
0
def vectorGradient(imIn, imModul, imAzim, size=1):
    """
    Computes modulus (result in 'imModul') and azimut (in 'imAzim') of image
    'imIn'. The 'size' of each directional gradient is set to 1 by default.
    This operator is defined on the hexagonal grid (12 directions are used).
    Note that this operator belongs to the residual operators class.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn)
    imWrk4 = mamba.imageMb(imIn, 1)
    
    mamba.copy(imIn, imWrk1)
    imModul.reset()
    imAzim.reset()
    for i in range(12):
        d = i + 1
        # Directional gradient obtained with linear erosions and dilations.
        directionalDilate(imWrk1, imWrk2, d, size)
        directionalErode(imWrk1, imWrk3, d, size)
        mamba.sub(imWrk2, imWrk3, imWrk2)
        # For each direction, maximal pixels are indexed in a mask image.
        mamba.generateSupMask(imWrk2, imModul, imWrk4, True)
        mamba.convertByMask(imWrk4, imWrk3, 0, d)
        # Modulus and azimut are calculated.
        mamba.logic(imWrk2, imModul, imModul, "sup")
        mamba.logic(imWrk3, imAzim, imAzim, "sup")
コード例 #22
0
def quasiDistance(imIn, imOut1, imOut2, grid=mamba.DEFAULT_GRID):
    """
    Quasi-distance of image 'imIn'. 'imOut1' contains the residues image
    and 'imOut2' contains the quasi-distance (associated function).
    
    The quasi-distance of a greytone image is made of a patch of distance
    functions of some almost flat regions in the image. When the image is a
    simple indicator function of a set, the quasi-distance and the distance
    function are identical.

    Depth of 'imOut1' is the same as 'imIn', depth of 'imOut2' is 32.
    """

    imWrk1 = mamba.imageMb(imIn, 32)
    imWrk2 = mamba.imageMb(imIn, 32)
    imWrk3 = mamba.imageMb(imIn, 32)
    maskIm = mamba.imageMb(imIn, 1) 
    se = mamba.structuringElement(mamba.getDirections(grid), grid)
    _initialQuasiDist_(imIn, imOut1, imOut2, grid=grid)
    mamba.copy(imOut2, imWrk1)
    v1 = mamba.computeVolume(imOut2)
    v2 = v1 + 1
    while v2 > v1:
        v2 = v1
        mamba.erode(imWrk1, imWrk2, se=se)
        mamba.sub(imWrk1, imWrk2, imWrk2)
        mamba.threshold(imWrk2, maskIm, 2, mamba.computeMaxRange(imWrk2)[1])
        mamba.convertByMask(maskIm, imWrk3, 0, mamba.computeMaxRange(imWrk3)[1])
        mamba.logic(imWrk2, imWrk3, imWrk2, "inf")
        mamba.subConst(imWrk2, 1, imWrk3)
        mamba.logic(imWrk2, imWrk3, imWrk2, "inf") # Patch non saturated subtraction
        mamba.sub(imWrk1, imWrk2, imWrk1)
        v1 = mamba.computeVolume(imWrk1)
    mamba.copy(imWrk1, imOut2)
コード例 #23
0
def rotatingThin(imIn, imOut, dse, edge=mamba.FILLED):
    """
    Performs a complete rotation of thinnings , the initial 'dse' double
    structuring element being turned one step clockwise after each thinning.
    At each rotation step, the previous result is used as input for the next
    thinning (chained thinnings). Depending on the grid where 'dse' is defined,
    6 or 8 rotations are performed.
    
    'imIn' and 'imOut' are binary images.
    
    'edge' is set to FILLED by default (default value is EMPTY in simple thin).
    """
    
    imWrk = mamba.imageMb(imIn)
    if edge == mamba.FILLED:
        mamba.negate(imIn, imOut)
        for d in mamba.getDirections(dse.getGrid(), True):
            hitOrMiss(imOut, imWrk, dse.flip(), edge=mamba.EMPTY)
            mamba.logic(imWrk, imOut, imOut, "sup")
            dse = dse.rotate()
        mamba.negate(imOut, imOut)
    else:
        mamba.copy(imIn, imOut)
        for d in mamba.getDirections(dse.getGrid(), True):
            hitOrMiss(imOut, imWrk, dse, edge=mamba.EMPTY)
            mamba.diff(imOut, imWrk, imOut)
            dse = dse.rotate()
コード例 #24
0
def fullThin(imIn, imOut, dse, edge=mamba.EMPTY):
    """
    Performs a complete thinning of 'imIn' with the successive rotations of 'dse'
    (until idempotence) and puts the result in 'imOut'.
    
    'imIn' and 'imOut' are binary images.
    
    'edge' is set to EMPTY by default.
    """
    
    if edge == mamba.EMPTY:
        imWrk = mamba.imageMb(imIn)
        mamba.copy(imIn, imOut)
        v1 = mamba.computeVolume(imOut)
        v2 = 0
        while v1 != v2:
            v2 = v1
            for i in range(mamba.gridNeighbors(dse.getGrid())):
                hitOrMiss(imOut, imWrk, dse)
                mamba.diff(imOut, imWrk, imOut)
                dse = dse.rotate()
            v1 = mamba.computeVolume(imOut)
    else:
        mamba.negate(imIn, imOut)
        v1 = mamba.computeVolume(imOut)
        v2 = 0
        while v1 != v2:
            v2 = v1
            rotatingThick(imOut, imOut, dse.flip())
            v1 = mamba.computeVolume(imOut)
        mamba.negate(imOut, imOut)
コード例 #25
0
ファイル: erodil.py プロジェクト: nicolasBeucher/mamba-image
def isotropicDistance(imIn, imOut, edge=mamba.FILLED):
    """
    Computes the distance function of a set in 'imIn'. This distance function
    uses dodecagonal erosions and the grid is assumed to be hexagonal.
    The procedure is quite slow but the result is more aesthetic.
    This operator also illustrates how to perform successive dodecagonal
    operations of increasing sizes.
    """

    if imIn.getDepth() != 1:
        mamba.raiseExceptionOnError(core.MB_ERR_BAD_DEPTH)
    imOut.reset()
    oldn = 0
    size = 0
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk1)
    while mamba.computeVolume(imWrk1) != 0:
        mamba.add(imOut, imWrk1, imOut)
        size += 1
        n = int(0.4641 * size)
        n += abs(n % 2 - size % 2)
        if (n - oldn) == 1:
            mamba.copy(imWrk1, imWrk2)
            mamba.erode(imWrk1, imWrk1, 1, se=mamba.HEXAGON, edge=edge)
        else:
            mamba.conjugateHexagonalErode(imWrk2, imWrk1, 1, edge=edge)
        oldn = n
コード例 #26
0
def nonEqualNeighbors(imIn, imOut, nb, grid=mamba.DEFAULT_GRID, edge=mamba.FILLED):
    """
    This operator compares the value of each pixel of image 'imIn'
    with the value of its neighbors encoded in 'nb'.
    If all the neighbor values are different, the pixel is unchanged.
    Otherwise, it takes value 0.
    This operator works on hexagonal or square 'grid' and
    'edge' is set to FILLED by default.
    This operator works for 8-bit and 32-bit images.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn, 1)
    imWrk4 = mamba.imageMb(imIn, 1)
    for d in mamba.getDirections(grid):
        ed = 1<<d
        if (nb & ed):
            mamba.copy(imIn, imWrk1)
            mamba.copy(imIn, imWrk2)
            mamba.supNeighbor(imWrk1, imWrk1, ed, grid=grid, edge=edge)
            mamba.infNeighbor(imWrk2, imWrk2, ed, grid=grid, edge=edge)
            mamba.generateSupMask(imWrk2, imWrk1, imWrk3, False)
            mamba.logic(imWrk4, imWrk3, imWrk4, "or")
    mamba.convertByMask(imWrk4, imWrk1, mamba.computeMaxRange(imIn)[1], 0)
    mamba.logic(imIn, imWrk1, imOut, "inf")
コード例 #27
0
def cellsHMT(imIn, imOut, dse, edge=mamba.EMPTY):
    """
    A Hit-Or-Miss transform is performed on each cell of the partition 'imIn'.
    'dse' is a double structuring element (see thinthick.py module).
    The result is put in 'imOut'. 'edge' is set to EMPTY by default.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    grid = dse.getGrid()
    cse0 = dse.getStructuringElement(0)
    cse1 = dse.getStructuringElement(1)
    mamba.copy(imIn, imOut)
    mamba.copy(imIn, imWrk1)
    equalNeighbors(imWrk1,
                   imWrk2,
                   cse1.getEncodedDirections(withoutZero=True),
                   grid=grid,
                   edge=edge)
    mamba.logic(imOut, imWrk2, imOut, "inf")
    nonEqualNeighbors(imWrk1,
                      imWrk2,
                      cse0.getEncodedDirections(withoutZero=True),
                      grid=grid,
                      edge=edge)
    mamba.logic(imOut, imWrk2, imOut, "inf")
コード例 #28
0
def largeHexagonalDilate(imIn, imOut, size, edge=mamba.EMPTY):
    """
    Dilation by large hexagons using dilations by large segments and the Steiner
    decomposition property of the hexagon.
    Edge effects are corrected by dilations with transposed decompositions
    combined with sup operators.
    
    This operator is quite complex to avoid edge effects.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    sizemax = min(imIn.getSize())//2
    # If size larger than sizemax, the operation must be iterated to prevent edge effects.
    n = size
    mamba.copy(imIn, imOut)
    while n >  0:
        s = min(n, sizemax)
        largeLinearDilate(imOut, imWrk1, 6, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imWrk1, imWrk1, 4, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imOut, imWrk2, 4, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imWrk2, imWrk2, 6, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
        largeLinearDilate(imWrk1, imWrk2, 2, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imOut, imWrk1, 1, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imWrk1, imWrk1, 3, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imOut, imOut, 3, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imOut, imOut, 1, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imWrk1, imOut, imWrk1, "sup")
        largeLinearDilate(imWrk1, imOut, 5, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imOut, imWrk2, imOut, "sup")
        n = n - s
コード例 #29
0
def largeOctogonalAlternateFilter(imIn, imOut, start, end, step, openFirst):
    """
    Fast full alternate octogonal filter of image 'imIn'. The initial size
    is equal to 'start', the final one is limited by 'end' (this size is not
    taken into account), the increment of size is 'step'. If 'openFirst' is
    true, the filter starts with on opening. It starts with a closing otherwise.
    The result is put in 'imOut'.
    """
    
    prev = 0
    mamba.copy(imIn, imOut)
    if openFirst:
        for i in range(start, end, step):
            t1 = i + prev
            t2 = 2 * i
            mamba.largeOctogonalErode(imOut, imOut, t1)
            mamba.largeOctogonalDilate(imOut, imOut, t2)
            prev = i
        mamba.largeOctogonalErode(imOut, imOut, prev)
    else:
        for i in range(start, end, step):
            t1 = i + prev
            t2 = 2 * i
            mamba.largeOctogonalDilate(imOut, imOut, t1)
            mamba.largeOctogonalErode(imOut, imOut, t2)
            prev = i
        mamba.largeOctogonalDilate(imOut, imOut, prev)
コード例 #30
0
ファイル: segment.py プロジェクト: nicolasBeucher/mamba-image
def mosaic(imIn, imOut, imWts, grid=mamba.DEFAULT_GRID):
    """
    Builds the mosaic image of 'imIn' and puts the results into 'imOut'.
    The watershed line (pixel values set to 255) is stored in the 
    greytone image 'imWts'. A mosaic image is a simple image made of various 
    tiles of uniform grey values. It is built using the watershed of 'imIn' 
    gradient and original markers made of gradient minima which are labelled by
    the maximum value of 'imIn' pixels inside them.
    """

    imWrk1 = mamba.imageMb(imIn, 1)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk2)
    im_mark = mamba.imageMb(imIn, 32)
    se = mamba.structuringElement(mamba.getDirections(grid), grid)
    mamba.gradient(imIn, imOut, se=se)
    mamba.minima(imOut, imWrk1, grid=grid)
    mamba.add(im_mark, imWrk1, im_mark)
    imWrk1.convert(8)
    mamba.build(imWrk1, imWrk2, grid=grid)
    mamba.add(im_mark, imWrk2, im_mark)
    watershedSegment(imOut, im_mark, grid=grid)
    mamba.copyBytePlane(im_mark, 3, imWts)
    mamba.subConst(im_mark, 1, im_mark)
    mamba.copyBytePlane(im_mark, 0, imOut)
コード例 #31
0
def copy3D(imIn, imOut, firstPlaneIn=0, firstPlaneOut=0):
    """
    Copies 3D image 'imIn' into 'imOut'. 'firstPlaneIn' indicates the starting
    plane inside 'imIn' and 'firstPlaneOut' the starting plane inside 'imOut'.
    """
    nbPlanes = min(len(imOut)-firstPlaneOut, len(imIn)-firstPlaneIn)
    for i in range(nbPlanes):
        mamba.copy(imIn[i+firstPlaneIn], imOut[i+firstPlaneOut])
コード例 #32
0
def copy3D(imIn, imOut, firstPlaneIn=0, firstPlaneOut=0):
    """
    Copies 3D image 'imIn' into 'imOut'. 'firstPlaneIn' indicates the starting
    plane inside 'imIn' and 'firstPlaneOut' the starting plane inside 'imOut'.
    """
    nbPlanes = min(len(imOut) - firstPlaneOut, len(imIn) - firstPlaneIn)
    for i in range(nbPlanes):
        mamba.copy(imIn[i + firstPlaneIn], imOut[i + firstPlaneOut])
コード例 #33
0
def generalSegment(imIn, imOut, gain=2.0, offset=1, grid=mamba.DEFAULT_GRID):
    """
    General segmentation algorithm. This algorithm is controlled by two
    parameters: the 'gain' (identical to the gain used in standard and P
    segmentation) and a new one, the 'offset'. The 'offset' indicates which
    level of hierarchy is compared to the current hierarchical image.
    The 'offset' is relative to the current hierarchical level. If 'offset' is
    equal to 1, this operator corresponds to the standard segmentation, if
    'offset' is equal to 255 (this value stands for the infinity), the operator
    is equivalent to P algorithm.
    Image 'imOut' contains all these hierarchies which are embedded.
    'imIn' and 'imOut' must be greyscale images. 'imIn' and 'imOut' must be
    different.
    This transformation returns the number of hierarchical levels.    
    """
    
    imWrk0 = mamba.imageMb(imIn)
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn)
    imWrk4 = mamba.imageMb(imIn, 1)
    imWrk5 = mamba.imageMb(imIn, 1)
    imWrk6 = mamba.imageMb(imIn, 32)    
    mamba.copy(imIn, imWrk1)
    mamba.mulRealConst(imIn, gain, imWrk6)
    mamba.floorSubConst(imWrk6, 1, imWrk6)
    mamba.threshold(imWrk6, imWrk4, 255, mamba.computeMaxRange(imWrk6)[1])  
    mamba.copyBytePlane(imWrk6, 0, imWrk0)
    mamba.convert(imWrk4, imWrk2)
    mamba.logic(imWrk0, imWrk2, imWrk0, "sup")
    mamba.logic(imWrk0, imWrk1, imWrk0, "sup")
    imOut.reset()
    nbLevels = 0
    mamba.threshold(imWrk1, imWrk4, 1, 255)
    flag = not(mamba.checkEmptiness(imWrk4))
    while flag:
        nbLevels += 1
        hierarchy(imWrk1, imWrk4, imWrk2, grid=grid)
        mamba.add(imOut, imWrk4, imOut)
        v = max(nbLevels - offset, 0) + 1
        mamba.threshold(imOut, imWrk4, v, 255)
        mamba.valuedWatershed(imWrk2, imWrk3, grid=grid)
        mamba.threshold(imWrk3, imWrk5, 1, 255)
        flag = not(mamba.checkEmptiness(imWrk5))
        hierarchy(imWrk3, imWrk5, imWrk2, grid=grid)
        mamba.generateSupMask(imWrk0, imWrk2, imWrk5, strict=False)
        mamba.logic(imWrk4, imWrk5, imWrk4, "inf")
        mamba.convertByMask(imWrk4, imWrk3, 0, 255)
        mamba.logic(imWrk1, imWrk3, imWrk3, "inf")
        mamba.negate(imWrk4, imWrk4)
        mamba.label(imWrk4, imWrk6, grid=grid)
        mamba.watershedSegment(imWrk3, imWrk6, grid=grid)
        mamba.copyBytePlane(imWrk6, 3, imWrk3)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
        mamba.logic(imWrk1, imWrk3, imWrk1, "inf")
        mamba.threshold(imWrk1, imWrk4, 1, 255)
    return nbLevels
コード例 #34
0
def generalSegment(imIn, imOut, gain=2.0, offset=1, grid=mamba.DEFAULT_GRID):
    """
    General segmentation algorithm. This algorithm is controlled by two
    parameters: the 'gain' (identical to the gain used in standard and P
    segmentation) and a new one, the 'offset'. The 'offset' indicates which
    level of hierarchy is compared to the current hierarchical image.
    The 'offset' is relative to the current hierarchical level. If 'offset' is
    equal to 1, this operator corresponds to the standard segmentation, if
    'offset' is equal to 255 (this value stands for the infinity), the operator
    is equivalent to P algorithm.
    Image 'imOut' contains all these hierarchies which are embedded.
    'imIn' and 'imOut' must be greyscale images. 'imIn' and 'imOut' must be
    different.
    This transformation returns the number of hierarchical levels.    
    """

    imWrk0 = mamba.imageMb(imIn)
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn)
    imWrk4 = mamba.imageMb(imIn, 1)
    imWrk5 = mamba.imageMb(imIn, 1)
    imWrk6 = mamba.imageMb(imIn, 32)
    mamba.copy(imIn, imWrk1)
    mamba.mulRealConst(imIn, gain, imWrk6)
    mamba.floorSubConst(imWrk6, 1, imWrk6)
    mamba.threshold(imWrk6, imWrk4, 255, mamba.computeMaxRange(imWrk6)[1])
    mamba.copyBytePlane(imWrk6, 0, imWrk0)
    mamba.convert(imWrk4, imWrk2)
    mamba.logic(imWrk0, imWrk2, imWrk0, "sup")
    mamba.logic(imWrk0, imWrk1, imWrk0, "sup")
    imOut.reset()
    nbLevels = 0
    mamba.threshold(imWrk1, imWrk4, 1, 255)
    flag = not (mamba.checkEmptiness(imWrk4))
    while flag:
        nbLevels += 1
        hierarchy(imWrk1, imWrk4, imWrk2, grid=grid)
        mamba.add(imOut, imWrk4, imOut)
        v = max(nbLevels - offset, 0) + 1
        mamba.threshold(imOut, imWrk4, v, 255)
        mamba.valuedWatershed(imWrk2, imWrk3, grid=grid)
        mamba.threshold(imWrk3, imWrk5, 1, 255)
        flag = not (mamba.checkEmptiness(imWrk5))
        hierarchy(imWrk3, imWrk5, imWrk2, grid=grid)
        mamba.generateSupMask(imWrk0, imWrk2, imWrk5, strict=False)
        mamba.logic(imWrk4, imWrk5, imWrk4, "inf")
        mamba.convertByMask(imWrk4, imWrk3, 0, 255)
        mamba.logic(imWrk1, imWrk3, imWrk3, "inf")
        mamba.negate(imWrk4, imWrk4)
        mamba.label(imWrk4, imWrk6, grid=grid)
        mamba.watershedSegment(imWrk3, imWrk6, grid=grid)
        mamba.copyBytePlane(imWrk6, 3, imWrk3)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
        mamba.logic(imWrk1, imWrk3, imWrk1, "inf")
        mamba.threshold(imWrk1, imWrk4, 1, 255)
    return nbLevels
コード例 #35
0
def buildClose(imIn, imOut, n=1, se=mamba.DEFAULT_SE):
    """
    Performs a closing by dual reconstruction operation on image 'imIn' and puts
    the result in 'imOut'. 'n' controls the size of the closing.
    """
    
    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk)
    mamba.dilate(imIn, imOut, n, se=se)
    mamba.dualBuild(imWrk, imOut, grid=se.getGrid())
コード例 #36
0
def buildOpen(imIn, imOut, n=1, se=mamba.DEFAULT_SE):
    """
    Performs an opening by reconstruction operation on image 'imIn' and puts the
    result in 'imOut'. 'n' controls the size of the opening.
    """
    
    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk)
    mamba.erode(imIn, imOut, n, se=se)
    mamba.build(imWrk, imOut, grid=se.getGrid())
コード例 #37
0
def buildClose(imIn, imOut, n=1, se=mamba.DEFAULT_SE):
    """
    Performs a closing by dual reconstruction operation on image 'imIn' and puts
    the result in 'imOut'. 'n' controls the size of the closing.
    """

    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk)
    mamba.dilate(imIn, imOut, n, se=se)
    mamba.dualBuild(imWrk, imOut, grid=se.getGrid())
コード例 #38
0
def buildOpen(imIn, imOut, n=1, se=mamba.DEFAULT_SE):
    """
    Performs an opening by reconstruction operation on image 'imIn' and puts the
    result in 'imOut'. 'n' controls the size of the opening.
    """

    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk)
    mamba.erode(imIn, imOut, n, se=se)
    mamba.build(imWrk, imOut, grid=se.getGrid())
コード例 #39
0
def largeLinearDilate(imIn, imOut, dir, size, grid=mamba.DEFAULT_GRID, edge=mamba.EMPTY):
    """
    Dilation by a large segment in direction 'dir' in a reduced number of iterations.
    Uses the dilations by doublets of points (supposed to be faster, thanks to
    an enhanced shift operator).
    """
    
    mamba.copy(imIn, imOut)
    for i in _sizeSplit(size):
        supFarNeighbor(imOut, imOut, dir, i, grid=grid, edge=edge)
コード例 #40
0
def standardSegment(imIn, imOut, gain=2.0, grid=mamba.DEFAULT_GRID):
    """
    General standard segmentation. This algorithm keeps the contours of the 
    watershed transform which are above or equal to the hierarchical image 
    associated to the next level of hierarchy when the altitude of the contour
    is multiplied by a 'gain' factor (default is 2.0). This transform also ends 
    by idempotence. All the hierarchical levels of image 'imIn'(which is a 
    valued watershed) are computed. 'imOut' contains all these hierarchies which
    are embedded, so that hierarchy i is simply obtained by a threshold
    [i+1, 255] of image 'imOut'.
    'imIn' and 'imOut' must be greyscale images. 'imIn' and 'imOut' must be
    different.
    This transformation returns the number of hierarchical levels.    
    """

    imWrk0 = mamba.imageMb(imIn)
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn)
    imWrk4 = mamba.imageMb(imIn, 1)
    imWrk5 = mamba.imageMb(imIn, 1)
    imWrk6 = mamba.imageMb(imIn, 32)
    mamba.copy(imIn, imWrk1)
    mamba.mulRealConst(imIn, gain, imWrk6)
    mamba.floorSubConst(imWrk6, 1, imWrk6)
    mamba.threshold(imWrk6, imWrk4, 255, mamba.computeMaxRange(imWrk6)[1])
    mamba.copyBytePlane(imWrk6, 0, imWrk0)
    mamba.convert(imWrk4, imWrk2)
    mamba.logic(imWrk0, imWrk2, imWrk0, "sup")
    mamba.logic(imWrk0, imWrk1, imWrk0, "sup")
    imOut.reset()
    nbLevels = 0
    mamba.threshold(imWrk1, imWrk4, 1, 255)
    flag = not (mamba.checkEmptiness(imWrk4))
    while flag:
        hierarchy(imWrk1, imWrk4, imWrk2, grid=grid)
        mamba.add(imOut, imWrk4, imOut)
        mamba.valuedWatershed(imWrk2, imWrk3, grid=grid)
        mamba.threshold(imWrk3, imWrk5, 1, 255)
        flag = not (mamba.checkEmptiness(imWrk5))
        hierarchy(imWrk3, imWrk5, imWrk2, grid=grid)
        mamba.generateSupMask(imWrk0, imWrk2, imWrk5, strict=False)
        mamba.logic(imWrk4, imWrk5, imWrk4, "inf")
        mamba.convertByMask(imWrk4, imWrk3, 0, 255)
        mamba.logic(imWrk1, imWrk3, imWrk3, "inf")
        mamba.negate(imWrk4, imWrk4)
        mamba.label(imWrk4, imWrk6, grid=grid)
        mamba.watershedSegment(imWrk3, imWrk6, grid=grid)
        mamba.copyBytePlane(imWrk6, 3, imWrk3)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
        mamba.logic(imWrk1, imWrk3, imWrk1, "inf")
        mamba.threshold(imWrk1, imWrk4, 1, 255)
        nbLevels += 1
    return nbLevels
コード例 #41
0
def standardSegment(imIn, imOut, gain=2.0, grid=mamba.DEFAULT_GRID):
    """
    General standard segmentation. This algorithm keeps the contours of the 
    watershed transform which are above or equal to the hierarchical image 
    associated to the next level of hierarchy when the altitude of the contour
    is multiplied by a 'gain' factor (default is 2.0). This transform also ends 
    by idempotence. All the hierarchical levels of image 'imIn'(which is a 
    valued watershed) are computed. 'imOut' contains all these hierarchies which
    are embedded, so that hierarchy i is simply obtained by a threshold
    [i+1, 255] of image 'imOut'.
    'imIn' and 'imOut' must be greyscale images. 'imIn' and 'imOut' must be
    different.
    This transformation returns the number of hierarchical levels.    
    """
    
    imWrk0 = mamba.imageMb(imIn)
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    imWrk3 = mamba.imageMb(imIn)
    imWrk4 = mamba.imageMb(imIn, 1)
    imWrk5 = mamba.imageMb(imIn, 1)
    imWrk6 = mamba.imageMb(imIn, 32)    
    mamba.copy(imIn, imWrk1)
    mamba.mulRealConst(imIn, gain, imWrk6)
    mamba.floorSubConst(imWrk6, 1, imWrk6)
    mamba.threshold(imWrk6, imWrk4, 255, mamba.computeMaxRange(imWrk6)[1])  
    mamba.copyBytePlane(imWrk6, 0, imWrk0)
    mamba.convert(imWrk4, imWrk2)
    mamba.logic(imWrk0, imWrk2, imWrk0, "sup")
    mamba.logic(imWrk0, imWrk1, imWrk0, "sup")
    imOut.reset()
    nbLevels = 0
    mamba.threshold(imWrk1, imWrk4, 1, 255)
    flag = not(mamba.checkEmptiness(imWrk4))
    while flag:
        hierarchy(imWrk1, imWrk4, imWrk2, grid=grid)
        mamba.add(imOut, imWrk4, imOut)
        mamba.valuedWatershed(imWrk2, imWrk3, grid=grid)
        mamba.threshold(imWrk3, imWrk5, 1, 255)
        flag = not(mamba.checkEmptiness(imWrk5))
        hierarchy(imWrk3, imWrk5, imWrk2, grid=grid)
        mamba.generateSupMask(imWrk0, imWrk2, imWrk5, strict=False)
        mamba.logic(imWrk4, imWrk5, imWrk4, "inf")
        mamba.convertByMask(imWrk4, imWrk3, 0, 255)
        mamba.logic(imWrk1, imWrk3, imWrk3, "inf")
        mamba.negate(imWrk4, imWrk4)
        mamba.label(imWrk4, imWrk6, grid=grid)
        mamba.watershedSegment(imWrk3, imWrk6, grid=grid)
        mamba.copyBytePlane(imWrk6, 3, imWrk3)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
        mamba.logic(imWrk1, imWrk3, imWrk1, "inf")
        mamba.threshold(imWrk1, imWrk4, 1, 255)
        nbLevels += 1
    return nbLevels
コード例 #42
0
ファイル: erodil.py プロジェクト: nicolasBeucher/mamba-image
def conjugateHexagonalDilate(imIn, imOut, size, edge=mamba.EMPTY):
    """
    Dilation by a conjugate hexagon (hexagon turned by 30 degrees).
    Be aware that the size of operation corresponds to twice the size of the
    regular hexagon: a conjugate hexagon of size 1 is inscribed in a regular
    hexagon of size 2.
    """

    mamba.copy(imIn, imOut)
    for i in range(size):
        dilate(imOut, imOut, 1, se=TRIPOD, edge=edge)
        dilate(imOut, imOut, 1, se=TRIPOD.transpose(), edge=edge)
コード例 #43
0
def largeHexagonalDilate(imIn, imOut, size, edge=mamba.EMPTY):
    """
    Dilation by large hexagons using dilations by large segments and the Steiner
    decomposition property of the hexagon.
    Edge effects are corrected by dilations with transposed decompositions
    combined with sup operators.
    
    This operator is quite complex to avoid edge effects.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    sizemax = min(imIn.getSize()) // 2
    # If size larger than sizemax, the operation must be iterated to prevent edge effects.
    n = size
    mamba.copy(imIn, imOut)
    while n > 0:
        s = min(n, sizemax)
        largeLinearDilate(imOut, imWrk1, 6, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imWrk1,
                          imWrk1,
                          4,
                          s,
                          grid=mamba.HEXAGONAL,
                          edge=edge)
        largeLinearDilate(imOut, imWrk2, 4, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imWrk2,
                          imWrk2,
                          6,
                          s,
                          grid=mamba.HEXAGONAL,
                          edge=edge)
        mamba.logic(imWrk1, imWrk2, imWrk1, "sup")
        largeLinearDilate(imWrk1,
                          imWrk2,
                          2,
                          s,
                          grid=mamba.HEXAGONAL,
                          edge=edge)
        largeLinearDilate(imOut, imWrk1, 1, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imWrk1,
                          imWrk1,
                          3,
                          s,
                          grid=mamba.HEXAGONAL,
                          edge=edge)
        largeLinearDilate(imOut, imOut, 3, s, grid=mamba.HEXAGONAL, edge=edge)
        largeLinearDilate(imOut, imOut, 1, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imWrk1, imOut, imWrk1, "sup")
        largeLinearDilate(imWrk1, imOut, 5, s, grid=mamba.HEXAGONAL, edge=edge)
        mamba.logic(imOut, imWrk2, imOut, "sup")
        n = n - s
コード例 #44
0
def fullGeodesicThick(imIn, imMask, imOut, dse):
    """
    Performs a complete geodesic thickening (until idempotence) of image 'imIn'
    inside mask 'imMask' with all the rotations of the double structuring
    element 'dse'. The result is put in 'imOut'.
    """

    mamba.copy(imIn, imOut)
    v1 = mamba.computeVolume(imOut)
    v2 = 0
    while v1 != v2:
        v2 = v1
        rotatingGeodesicThick(imOut, imMask, imOut, dse)
        v1 = mamba.computeVolume(imOut)
コード例 #45
0
def linearClose(imIn, imOut, dir, n, grid=mamba.DEFAULT_GRID, edge=mamba.FILLED):
    """
    Performs a closing by a segment of size 'n' in direction 'dir'.
    
    If 'edge' is set to 'EMPTY', the operation must be modified to remain extensive.
    """
    
    imWrk = mamba.imageMb(imIn)
    if edge==mamba.EMPTY:
        mamba.copy(imIn, imWrk)
    mamba.linearDilate(imIn, imOut, dir, n, grid=grid)
    mamba.linearErode(imOut, imOut, mamba.transposeDirection(dir, grid=grid), n, edge=edge, grid=grid)
    if edge==mamba.EMPTY:
        mamba.logic(imOut, imWrk, imOut, "sup")
コード例 #46
0
def _sparseDiamondErode(imIn, imOut, size, edge=mamba.FILLED):
    """
    Erosion by a large diamond (conjugate square) on square grid. This diamond
    is not completely filled. It is for internal use only.
    """

    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    for i in _sizeSplit(size):
        mamba.copy(imOut, imWrk)
        infFarNeighbor(imWrk, imOut, 1, i, grid=mamba.SQUARE, edge=edge)
        infFarNeighbor(imWrk, imOut, 3, i, grid=mamba.SQUARE, edge=edge)
        infFarNeighbor(imWrk, imOut, 5, i, grid=mamba.SQUARE, edge=edge)
        infFarNeighbor(imWrk, imOut, 7, i, grid=mamba.SQUARE, edge=edge)
コード例 #47
0
def _sparseDiamondErode(imIn, imOut, size, edge=mamba.FILLED):
    """
    Erosion by a large diamond (conjugate square) on square grid. This diamond
    is not completely filled. It is for internal use only.
    """

    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    for i in _sizeSplit(size):
        mamba.copy(imOut, imWrk)
        infFarNeighbor(imWrk, imOut, 1, i, grid=mamba.SQUARE, edge=edge)
        infFarNeighbor(imWrk, imOut, 3, i, grid=mamba.SQUARE, edge=edge)
        infFarNeighbor(imWrk, imOut, 5, i, grid=mamba.SQUARE, edge=edge)
        infFarNeighbor(imWrk, imOut, 7, i, grid=mamba.SQUARE, edge=edge)
コード例 #48
0
ファイル: script.py プロジェクト: nicolasBeucher/mamba-image
def firstParticle(imIn, imOut, grid=mamba.DEFAULT_GRID):
    """
    Extraction of the first particle (in scanning order) of binary image imIn.
    The particle is put into image imOut and removed from imIn.
    
    If imIn is empty, imOut is also empty.
    imIn and imOut must be different.
    """

    imWrk = mamba.imageMb(imIn)
    mamba.compare(imIn, imWrk, imWrk)
    mamba.build(imIn, imWrk, grid=grid)
    mamba.diff(imIn, imWrk, imIn)
    mamba.copy(imWrk, imOut) 
コード例 #49
0
def fullGeodesicThick(imIn, imMask, imOut, dse):
    """
    Performs a complete geodesic thickening (until idempotence) of image 'imIn'
    inside mask 'imMask' with all the rotations of the double structuring
    element 'dse'. The result is put in 'imOut'.
    """
    
    mamba.copy(imIn, imOut)
    v1 = mamba.computeVolume(imOut)
    v2 = 0
    while v1 != v2:
        v2 = v1
        rotatingGeodesicThick(imOut, imMask, imOut, dse)
        v1 = mamba.computeVolume(imOut)
コード例 #50
0
def areaLabelling(imIn, imOut):
    """
    Special case of measure labelling where each connected component of the binary image
    'imIn' or each cell of the partition 'imIn'	is labelled with its area. The label image
    is stored in the 32-bit image 'imOut'.
    """

    imWrk = mamba.imageMb(imIn, 1)

    if imIn.getDepth() == 1:
        mamba.copy(imIn, imWrk)
    else:
        imWrk.fill(1)
    measureLabelling(imIn, imWrk, imOut)
コード例 #51
0
def areaLabelling(imIn, imOut):
    """
    Special case of measure labelling where each connected component of the binary image
    'imIn' or each cell of the partition 'imIn'	is labelled with its area. The label image
    is stored in the 32-bit image 'imOut'.
    """
	
    imWrk = mamba.imageMb(imIn, 1)
    
    if imIn.getDepth() == 1:
        mamba.copy(imIn, imWrk)
    else:
        imWrk.fill(1)
    measureLabelling(imIn, imWrk, imOut)
コード例 #52
0
ファイル: segment.py プロジェクト: nicolasBeucher/mamba-image
def geodesicSKIZ(imIn, imMask, imOut, grid=mamba.DEFAULT_GRID):
    """
    Geodesic skeleton by zones of influence of binary image 'imIn' inside the
    geodesic mask 'imMask'. The result is in binary image 'imOut'.
    """

    imWrk1 = mamba.imageMb(imIn, 8)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk2)
    mamba.build(imMask, imWrk2, grid=grid)
    mamba.convertByMask(imWrk2, imWrk1, 2, 1)
    mamba.sub(imWrk1, imIn, imWrk1)
    markerControlledWatershed(imWrk1, imIn, imWrk1, grid=grid)
    mamba.threshold(imWrk1, imOut, 0, 0)
    mamba.logic(imOut, imWrk2, imOut, "inf")
コード例 #53
0
def partitionDilate(imIn, imOut, n=1, grid=mamba.DEFAULT_GRID):
    """
    Graph dilation of the corresponding partition image 'imIn'. The size is given
    by 'n'. The corresponding partition image of the resulting dilated graph is
    put in 'imOut'.
    'grid' can be set to HEXAGONAL or SQUARE.
    """

    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    mamba.copy(imIn, imWrk)
    se = mamba.structuringElement(mamba.getDirections(grid), grid)
    for i in range(n):
        mamba.dilate(imOut, imOut, se=se)
        cellsBuild(imWrk, imOut, grid=grid)
コード例 #54
0
def partitionDilate(imIn, imOut, n=1, grid=mamba.DEFAULT_GRID):
    """
    Graph dilation of the corresponding partition image 'imIn'. The size is given
    by 'n'. The corresponding partition image of the resulting dilated graph is
    put in 'imOut'.
    'grid' can be set to HEXAGONAL or SQUARE.
    """
    
    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    mamba.copy(imIn, imWrk)
    se = mamba.structuringElement(mamba.getDirections(grid), grid)
    for i in range(n):
        mamba.dilate(imOut, imOut, se=se)
        cellsBuild(imWrk, imOut, grid=grid)