Example #1
0
def directionalOpen(imIn, imOut, d, size, grid=mamba.DEFAULT_GRID, edge=mamba.FILLED):
    """
    Directional opening of image 'imIn' defined by combining an erosion in
    direction 'd' followed by a dilation in the transposed direction (which
    depends on the grid in use). Result is put in 'imOut'.
    """
    
    directionalErode(imIn, imOut, d, size, grid=grid, edge=edge)
    j = (d + mamba.gridNeighbors(grid=grid) - 1) % (mamba.gridNeighbors(grid=grid) * 2) + 1
    directionalDilate(imOut, imOut, j, size, grid=grid)
Example #2
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)
Example #3
0
def directionalOpen(imIn,
                    imOut,
                    d,
                    size,
                    grid=mamba.DEFAULT_GRID,
                    edge=mamba.FILLED):
    """
    Directional opening of image 'imIn' defined by combining an erosion in
    direction 'd' followed by a dilation in the transposed direction (which
    depends on the grid in use). Result is put in 'imOut'.
    """

    directionalErode(imIn, imOut, d, size, grid=grid, edge=edge)
    j = (d + mamba.gridNeighbors(grid=grid) -
         1) % (mamba.gridNeighbors(grid=grid) * 2) + 1
    directionalDilate(imOut, imOut, j, size, grid=grid)
Example #4
0
    def __init__(self, directions, grid):
        """
        Structuring element constructor. A structuring element is defined by the 
        couple 'directions' (given in an ordered list) and 'grid'. You cannot
        defines a structuring element that holds a direction more than once.
        
        You can look at the predefined structuring elements to get examples of
        how to make yours.
        """

        self.grid = grid
        xx = {}
        for d in directions:
            xx[d] = 1
        self.directions = list(xx.keys())  # This is actually a trick to
        # remove duplicate from the direction
        # list
        self.directions.sort()
        self.directions_w0 = self.directions[:]
        self.has_zero = False
        if self.directions_w0.count(0) > 0:
            self.directions_w0.remove(0)
            self.has_zero = True
        self.enc_dirs = functools.reduce(lambda x, y: x | (1 << y),
                                         self.directions, 0)
        self.enc_dirs_w0 = functools.reduce(lambda x, y: x | (1 << y),
                                            self.directions_w0, 0)
        # neighbors defines the max number of neighbor points according to the grid
        # in use
        self.neighbors = mamba.gridNeighbors(grid)
