Example #1
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)
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
Example #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)
Example #4
0
    def initAcquisition(self):
        # At the beginning, the thread creates the acquisition device and extracts
        # specific information. This allow to create the mamba images and
        # sequences.
        
        err,w,h = core.MBRT_GetAcqSize()
        if err!=core.MBRT_NO_ERR:
            self.error = core.MBRT_StrErr(err)
            self.mustStop = True
            return (0,0)
        err, freq = core.MBRT_GetAcqFrameRate()
        if err!=core.MBRT_NO_ERR:
            self.error = core.MBRT_StrErr(err)
            self.mustStop = True
            return (0,0)
        self.frequency = freq
        self.period = 1.0/self.frequency

        core.MBRT_StartAcq()
        
        self.red = mamba.imageMb(w,h)
        self.green = mamba.imageMb(w,h)
        self.blue = mamba.imageMb(w,h)
        self.redSeq = mamba3D.sequenceMb(w,h,self.seqDepth)
        self.greenSeq = mamba3D.sequenceMb(w,h,self.seqDepth)
        self.blueSeq = mamba3D.sequenceMb(w,h,self.seqDepth)
        self.seqIndex = 0
        
        return self.red.getSize()
def hierarchicalLevel(imIn, imOut, grid=mamba.DEFAULT_GRID):
    """
    Computes the next hierarchical level of image 'imIn' in the
    waterfalls transformation and puts the result in 'imOut'.
    This operation makes sure that the next hierarchical level is embedded
    in the previous one.
    'imIn' must be a valued watershed image.
    """

    imWrk0 = mamba.imageMb(imIn)
    imWrk1 = mamba.imageMb(imIn, 1)
    imWrk2 = mamba.imageMb(imIn, 1)
    imWrk3 = mamba.imageMb(imIn, 1)
    imWrk4 = mamba.imageMb(imIn, 32)
    mamba.threshold(imIn, imWrk1, 0, 0)
    mamba.negate(imWrk1, imWrk2)
    hierarchy(imIn, imWrk2, imWrk0, grid=grid)
    mamba.minima(imWrk0, imWrk2, grid=grid)
    mamba.label(imWrk2, imWrk4, grid=grid)
    mamba.watershedSegment(imWrk0, imWrk4, grid=grid)
    mamba.copyBytePlane(imWrk4, 3, imWrk0)
    mamba.threshold(imWrk0, imWrk2, 0, 0)
    mamba.diff(imWrk1, imWrk2, imWrk3)
    mamba.build(imWrk1, imWrk3)
    se = mamba.structuringElement(mamba.getDirections(grid), grid)
    mamba.dilate(imWrk3, imWrk1, 1, se)
    mamba.diff(imWrk2, imWrk1, imWrk1)
    mamba.logic(imWrk1, imWrk3, imWrk1, "sup")
    mamba.convertByMask(imWrk1, imWrk0, 255, 0)
    mamba.logic(imIn, imWrk0, imOut, "inf")
Example #6
0
def partitionLabel(imIn, imOut):
    """
    This procedure labels each cell of image 'imIn' and puts the result in
    'imOut'. The number of cells is returned. 'imIn' can be a 1-bit, 8-bit or a
    32-bit image. 'imOut' is a 32-bit image. When 'imIn' is a binary image, all the
    connected components of the background are also labelled. When 'imIn' is a grey
    image, the 0-valued cells are also labelled (which is not the case with the label
    operator.
    Warning! The label values of adjacent cells are not necessarily consecutive.
    """
    
    imWrk1 = mamba.imageMb(imIn, 1)
    imWrk2 = mamba.imageMb(imIn, 32)
    
    if imIn.getDepth() == 1:
        mamba.negate(imIn, imWrk1)
    else:
        mamba.threshold(imIn, imWrk1, 0, 0)
    nb1 = mamba.label(imWrk1, imWrk2)
    mamba.convertByMask(imWrk1, imOut, mamba.computeMaxRange(imOut)[1], 0)
    mamba.logic(imOut, imWrk2, imOut, "sup")
    nb2 = mamba.label(imIn, imWrk2)
    mamba.addConst(imWrk2, nb1, imWrk2)
    mamba.logic(imOut, imWrk2, imOut, "inf")
    return nb1 + nb2
