Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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")
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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)
Пример #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)
Пример #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")
Пример #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()
Пример #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)
Пример #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()
Пример #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)
Пример #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()
Пример #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()
Пример #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()
Пример #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()
Пример #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")       
Пример #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")
Пример #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)
Пример #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)