Example #5
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)
Example #6
0
def directionalClose(imIn, imOut, d, size, grid=mamba.DEFAULT_GRID, edge=mamba.FILLED):
    """
    Directional closing of image 'imIn' defined by combining a dilation in
    direction 'd' followed by an erosion in the transposed direction (which
    depends on the grid in use). Result is put in 'imOut'.
    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)
    directionalDilate(imIn, imOut, d, size, grid=grid, edge=edge)
    j = (d + mamba.gridNeighbors(grid=grid) - 1) % (mamba.gridNeighbors(grid=grid) * 2) + 1
    directionalErode(imOut, imOut, j, size, grid=grid)
    if edge==mamba.EMPTY:
        mamba.logic(imOut, imWrk, imOut, "sup")
Example #7
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
Example #8
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
Example #9
0
def computePerimeter(imIn, scale=(1.0, 1.0), grid=mamba.DEFAULT_GRID):
    """
    Computes the perimeter of all particles in binary image 'imIn' according
    to the Cauchy-Crofton formula. 'scale' is a tuple defining the horizontal
    and vertical scale factors (default is 1.0).
    
    The edge of the image is always set to 'EMPTY'.
    
    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)
    p = 0.
    for i in range(1, mamba.gridNeighbors(grid)//2 + 1):
        p += computeDiameter(imIn, i, scale=scale, grid=grid)
    p = 2*math.pi*p/mamba.gridNeighbors(grid)
    return p
Example #10
0
def computePerimeter(imIn, scale=(1.0, 1.0), grid=mamba.DEFAULT_GRID):
    """
    Computes the perimeter of all particles in binary image 'imIn' according
    to the Cauchy-Crofton formula. 'scale' is a tuple defining the horizontal
    and vertical scale factors (default is 1.0).
    
    The edge of the image is always set to 'EMPTY'.
    
    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)
    p = 0.
    for i in range(1, mamba.gridNeighbors(grid) // 2 + 1):
        p += computeDiameter(imIn, i, scale=scale, grid=grid)
    p = 2 * math.pi * p / mamba.gridNeighbors(grid)
    return p
Example #11
0
def linearUltimateOpen(imIn, imOut, d, grid=mamba.DEFAULT_GRID):
    """
    This operator performs the ultimate directional opening of the binary image
    'imIn' in direction 'd' and puts the result in the 32-bit image 'imOut'.
    The value of 'imOut' at each point of 'imIn' corresponds to the length of the
    intercept passing through this point.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    
    size = 0
    imOut.reset()
    mamba.copy(imIn, imWrk1)
    while mamba.computeVolume(imWrk1) != 0:
        size += 1
        directionalErode(imWrk1, imWrk1, d, 1, grid=grid, edge=mamba.EMPTY)
        td = (d + mamba.gridNeighbors(grid) - 1) % (mamba.gridNeighbors(grid) * 2) + 1
        directionalDilate(imWrk1, imWrk2, td, size, grid=grid)
        mamba.add(imOut, imWrk2, imOut)
Example #12
0
def linearUltimateOpen(imIn, imOut, d, grid=mamba.DEFAULT_GRID):
    """
    This operator performs the ultimate directional opening of the binary image
    'imIn' in direction 'd' and puts the result in the 32-bit image 'imOut'.
    The value of 'imOut' at each point of 'imIn' corresponds to the length of the
    intercept passing through this point.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)

    size = 0
    imOut.reset()
    mamba.copy(imIn, imWrk1)
    while mamba.computeVolume(imWrk1) != 0:
        size += 1
        directionalErode(imWrk1, imWrk1, d, 1, grid=grid, edge=mamba.EMPTY)
        td = (d + mamba.gridNeighbors(grid) - 1) % (mamba.gridNeighbors(grid) *
                                                    2) + 1
        directionalDilate(imWrk1, imWrk2, td, size, grid=grid)
        mamba.add(imOut, imWrk2, imOut)
Example #13
0
def directionalClose(imIn,
                     imOut,
                     d,
                     size,
                     grid=mamba.DEFAULT_GRID,
                     edge=mamba.FILLED):
    """
    Directional closing of image 'imIn' defined by combining a dilation in
    direction 'd' followed by an erosion in the transposed direction (which
    depends on the grid in use). Result is put in 'imOut'.
    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)
    directionalDilate(imIn, imOut, d, size, grid=grid, edge=edge)
    j = (d + mamba.gridNeighbors(grid=grid) -
         1) % (mamba.gridNeighbors(grid=grid) * 2) + 1
    directionalErode(imOut, imOut, j, size, grid=grid)
    if edge == mamba.EMPTY:
        mamba.logic(imOut, imWrk, imOut, "sup")
Example #14
0
def rotatingGeodesicThick(imIn, imMask, imOut, dse):
    """
    Performs successive geodesic thickenings of 'imIn' inside 'imMask' with 
    clockwise rotations of the double structuring element 'dse'. The number of 
    rotations is either 6 or 8 according to the grid where 'dse' is defined.
    All the thickenings are concatenated.
    
    'imIn', 'imMask' and 'imOut' are binary images.
    """

    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    for i in range(mamba.gridNeighbors(dse.getGrid())):
        hitOrMiss(imOut, imWrk, dse)
        mamba.logic(imWrk, imOut, imOut, "sup")
        mamba.logic(imMask, imOut, imOut, "inf")
        dse = dse.rotate()
Example #15
0
def cellsFullThin(imIn, imOut, dse, edge=mamba.EMPTY):
    """
    A full thinning transform is performed on each cell of the partition 'imIn'
    until idempotence. 'dse' is a double structuring element. The result
    is put in 'imOut'. 'edge' is set to EMPTY by default. 
    """
    
    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())):
            cellsThin(imOut, imOut, dse, edge=edge)
            dse = dse.rotate()
        v1 = mamba.computeVolume(imOut)