Example #7
0
def endPoints(imIn, imOut, grid=mamba.DEFAULT_GRID, edge=mamba.FILLED):
    """
    Extracts end points in 'imIn', supposed to be a "skeleton" image (connected 
    components without thickness), and puts them in 'imOut'.
    
    'edge' is FILLED by default and it can be modified to take into account
    extremities touching the edge.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    if grid == mamba.HEXAGONAL:
        dse1 = hexagonalE
        dse2 = hexagonalL
        nb = 6
        step = 1
    else:
        dse1 = squareE
        dse2 = squareL
        nb = 4
        step = 2
    rotatingThin(imIn, imWrk1, dse2, edge=edge)
    # added to avoid blocking of the process in clipping
    mamba.diff(imIn, imWrk1, imOut)
    for i in range(nb):
        hitOrMiss(imWrk1, imWrk2, dse1, edge=edge)
        mamba.logic(imOut, imWrk2, imOut, "sup")
        dse1 = dse1.rotate(step)
Example #8
0
def conjugateDirectionalErode(imIn,
                              imOut,
                              d,
                              size,
                              grid=mamba.DEFAULT_GRID,
                              edge=mamba.FILLED):
    """
    Performs the erosion of image 'imIn' in the conjugate direction 'd' of the
    grid and puts the result in image 'imOut'. The images can be binary, greyscale
    or 32-bit images. 'size' is a multiple of the distance between two adjacent
    points in the conjugate directions. 'edge' is set to FILLED by default (can
    be changed).
    Note that this operator is not equivalent to successive erosions by a doublet
    of points.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)

    j3 = mamba.transposeDirection(d, grid=grid)
    j2 = mamba.rotateDirection(d, grid=grid)
    j1 = mamba.transposeDirection(j2, grid=grid)
    val = mamba.computeMaxRange(imIn)[1] * int(edge == mamba.FILLED)
    for i in range(size):
        mamba.copy(imOut, imWrk1)
        mamba.copy(imOut, imWrk2)
        mamba.linearErode(imWrk1, imWrk1, d, n=1, grid=grid, edge=edge)
        mamba.shift(imWrk1, imWrk1, j1, 1, val, grid=grid)
        mamba.logic(imWrk1, imOut, imWrk1, "inf")
        mamba.linearErode(imWrk2, imWrk2, j2, n=1, grid=grid, edge=edge)
        mamba.shift(imWrk2, imWrk2, j3, 1, val, grid=grid)
        mamba.logic(imWrk2, imOut, imWrk2, "inf")
        mamba.logic(imWrk1, imWrk2, imOut, "sup")