Example #16
0
def rotatingGeodesicThick(imIn, imMask, imOut, dse):
    """
    Performs successive geodesic thickenings of 'imIn' inside 'imMask' with 
    clockwise rotations of the double structuring element 'dse'. The number of 
    rotations is either 6 or 8 according to the grid where 'dse' is defined.
    All the thickenings are concatenated.
    
    'imIn', 'imMask' and 'imOut' are binary images.
    """

    imWrk = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    for i in range(mamba.gridNeighbors(dse.getGrid())):
        hitOrMiss(imOut, imWrk, dse)
        mamba.logic(imWrk, imOut, imOut, "sup")
        mamba.logic(imMask, imOut, imOut, "inf")
        dse = dse.rotate()
Example #17
0
def cellsFullThin(imIn, imOut, dse, edge=mamba.EMPTY):
    """
    A full thinning transform is performed on each cell of the partition 'imIn'
    until idempotence. 'dse' is a double structuring element. The result
    is put in 'imOut'. 'edge' is set to EMPTY by default. 
    """

    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())):
            cellsThin(imOut, imOut, dse, edge=edge)
            dse = dse.rotate()
        v1 = mamba.computeVolume(imOut)
Example #18
0
def infThin(imIn, imOut, dse, edge=mamba.EMPTY):
    """
    Performs an inf of thinnings, each thinning being made with the successive 
    rotations of 'dse'. The initial image 'imIn' is used at each step of 
    thinning (intersection of thinnings).
    
    'imIn' and 'imOut' are binary images.
    
    'edge' is set to EMPTY by default.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    mamba.copy(imIn, imWrk1)
    for i in range(mamba.gridNeighbors(dse.getGrid())):
        hitOrMiss(imWrk1, imWrk2, dse, edge=edge)
        mamba.diff(imOut, imWrk2, imOut)
        dse = dse.rotate()
Example #19
0
def supThick(imIn, imOut, dse):
    """
    Performs a sup of thickenings, each thickening being made with the successive 
    rotations of 'dse'. The initial image 'imIn' is used at each step of 
    thickening (union of thickenings).

    'imIn' and 'imOut' are binary images.
    
    The edge is always set to EMPTY.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk1)
    mamba.copy(imIn, imOut)
    for i in range(mamba.gridNeighbors(dse.getGrid())):
        hitOrMiss(imWrk1, imWrk2, dse)
        mamba.logic(imWrk2, imOut, imOut, "sup")
        dse = dse.rotate()
Example #20
0
def infThin(imIn, imOut, dse, edge=mamba.EMPTY):
    """
    Performs an inf of thinnings, each thinning being made with the successive 
    rotations of 'dse'. The initial image 'imIn' is used at each step of 
    thinning (intersection of thinnings).
    
    'imIn' and 'imOut' are binary images.
    
    'edge' is set to EMPTY by default.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    mamba.copy(imIn, imWrk1)
    for i in range(mamba.gridNeighbors(dse.getGrid())):
        hitOrMiss(imWrk1, imWrk2, dse, edge=edge)
        mamba.diff(imOut, imWrk2, imOut)
        dse = dse.rotate()
Example #21
0
def supThick(imIn, imOut, dse):
    """
    Performs a sup of thickenings, each thickening being made with the successive 
    rotations of 'dse'. The initial image 'imIn' is used at each step of 
    thickening (union of thickenings).

    'imIn' and 'imOut' are binary images.
    
    The edge is always set to EMPTY.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imWrk1)
    mamba.copy(imIn, imOut)
    for i in range(mamba.gridNeighbors(dse.getGrid())):
        hitOrMiss(imWrk1, imWrk2, dse)
        mamba.logic(imWrk2, imOut, imOut, "sup")
        dse = dse.rotate()
Example #22
0
def directionalCoding(imIn, imOut, grid=mamba.DEFAULT_GRID):
    """
    Coding of the direction which, at each point of 'imIn', corresponds to the
    direction of the maximal intercept through this point. The result of this
    coding is put in the grey scale image 'imOut'.
    6 directions are coded on the hexagonal grid, 8 on the square one.
    """
    imWrk1 = mamba.imageMb(imIn, 32)
    imWrk2 = mamba.imageMb(imIn, 32)
    imWrk3 = mamba.imageMb(imIn)
    imWrk4 = mamba.imageMb(imIn, 8)
    
    imOut.reset()
    imWrk1.reset()
    for i in range(mamba.gridNeighbors(grid=grid)):
        d = i + 1
        linearUltimateOpen(imIn, imWrk2, d, grid=grid)
        mamba.generateSupMask(imWrk2, imWrk1, imWrk3, True)
        mamba.logic(imWrk2, imWrk1, imWrk1, "sup")
        mamba.convertByMask(imWrk3, imWrk4, 0, d)
        mamba.logic(imWrk4, imOut, imOut, "sup")       
Example #23
0
def directionalCoding(imIn, imOut, grid=mamba.DEFAULT_GRID):
    """
    Coding of the direction which, at each point of 'imIn', corresponds to the
    direction of the maximal intercept through this point. The result of this
    coding is put in the grey scale image 'imOut'.
    6 directions are coded on the hexagonal grid, 8 on the square one.
    """
    imWrk1 = mamba.imageMb(imIn, 32)
    imWrk2 = mamba.imageMb(imIn, 32)
    imWrk3 = mamba.imageMb(imIn)
    imWrk4 = mamba.imageMb(imIn, 8)

    imOut.reset()
    imWrk1.reset()
    for i in range(mamba.gridNeighbors(grid=grid)):
        d = i + 1
        linearUltimateOpen(imIn, imWrk2, d, grid=grid)
        mamba.generateSupMask(imWrk2, imWrk1, imWrk3, True)
        mamba.logic(imWrk2, imWrk1, imWrk1, "sup")
        mamba.convertByMask(imWrk3, imWrk4, 0, d)
        mamba.logic(imWrk4, imOut, imOut, "sup")
Example #24
0
def diameterLabelling(imIn, imOut, dir, grid=mamba.DEFAULT_GRID):
    """
    Labels each connected component of the binary image 'imIn' with its diameter in 
    direction 'dir'. The labelled image is stored in the 32-bit image 'imOut'.
    If 'imIn' is a 8-bit or 32-bit image, this function works too. However, the
    0-valued connected components are labelled with 0.
    This procedure works on hexagonal or square grid.
    'dir' can be any strictly positive integer value.
    """
    
    imWrk1 = mamba.imageMb(imIn, 1)
    imWrk2 = mamba.imageMb(imIn)
    
    ed = 1 << ((dir - 1)%(mamba.gridNeighbors(grid)//2)) +1
    if imIn.getDepth() == 1:
        mamba.copy(imIn, imWrk1)
        mamba.diffNeighbor(imIn, imWrk1, ed, grid=grid)
    else:
        mamba.nonEqualNeighbors(imIn, imWrk2, ed, grid=grid, edge= mamba.EMPTY)
        mamba.threshold(imWrk2, imWrk1, 1, mamba.computeMaxRange(imWrk2)[1])
    # They are used for the labelling.
    measureLabelling(imIn, imWrk1, imOut)
Example #25
0
def diameterLabelling(imIn, imOut, dir, grid=mamba.DEFAULT_GRID):
    """
    Labels each connected component of the binary image 'imIn' with its diameter in 
    direction 'dir'. The labelled image is stored in the 32-bit image 'imOut'.
    If 'imIn' is a 8-bit or 32-bit image, this function works too. However, the
    0-valued connected components are labelled with 0.
    This procedure works on hexagonal or square grid.
    'dir' can be any strictly positive integer value.
    """

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

    ed = 1 << ((dir - 1) % (mamba.gridNeighbors(grid) // 2)) + 1
    if imIn.getDepth() == 1:
        mamba.copy(imIn, imWrk1)
        mamba.diffNeighbor(imIn, imWrk1, ed, grid=grid)
    else:
        mamba.nonEqualNeighbors(imIn, imWrk2, ed, grid=grid, edge=mamba.EMPTY)
        mamba.threshold(imWrk2, imWrk1, 1, mamba.computeMaxRange(imWrk2)[1])
    # They are used for the labelling.
    measureLabelling(imIn, imWrk1, imOut)