Example #9
0
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)
Example #10
0
def conjugateDirectionalErode(imIn, imOut, d, size, grid=mamba.DEFAULT_GRID, edge=mamba.FILLED):
    """
    Performs the erosion of image 'imIn' in the conjugate direction 'd' of the
    grid and puts the result in image 'imOut'. The images can be binary, greyscale
    or 32-bit images. 'size' is a multiple of the distance between two adjacent
    points in the conjugate directions. 'edge' is set to FILLED by default (can
    be changed).
    Note that this operator is not equivalent to successive erosions by a doublet
    of points.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)

    j3 = mamba.transposeDirection(d, grid=grid)
    j2 = mamba.rotateDirection(d, grid=grid)
    j1 = mamba.transposeDirection(j2, grid=grid)
    val = mamba.computeMaxRange(imIn)[1] * int(edge == mamba.FILLED)
    for i in range(size):
        mamba.copy(imOut, imWrk1)
        mamba.copy(imOut, imWrk2)
        mamba.linearErode(imWrk1, imWrk1, d, n=1, grid=grid, edge=edge)
        mamba.shift(imWrk1, imWrk1, j1, 1, val, grid=grid)
        mamba.logic(imWrk1, imOut, imWrk1, "inf")
        mamba.linearErode(imWrk2, imWrk2, j2, n=1, grid=grid, edge=edge)
        mamba.shift(imWrk2, imWrk2, j3, 1, val, grid=grid)
        mamba.logic(imWrk2, imOut, imWrk2, "inf")
        mamba.logic(imWrk1, imWrk2, imOut, "sup")
Example #11
0
def conjugateDirectionalDilate(imIn, imOut, d, size, grid=mamba.DEFAULT_GRID, edge=mamba.EMPTY):
    """
    Performs the dilation of image 'imIn' in the conjugate direction 'd' of the
    grid and puts the result in image 'imOut'. The images can be binary, greyscale
    or 32-bit images. 'size' is a multiple of the distance between two adjacent
    points in the conjugate directions. 'edge' is set to EMPTY by default (can
    be changed).
    Note that the linear structuring element is not connected. Points connecting
    adjacent points in the conjugate directions are not present. This is normal
    if we want to insure that the result is identical when we iterate n size 1
    operations to get a size n one (the same remark applies to the erosion).
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)

    j3 = mamba.transposeDirection(d, grid=grid)
    j2 = mamba.rotateDirection(d, grid=grid)
    j1 = mamba.transposeDirection(j2, grid=grid)
    val = mamba.computeMaxRange(imIn)[1] * int(edge == mamba.FILLED)
    for i in range(size):
        mamba.copy(imOut, imWrk1)
        mamba.copy(imOut, imWrk2)
        mamba.linearDilate(imWrk1, imWrk1, d, 1, grid=grid, edge=edge)
        mamba.shift(imWrk1, imWrk1, j1, 1, val, grid=grid)
        mamba.logic(imWrk1, imOut, imWrk1, "sup")
        mamba.linearDilate(imWrk2, imWrk2, j2, 1, grid=grid, edge=edge)
        mamba.shift(imWrk2, imWrk2, j3, 1, val, grid=grid)
        mamba.logic(imWrk2, imOut, imWrk2, "sup")
        mamba.logic(imWrk1, imWrk2, imOut, "inf")
Example #12
0
def conjugateDirectionalDilate(imIn, imOut, d, size, grid=mamba.DEFAULT_GRID, edge=mamba.EMPTY):
    """
    Performs the dilation of image 'imIn' in the conjugate direction 'd' of the
    grid and puts the result in image 'imOut'. The images can be binary, greyscale
    or 32-bit images. 'size' is a multiple of the distance between two adjacent
    points in the conjugate directions. 'edge' is set to EMPTY by default (can
    be changed).
    Note that the linear structuring element is not connected. Points connecting
    adjacent points in the conjugate directions are not present. This is normal
    if we want to insure that the result is identical when we iterate n size 1
    operations to get a size n one (the same remark applies to the erosion).
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    mamba.copy(imIn, imOut)
    
    j3 = mamba.transposeDirection(d, grid=grid)
    j2 = mamba.rotateDirection(d, grid=grid)
    j1 = mamba.transposeDirection(j2, grid=grid)
    val = mamba.computeMaxRange(imIn)[1] * int(edge == mamba.FILLED)
    for i in range(size):
        mamba.copy(imOut, imWrk1)
        mamba.copy(imOut, imWrk2)
        mamba.linearDilate(imWrk1, imWrk1, d, 1, grid=grid, edge=edge)
        mamba.shift(imWrk1, imWrk1, j1, 1, val, grid=grid)
        mamba.logic(imWrk1, imOut, imWrk1, "sup")
        mamba.linearDilate(imWrk2, imWrk2, j2, 1, grid=grid, edge=edge)
        mamba.shift(imWrk2, imWrk2, j3, 1, val, grid=grid)
        mamba.logic(imWrk2, imOut, imWrk2, "sup")
        mamba.logic(imWrk1, imWrk2, imOut, "inf")
Example #13
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")
Example #14
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")
Example #15
0
def partitionLabel(imIn, imOut):
    """
    This procedure labels each cell of image 'imIn' and puts the result in
    'imOut'. The number of cells is returned. 'imIn' can be a 1-bit, 8-bit or a
    32-bit image. 'imOut' is a 32-bit image. When 'imIn' is a binary image, all the
    connected components of the background are also labelled. When 'imIn' is a grey
    image, the 0-valued cells are also labelled (which is not the case with the label
    operator.
    Warning! The label values of adjacent cells are not necessarily consecutive.
    """

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

    if imIn.getDepth() == 1:
        mamba.negate(imIn, imWrk1)
    else:
        mamba.threshold(imIn, imWrk1, 0, 0)
    nb1 = mamba.label(imWrk1, imWrk2)
    mamba.convertByMask(imWrk1, imOut, mamba.computeMaxRange(imOut)[1], 0)
    mamba.logic(imOut, imWrk2, imOut, "sup")
    nb2 = mamba.label(imIn, imWrk2)
    mamba.addConst(imWrk2, nb1, imWrk2)
    mamba.logic(imOut, imWrk2, imOut, "inf")
    return nb1 + nb2
Example #16
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)
Example #17
0
def upperGeodesicDilate(imIn, imMask, imOut, n=1, se=mamba.DEFAULT_SE):
    """
    Performs an upper geodesic dilation of image 'imIn' above 'imMask'.
    The result is put inside 'imOut', 'n' controls the size of the dilation.
    'se' specifies the type of structuring element used to perform the 
    computation (DEFAULT_SE by default). 
    
    Warning! 'imMask' and 'imOut' must be different.
    """
    
    mamba.logic(imIn, imMask, imOut, "sup")
    if imIn.getDepth() == 1:
        for i in range(n):
            mamba.diff(imOut, imMask, imOut)
            mamba.dilate(imOut, imOut, se=se)
            mamba.logic(imMask, imOut, imOut, "sup")
    else:
        imWrk1 = mamba.imageMb(imIn)
        imWrk2 = mamba.imageMb(imIn, 1)
        for i in range(n):
            mamba.generateSupMask(imOut, imMask, imWrk2, True)
            mamba.convertByMask(imWrk2, imWrk1, 0, mamba.computeMaxRange(imWrk1)[1])
            mamba.logic(imOut, imWrk1, imOut, "inf")
            mamba.dilate(imOut, imOut, se=se)
            mamba.logic(imOut, imMask, imOut, "sup")
Example #18
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
Example #19
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)
Example #20
0
def hierarchicalLevel(imIn, imOut, grid=mamba.DEFAULT_GRID):
    """
    Computes the next hierarchical level of image 'imIn' in the
    waterfalls transformation and puts the result in 'imOut'.
    This operation makes sure that the next hierarchical level is embedded
    in the previous one.
    'imIn' must be a valued watershed image.
    """
    
    imWrk0 = mamba.imageMb(imIn)
    imWrk1 = mamba.imageMb(imIn, 1)
    imWrk2 = mamba.imageMb(imIn, 1)
    imWrk3 = mamba.imageMb(imIn, 1)
    imWrk4 = mamba.imageMb(imIn, 32)
    mamba.threshold(imIn,imWrk1, 0, 0)
    mamba.negate(imWrk1, imWrk2)
    hierarchy(imIn, imWrk2, imWrk0, grid=grid)
    mamba.minima(imWrk0, imWrk2, grid=grid)
    mamba.label(imWrk2, imWrk4, grid=grid)
    mamba.watershedSegment(imWrk0, imWrk4, grid=grid)
    mamba.copyBytePlane(imWrk4, 3, imWrk0)
    mamba.threshold(imWrk0, imWrk2, 0, 0)
    mamba.diff(imWrk1, imWrk2, imWrk3)
    mamba.build(imWrk1, imWrk3)
    se = mamba.structuringElement(mamba.getDirections(grid), grid)
    mamba.dilate(imWrk3, imWrk1, 1, se)
    mamba.diff(imWrk2, imWrk1, imWrk1)
    mamba.logic(imWrk1, imWrk3, imWrk1, "sup")
    mamba.convertByMask(imWrk1, imWrk0, 255, 0)
    mamba.logic(imIn, imWrk0, imOut, "inf")
Example #21
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")
Example #22
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)
Example #23
0
    def initAcquisition(self):
        # At the beginning, the thread creates the acquisition device and extracts
        # specific information. This allow to create the mamba images and
        # sequences.

        err, w, h = core.MBRT_GetAcqSize()
        if err != core.MBRT_NO_ERR:
            self.error = core.MBRT_StrErr(err)
            self.mustStop = True
            return (0, 0)
        err, freq = core.MBRT_GetAcqFrameRate()
        if err != core.MBRT_NO_ERR:
            self.error = core.MBRT_StrErr(err)
            self.mustStop = True
            return (0, 0)
        self.frequency = freq
        self.period = 1.0 / self.frequency

        core.MBRT_StartAcq()

        self.red = mamba.imageMb(w, h)
        self.green = mamba.imageMb(w, h)
        self.blue = mamba.imageMb(w, h)
        self.redSeq = mamba3D.sequenceMb(w, h, self.seqDepth)
        self.greenSeq = mamba3D.sequenceMb(w, h, self.seqDepth)
        self.blueSeq = mamba3D.sequenceMb(w, h, self.seqDepth)
        self.seqIndex = 0

        return self.red.getSize()
Example #24
0
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
Example #25
0
def binaryUltimateErosion(imIn, imOut1, imOut2, grid=mamba.DEFAULT_GRID, edge=mamba.FILLED):
    """
    Ultimate erosion of binary image 'imIn'. 'imOut1' contains the ultimate 
    eroded set and 'imOut2' contains the associated function (that is the 
    height of each connected component of the ultimate erosion).
    
    An ultimate erosion is composed of the union of the last connected
    components of the successive erosions of the initial set. The associated
    function provides the size of the corresponding erosion.
    
    Depth of 'imOut1' is 1, depth of 'imOut2' is 32. 

    The operation is fast because it is computed using the distance function
    of 'imIn' (the ultimate erosion is identical to the maxima of this
    distance function).

    The edge is set to 'FILLED' by default.
    """

    imWrk1 = mamba.imageMb(imIn, 32)
    imWrk2 = mamba.imageMb(imIn, 32)
    mamba.computeDistance(imIn, imWrk1, grid=grid, edge=edge)
    mamba.maxima(imWrk1, imOut1, grid=grid)
    mamba.convertByMask(imOut1, imWrk2, 0, mamba.computeMaxRange(imWrk2)[1])
    mamba.logic(imWrk1, imWrk2, imOut2, "inf")
Example #26
0
def endPoints(imIn, imOut, grid=mamba.DEFAULT_GRID, edge=mamba.FILLED):
    """
    Extracts end points in 'imIn', supposed to be a "skeleton" image (connected 
    components without thickness), and puts them in 'imOut'.
    
    'edge' is FILLED by default and it can be modified to take into account
    extremities touching the edge.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    if grid == mamba.HEXAGONAL:
        dse1 = hexagonalE
        dse2 = hexagonalL
        nb = 6
        step = 1
    else:
        dse1 = squareE
        dse2 = squareL
        nb = 4
        step = 2
    rotatingThin(imIn, imWrk1, dse2, edge=edge)
    # added to avoid blocking of the process in clipping
    mamba.diff(imIn, imWrk1, imOut)
    for i in range(nb):
        hitOrMiss(imWrk1, imWrk2, dse1, edge=edge)
        mamba.logic(imOut, imWrk2, imOut, "sup")
        dse1 = dse1.rotate(step)
Example #27
0
def multiplePoints(imIn, imOut, grid=mamba.DEFAULT_GRID):
    """
    Extracts multiple points in 'imIn', supposed to be a "skeleton" image (connected 
    components without thickness), and puts the result in 'imOut'.
    
    Note that, on a square grid, the resulting skeleton is supposed to be defined 
    on a 4-connectivity grid. if it is not the case, some multiple points are likely
    to be missed.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    endPoints(imIn, imWrk2)
    if grid == mamba.HEXAGONAL:
        dse_list = [hexagonalS1, hexagonalS2]
        step = 1
        nb = 6
    else:
        dse_list = [squareS1, squareS2]
        step = 2
        nb = 4
    for dse in dse_list:
        for i in range(nb):
            hitOrMiss(imIn, imWrk1, dse)
            mamba.logic(imWrk1, imWrk2, imWrk2, "sup")
            dse = dse.rotate(step)
    mamba.diff(imIn, imWrk2, imOut)
Example #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
Example #29
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)
Example #30
0
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)
Example #31
0
def lowerGeodesicErode(imIn, imMask, imOut, n=1, se=mamba.DEFAULT_SE):
    """
    Performs a lower geodesic erosion of image 'imIn' under 'imMask'.
    The result is put inside 'imOut', 'n' controls the size of the erosion.
    'se' specifies the type of structuring element used to perform the 
    computation (DEFAULT_SE by default).

    The binary lower geodesic erosion is realised using the fact that the
    dilation is the dual operation of the erosion.
    
    Warning! 'imMask' and 'imOut' must be different.
    """
    
    if imIn.getDepth() == 1:
        mamba.diff(imMask, imIn, imOut)
        lowerGeodesicDilate(imOut, imMask, imOut, n, se=se)
        mamba.diff(imMask, imOut, imOut)
    else:
        imWrk1 = mamba.imageMb(imIn)
        imWrk2 = mamba.imageMb(imIn, 1)
        mamba.logic(imIn, imMask, imOut, "inf")
        for i in range(n):
            mamba.generateSupMask(imOut, imMask, imWrk2, False)
            mamba.convertByMask(imWrk2, imWrk1, 0, mamba.computeMaxRange(imWrk1)[1])
            mamba.logic(imOut, imWrk1, imOut, "sup")
            mamba.erode(imOut, imOut, se=se)
            mamba.logic(imOut, imMask, imOut, "inf")
Example #32
0
def volumeLabelling(imIn1, imIn2, imOut):
    """
    Each connected component of the binary image  or the partition 'imIn1' is
    labelled with the volume of the greyscale or 32-bit image 'imIn2' inside
    this component. The result is put in the 32-bit image 'imOut'.
    """

    imWrk1 = mamba.imageMb(imIn1, 1)
    imWrk2 = mamba.imageMb(imIn1, 32)
    imWrk3 = mamba.imageMb(imIn1, 8)

    imOut.reset()
    n = imIn2.getDepth()
    # Case of a 8-bit image.
    if n == 8:
        for i in range(8):
            # Each bit plane is extracted and used in the labelling.
            mamba.copyBitPlane(imIn2, i, imWrk1)
            measureLabelling(imIn1, imWrk1, imWrk2)
            # The resulting labels are combined to obtain the final one.
            v = 2**i
            mamba.mulConst(imWrk2, v, imWrk2)
            mamba.add(imOut, imWrk2, imOut)
    else:
        for j in range(4):
            # Each byte plane is treated.
            mamba.copyBytePlane(imIn2, j, imWrk3)
            for i in range(8):
                mamba.copyBitPlane(imWrk3, i, imWrk1)
                measureLabelling(imIn1, imWrk1, imWrk2)
                v = 2**(8 * j + i)
                mamba.mulConst(imWrk2, v, imWrk2)
                mamba.add(imOut, imWrk2, imOut)
Example #33
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")
Example #34
0
def multiplePoints(imIn, imOut, grid=mamba.DEFAULT_GRID):
    """
    Extracts multiple points in 'imIn', supposed to be a "skeleton" image (connected 
    components without thickness), and puts the result in 'imOut'.
    
    Note that, on a square grid, the resulting skeleton is supposed to be defined 
    on a 4-connectivity grid. if it is not the case, some multiple points are likely
    to be missed.
    """

    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn)
    endPoints(imIn, imWrk2)
    if grid == mamba.HEXAGONAL:
        dse_list = [hexagonalS1, hexagonalS2]
        step = 1
        nb = 6
    else:
        dse_list = [squareS1, squareS2]
        step = 2
        nb = 4
    for dse in dse_list:
        for i in range(nb):
            hitOrMiss(imIn, imWrk1, dse)
            mamba.logic(imWrk1, imWrk2, imWrk2, "sup")
            dse = dse.rotate(step)
    mamba.diff(imIn, imWrk2, imOut)
Example #35
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")
Example #36
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)
Example #37
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)
Example #38
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)
Example #39
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)
Example #40
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)
Example #41
0
def volumeLabelling(imIn1, imIn2, imOut):
    """
    Each connected component of the binary image  or the partition 'imIn1' is
    labelled with the volume of the greyscale or 32-bit image 'imIn2' inside
    this component. The result is put in the 32-bit image 'imOut'.
    """
    
    imWrk1 = mamba.imageMb(imIn1, 1)
    imWrk2 = mamba.imageMb(imIn1, 32)
    imWrk3 = mamba.imageMb(imIn1, 8)
    
    imOut.reset()
    n = imIn2.getDepth()
    # Case of a 8-bit image.
    if n == 8:
        for i in range(8):
            # Each bit plane is extracted and used in the labelling.
            mamba.copyBitPlane(imIn2, i, imWrk1)
            measureLabelling(imIn1, imWrk1, imWrk2)
            # The resulting labels are combined to obtain the final one.
            v = 2 ** i
            mamba.mulConst(imWrk2, v, imWrk2)
            mamba.add(imOut, imWrk2, imOut)
    else:
        for j in range(4):
            # Each byte plane is treated.
            mamba.copyBytePlane(imIn2, j, imWrk3)
            for i in range(8):
                mamba.copyBitPlane(imWrk3, i, imWrk1)
                measureLabelling(imIn1, imWrk1, imWrk2)
                v = 2 ** (8 * j + i)
                mamba.mulConst(imWrk2, v, imWrk2)
                mamba.add(imOut, imWrk2, imOut) 
Example #42
0
def contrast():
    im = mamba.imageMb("before.jpg")
    imContrast = mamba.imageMb(im)
    contrastEnhancer(im, imContrast, 10)
    imContrast.save("contrast_A.jpg")

    im = mamba.imageMb("after.jpg")
    imContrast = mamba.imageMb(im)
    contrastEnhancer(im, imContrast, 10)
    imContrast.save("contrast_B.jpg")
Example #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
Example #44
0
def markerControlledWatershed(imIn, imMarkers, imOut, grid=mamba.DEFAULT_GRID):
    """
    Marker-controlled watershed transform of greytone image 'imIn'. The binary
    image 'imMarkers' contains the markers which control the flooding process.
    'imOut' contains the valued watershed.
    """

    im_mark = mamba.imageMb(imIn, 32)
    imWrk = mamba.imageMb(imIn)
    label(imMarkers, im_mark, grid=grid)
    watershedSegment(imIn, im_mark, grid=grid)
    mamba.copyBytePlane(im_mark, 3, imWrk)
    mamba.logic(imWrk, imIn, imOut, 'inf')
Example #45
0
def markerControlledWatershed(imIn, imMarkers, imOut, grid=mamba.DEFAULT_GRID):
    """
    Marker-controlled watershed transform of greytone image 'imIn'. The binary
    image 'imMarkers' contains the markers which control the flooding process.
    'imOut' contains the valued watershed.
    """

    im_mark = mamba.imageMb(imIn, 32)
    imWrk = mamba.imageMb(imIn)
    label(imMarkers, im_mark, grid=grid)
    watershedSegment(imIn, im_mark, grid=grid)
    mamba.copyBytePlane(im_mark, 3, imWrk)
    mamba.logic(imWrk, imIn, imOut, "inf")
Example #46
0
def floorSubConst(imIn, v, imOut):
    """
    Subtracts a constant value 'v' to image 'imIn' and puts the result in 'imOut'.
    If imIn - v is negative, the result is truncated and limited to 0.
    
    Note that this operator is mainly useful for 32-bit images, as the result
    of the subtraction is always truncated for 8-bit images.
    """
    
    imMask = mamba.imageMb(imIn, 1)
    imWrk = mamba.imageMb(imIn)
    mamba.subConst(imIn, v, imWrk)
    mamba.generateSupMask(imIn, imWrk, imMask, False)
    mamba.convertByMask(imMask, imOut, 0, mamba.computeMaxRange(imOut)[1])
    mamba.logic(imOut, imWrk, imOut, "inf")
Example #47
0
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")
Example #48
0
    def mamba_ws(self, NEED_WL, res_type):
        imDist = imageMb(*self.dist.shape, 32)
        fillImageWithArray(self.dist, imDist)
        imMarkers = imageMb(*self.markers.shape, 32)
        fillImageWithArray(self.markers.astype(np.uint32), imMarkers)

        if NEED_WL:
            labels, res = decorator(watershedSegment, res_type)(imDist, imMarkers, grid=SQUARE)
        else:
            labels, res = decorator(basinSegment,res_type)(imDist, imMarkers, grid=SQUARE)

        tmp = imageMb(*self.markers.shape, 8)
        copyBytePlane(tmp, 3, imMarkers)
        self.labels = getArrayFromImage(imMarkers, self.size)
        return res
Example #49
0
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")
Example #50
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 #51
0
def blackClip(imIn, imOut, step=0, grid=mamba.DEFAULT_GRID):
    """
    Performs a black skeleton clipping (clipping of a black skeleton image). 
    If 'step' is not defined (or equal to 0), the clipping is performed until 
    idempotence. If 'step' is defined, 'step' black points (if possible) will be 
    removed from each branch of the black skeleton.
    
    'edge' is always set to FILLED.
    """
    
    imWrk = mamba.imageMb(imIn)
    mamba.negate(imIn, imOut)
    if step == 0:
        v1 = mamba.computeVolume(imOut)
        v2 = 0
        while v1 != v2:
            v2 = v1
            endPoints(imOut, imWrk, grid=grid, edge=mamba.FILLED)
            mamba.diff(imOut, imWrk, imOut)
            v1 = mamba.computeVolume(imOut)
    else:
        for i in range(step):
            endPoints(imOut, imWrk, grid=grid, edge=mamba.FILLED)
            mamba.diff(imOut, imWrk, imOut)
    mamba.negate(imOut, imOut)
Example #52
0
def cellsErode(imIn, imOut, n=1, se=mamba.DEFAULT_SE, edge=mamba.FILLED):
    """
    Simultaneous erosion of size 'n' (default 1) of all the cells of the
    partition image 'imIn' with 'se' structuring element.
    The resulting partition is put in 'imOut'.
    'edge' is set to FILLED by default.
    This operation works on 8-bit and 32-bit partitions.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn, 1)
    mamba.dilate(imIn, imWrk1, n=n, se=se)
    mamba.erode(imIn, imOut, n=n, se=se, edge=edge)
    mamba.generateSupMask(imOut, imWrk1, imWrk2, False)
    mamba.convertByMask(imWrk2, imWrk1, 0, mamba.computeMaxRange(imIn)[1])
    mamba.logic(imOut, imWrk1, imOut, "inf")
Example #53
0
def cellsComputeDistance(imIn, imOut, grid=mamba.DEFAULT_GRID, edge=mamba.EMPTY):
    """
    Computation of the distance function for each cell of the partition
    image 'imIn'.
    The result is put in the 32-bit image 'imOut'.
    This operator works on hexagonal or square 'grid' and
    'edge' is set to EMPTY by default.
    """
    
    imWrk1 = mamba.imageMb(imIn)
    imWrk2 = mamba.imageMb(imIn, 1)
    se = mamba.structuringElement(mamba.getDirections(grid), grid)
    cellsErode(imIn, imWrk1, 1, se=se, edge=edge)
    mamba.threshold(imWrk1, imWrk2, 1, 255)
    mamba.computeDistance(imWrk2, imOut, grid=grid, edge=edge)
    mamba.addConst(imOut, 1, imOut)