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)
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")
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")
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")
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")
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)
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")
def generalSegment(imIn, imOut, gain=2.0, offset=1, grid=mamba.DEFAULT_GRID): """ General segmentation algorithm. This algorithm is controlled by two parameters: the 'gain' (identical to the gain used in standard and P segmentation) and a new one, the 'offset'. The 'offset' indicates which level of hierarchy is compared to the current hierarchical image. The 'offset' is relative to the current hierarchical level. If 'offset' is equal to 1, this operator corresponds to the standard segmentation, if 'offset' is equal to 255 (this value stands for the infinity), the operator is equivalent to P algorithm. Image 'imOut' contains all these hierarchies which are embedded. 'imIn' and 'imOut' must be greyscale images. 'imIn' and 'imOut' must be different. This transformation returns the number of hierarchical levels. """ imWrk0 = mamba.imageMb(imIn) imWrk1 = mamba.imageMb(imIn) imWrk2 = mamba.imageMb(imIn) imWrk3 = mamba.imageMb(imIn) imWrk4 = mamba.imageMb(imIn, 1) imWrk5 = mamba.imageMb(imIn, 1) imWrk6 = mamba.imageMb(imIn, 32) mamba.copy(imIn, imWrk1) mamba.mulRealConst(imIn, gain, imWrk6) mamba.floorSubConst(imWrk6, 1, imWrk6) mamba.threshold(imWrk6, imWrk4, 255, mamba.computeMaxRange(imWrk6)[1]) mamba.copyBytePlane(imWrk6, 0, imWrk0) mamba.convert(imWrk4, imWrk2) mamba.logic(imWrk0, imWrk2, imWrk0, "sup") mamba.logic(imWrk0, imWrk1, imWrk0, "sup") imOut.reset() nbLevels = 0 mamba.threshold(imWrk1, imWrk4, 1, 255) flag = not (mamba.checkEmptiness(imWrk4)) while flag: nbLevels += 1 hierarchy(imWrk1, imWrk4, imWrk2, grid=grid) mamba.add(imOut, imWrk4, imOut) v = max(nbLevels - offset, 0) + 1 mamba.threshold(imOut, imWrk4, v, 255) mamba.valuedWatershed(imWrk2, imWrk3, grid=grid) mamba.threshold(imWrk3, imWrk5, 1, 255) flag = not (mamba.checkEmptiness(imWrk5)) hierarchy(imWrk3, imWrk5, imWrk2, grid=grid) mamba.generateSupMask(imWrk0, imWrk2, imWrk5, strict=False) mamba.logic(imWrk4, imWrk5, imWrk4, "inf") mamba.convertByMask(imWrk4, imWrk3, 0, 255) mamba.logic(imWrk1, imWrk3, imWrk3, "inf") mamba.negate(imWrk4, imWrk4) mamba.label(imWrk4, imWrk6, grid=grid) mamba.watershedSegment(imWrk3, imWrk6, grid=grid) mamba.copyBytePlane(imWrk6, 3, imWrk3) mamba.logic(imWrk1, imWrk2, imWrk1, "sup") mamba.logic(imWrk1, imWrk3, imWrk1, "inf") mamba.threshold(imWrk1, imWrk4, 1, 255) return nbLevels
def generalSegment(imIn, imOut, gain=2.0, offset=1, grid=mamba.DEFAULT_GRID): """ General segmentation algorithm. This algorithm is controlled by two parameters: the 'gain' (identical to the gain used in standard and P segmentation) and a new one, the 'offset'. The 'offset' indicates which level of hierarchy is compared to the current hierarchical image. The 'offset' is relative to the current hierarchical level. If 'offset' is equal to 1, this operator corresponds to the standard segmentation, if 'offset' is equal to 255 (this value stands for the infinity), the operator is equivalent to P algorithm. Image 'imOut' contains all these hierarchies which are embedded. 'imIn' and 'imOut' must be greyscale images. 'imIn' and 'imOut' must be different. This transformation returns the number of hierarchical levels. """ imWrk0 = mamba.imageMb(imIn) imWrk1 = mamba.imageMb(imIn) imWrk2 = mamba.imageMb(imIn) imWrk3 = mamba.imageMb(imIn) imWrk4 = mamba.imageMb(imIn, 1) imWrk5 = mamba.imageMb(imIn, 1) imWrk6 = mamba.imageMb(imIn, 32) mamba.copy(imIn, imWrk1) mamba.mulRealConst(imIn, gain, imWrk6) mamba.floorSubConst(imWrk6, 1, imWrk6) mamba.threshold(imWrk6, imWrk4, 255, mamba.computeMaxRange(imWrk6)[1]) mamba.copyBytePlane(imWrk6, 0, imWrk0) mamba.convert(imWrk4, imWrk2) mamba.logic(imWrk0, imWrk2, imWrk0, "sup") mamba.logic(imWrk0, imWrk1, imWrk0, "sup") imOut.reset() nbLevels = 0 mamba.threshold(imWrk1, imWrk4, 1, 255) flag = not(mamba.checkEmptiness(imWrk4)) while flag: nbLevels += 1 hierarchy(imWrk1, imWrk4, imWrk2, grid=grid) mamba.add(imOut, imWrk4, imOut) v = max(nbLevels - offset, 0) + 1 mamba.threshold(imOut, imWrk4, v, 255) mamba.valuedWatershed(imWrk2, imWrk3, grid=grid) mamba.threshold(imWrk3, imWrk5, 1, 255) flag = not(mamba.checkEmptiness(imWrk5)) hierarchy(imWrk3, imWrk5, imWrk2, grid=grid) mamba.generateSupMask(imWrk0, imWrk2, imWrk5, strict=False) mamba.logic(imWrk4, imWrk5, imWrk4, "inf") mamba.convertByMask(imWrk4, imWrk3, 0, 255) mamba.logic(imWrk1, imWrk3, imWrk3, "inf") mamba.negate(imWrk4, imWrk4) mamba.label(imWrk4, imWrk6, grid=grid) mamba.watershedSegment(imWrk3, imWrk6, grid=grid) mamba.copyBytePlane(imWrk6, 3, imWrk3) mamba.logic(imWrk1, imWrk2, imWrk1, "sup") mamba.logic(imWrk1, imWrk3, imWrk1, "inf") mamba.threshold(imWrk1, imWrk4, 1, 255) return nbLevels
def standardSegment(imIn, imOut, gain=2.0, grid=mamba.DEFAULT_GRID): """ General standard segmentation. This algorithm keeps the contours of the watershed transform which are above or equal to the hierarchical image associated to the next level of hierarchy when the altitude of the contour is multiplied by a 'gain' factor (default is 2.0). This transform also ends by idempotence. All the hierarchical levels of image 'imIn'(which is a valued watershed) are computed. 'imOut' contains all these hierarchies which are embedded, so that hierarchy i is simply obtained by a threshold [i+1, 255] of image 'imOut'. 'imIn' and 'imOut' must be greyscale images. 'imIn' and 'imOut' must be different. This transformation returns the number of hierarchical levels. """ imWrk0 = mamba.imageMb(imIn) imWrk1 = mamba.imageMb(imIn) imWrk2 = mamba.imageMb(imIn) imWrk3 = mamba.imageMb(imIn) imWrk4 = mamba.imageMb(imIn, 1) imWrk5 = mamba.imageMb(imIn, 1) imWrk6 = mamba.imageMb(imIn, 32) mamba.copy(imIn, imWrk1) mamba.mulRealConst(imIn, gain, imWrk6) mamba.floorSubConst(imWrk6, 1, imWrk6) mamba.threshold(imWrk6, imWrk4, 255, mamba.computeMaxRange(imWrk6)[1]) mamba.copyBytePlane(imWrk6, 0, imWrk0) mamba.convert(imWrk4, imWrk2) mamba.logic(imWrk0, imWrk2, imWrk0, "sup") mamba.logic(imWrk0, imWrk1, imWrk0, "sup") imOut.reset() nbLevels = 0 mamba.threshold(imWrk1, imWrk4, 1, 255) flag = not (mamba.checkEmptiness(imWrk4)) while flag: hierarchy(imWrk1, imWrk4, imWrk2, grid=grid) mamba.add(imOut, imWrk4, imOut) mamba.valuedWatershed(imWrk2, imWrk3, grid=grid) mamba.threshold(imWrk3, imWrk5, 1, 255) flag = not (mamba.checkEmptiness(imWrk5)) hierarchy(imWrk3, imWrk5, imWrk2, grid=grid) mamba.generateSupMask(imWrk0, imWrk2, imWrk5, strict=False) mamba.logic(imWrk4, imWrk5, imWrk4, "inf") mamba.convertByMask(imWrk4, imWrk3, 0, 255) mamba.logic(imWrk1, imWrk3, imWrk3, "inf") mamba.negate(imWrk4, imWrk4) mamba.label(imWrk4, imWrk6, grid=grid) mamba.watershedSegment(imWrk3, imWrk6, grid=grid) mamba.copyBytePlane(imWrk6, 3, imWrk3) mamba.logic(imWrk1, imWrk2, imWrk1, "sup") mamba.logic(imWrk1, imWrk3, imWrk1, "inf") mamba.threshold(imWrk1, imWrk4, 1, 255) nbLevels += 1 return nbLevels
def standardSegment(imIn, imOut, gain=2.0, grid=mamba.DEFAULT_GRID): """ General standard segmentation. This algorithm keeps the contours of the watershed transform which are above or equal to the hierarchical image associated to the next level of hierarchy when the altitude of the contour is multiplied by a 'gain' factor (default is 2.0). This transform also ends by idempotence. All the hierarchical levels of image 'imIn'(which is a valued watershed) are computed. 'imOut' contains all these hierarchies which are embedded, so that hierarchy i is simply obtained by a threshold [i+1, 255] of image 'imOut'. 'imIn' and 'imOut' must be greyscale images. 'imIn' and 'imOut' must be different. This transformation returns the number of hierarchical levels. """ imWrk0 = mamba.imageMb(imIn) imWrk1 = mamba.imageMb(imIn) imWrk2 = mamba.imageMb(imIn) imWrk3 = mamba.imageMb(imIn) imWrk4 = mamba.imageMb(imIn, 1) imWrk5 = mamba.imageMb(imIn, 1) imWrk6 = mamba.imageMb(imIn, 32) mamba.copy(imIn, imWrk1) mamba.mulRealConst(imIn, gain, imWrk6) mamba.floorSubConst(imWrk6, 1, imWrk6) mamba.threshold(imWrk6, imWrk4, 255, mamba.computeMaxRange(imWrk6)[1]) mamba.copyBytePlane(imWrk6, 0, imWrk0) mamba.convert(imWrk4, imWrk2) mamba.logic(imWrk0, imWrk2, imWrk0, "sup") mamba.logic(imWrk0, imWrk1, imWrk0, "sup") imOut.reset() nbLevels = 0 mamba.threshold(imWrk1, imWrk4, 1, 255) flag = not(mamba.checkEmptiness(imWrk4)) while flag: hierarchy(imWrk1, imWrk4, imWrk2, grid=grid) mamba.add(imOut, imWrk4, imOut) mamba.valuedWatershed(imWrk2, imWrk3, grid=grid) mamba.threshold(imWrk3, imWrk5, 1, 255) flag = not(mamba.checkEmptiness(imWrk5)) hierarchy(imWrk3, imWrk5, imWrk2, grid=grid) mamba.generateSupMask(imWrk0, imWrk2, imWrk5, strict=False) mamba.logic(imWrk4, imWrk5, imWrk4, "inf") mamba.convertByMask(imWrk4, imWrk3, 0, 255) mamba.logic(imWrk1, imWrk3, imWrk3, "inf") mamba.negate(imWrk4, imWrk4) mamba.label(imWrk4, imWrk6, grid=grid) mamba.watershedSegment(imWrk3, imWrk6, grid=grid) mamba.copyBytePlane(imWrk6, 3, imWrk3) mamba.logic(imWrk1, imWrk2, imWrk1, "sup") mamba.logic(imWrk1, imWrk3, imWrk1, "inf") mamba.threshold(imWrk1, imWrk4, 1, 255) nbLevels += 1 return nbLevels
def _generateMask_(imIn1, imIn2, imOut): #This procedure is used internally by the residues operators. It computes #a mask indicating the points in the image where 'imIn1' is greater or equal #to 'imIn2' with 'imIn1' strictly positive. #Depth of 'imOut' is 1. imWrk = mamba.imageMb(imOut) mamba.generateSupMask(imIn1, imIn2, imOut, False) if imIn1.getDepth()==1: mamba.negate(imIn1, imWrk) else: mamba.threshold(imIn1, imWrk, 0, 0) mamba.diff(imOut, imWrk, imOut)
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")
def ceilingAddConst(imIn, v, imOut): """ Adds a constant value 'v' to image 'imIn' and puts the result in 'imOut'. If imIn + v is larger than the maximal possible value in imOut, the result is truncated and limited to this maximal value. Note that this operator is mainly useful for 32-bit images, as the result of the addition is always truncated for 8-bit images. """ imMask = mamba.imageMb(imIn, 1) imWrk = mamba.imageMb(imIn) mamba.addConst(imIn, v, imWrk) mamba.generateSupMask(imIn, imWrk, imMask, True) mamba.convertByMask(imMask, imOut, 0, mamba.computeMaxRange(imOut)[1]) mamba.logic(imOut, imWrk, imOut, "sup")
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")
def extendedSegment(imIn, imTest, imOut, offset=255, grid=mamba.DEFAULT_GRID): """ Extended (experimental) segmentation algorithm. This algorithm is controlled by image 'imTest'. The current hierarchical image is compared to image 'imTest'. This image must be a greyscale image. The 'offset' indicates which level of hierarchy is compared to the current hierarchical image. The 'offset' is relative to the current hierarchical level (by default, 'offset' is equal to 255, so that the initial segmentation is used). Image 'imOut' contains all these hierarchies which are embedded. 'imIn', 'imTest' and 'imOut' must be greyscale images. 'imIn', 'imTest' and 'imOut' must be different. This transformation returns the number of hierarchical levels. """ imWrk1 = mamba.imageMb(imIn) imWrk2 = mamba.imageMb(imIn) imWrk3 = mamba.imageMb(imIn) imWrk4 = mamba.imageMb(imIn, 1) imWrk5 = mamba.imageMb(imIn, 1) imWrk6 = mamba.imageMb(imIn, 32) mamba.copy(imIn, imWrk1) imOut.reset() nbLevels = 0 mamba.threshold(imWrk1, imWrk4, 1, 255) flag = not(mamba.checkEmptiness(imWrk4)) while flag: nbLevels += 1 hierarchy(imWrk1, imWrk4, imWrk2, grid=grid) mamba.add(imOut, imWrk4, imOut) v = max(nbLevels - offset, 0) + 1 mamba.threshold(imOut, imWrk4, v, 255) mamba.valuedWatershed(imWrk2, imWrk3, grid=grid) mamba.threshold(imWrk3, imWrk5, 1, 255) flag = not(mamba.checkEmptiness(imWrk5)) hierarchy(imWrk3, imWrk5, imWrk2, grid=grid) mamba.generateSupMask(imTest, imWrk2, imWrk5, strict=False) mamba.logic(imWrk4, imWrk5, imWrk4, "inf") mamba.convertByMask(imWrk4, imWrk3, 0, 255) mamba.logic(imWrk1, imWrk3, imWrk3, "inf") mamba.negate(imWrk4, imWrk4) mamba.label(imWrk4, imWrk6, grid=grid) mamba.watershedSegment(imWrk3, imWrk6, grid=grid) mamba.copyBytePlane(imWrk6, 3, imWrk3) mamba.logic(imWrk1, imWrk2, imWrk1, "sup") mamba.logic(imWrk1, imWrk3, imWrk1, "inf") mamba.threshold(imWrk1, imWrk4, 1, 255) return nbLevels
def extendedSegment(imIn, imTest, imOut, offset=255, grid=mamba.DEFAULT_GRID): """ Extended (experimental) segmentation algorithm. This algorithm is controlled by image 'imTest'. The current hierarchical image is compared to image 'imTest'. This image must be a greyscale image. The 'offset' indicates which level of hierarchy is compared to the current hierarchical image. The 'offset' is relative to the current hierarchical level (by default, 'offset' is equal to 255, so that the initial segmentation is used). Image 'imOut' contains all these hierarchies which are embedded. 'imIn', 'imTest' and 'imOut' must be greyscale images. 'imIn', 'imTest' and 'imOut' must be different. This transformation returns the number of hierarchical levels. """ imWrk1 = mamba.imageMb(imIn) imWrk2 = mamba.imageMb(imIn) imWrk3 = mamba.imageMb(imIn) imWrk4 = mamba.imageMb(imIn, 1) imWrk5 = mamba.imageMb(imIn, 1) imWrk6 = mamba.imageMb(imIn, 32) mamba.copy(imIn, imWrk1) imOut.reset() nbLevels = 0 mamba.threshold(imWrk1, imWrk4, 1, 255) flag = not (mamba.checkEmptiness(imWrk4)) while flag: nbLevels += 1 hierarchy(imWrk1, imWrk4, imWrk2, grid=grid) mamba.add(imOut, imWrk4, imOut) v = max(nbLevels - offset, 0) + 1 mamba.threshold(imOut, imWrk4, v, 255) mamba.valuedWatershed(imWrk2, imWrk3, grid=grid) mamba.threshold(imWrk3, imWrk5, 1, 255) flag = not (mamba.checkEmptiness(imWrk5)) hierarchy(imWrk3, imWrk5, imWrk2, grid=grid) mamba.generateSupMask(imTest, imWrk2, imWrk5, strict=False) mamba.logic(imWrk4, imWrk5, imWrk4, "inf") mamba.convertByMask(imWrk4, imWrk3, 0, 255) mamba.logic(imWrk1, imWrk3, imWrk3, "inf") mamba.negate(imWrk4, imWrk4) mamba.label(imWrk4, imWrk6, grid=grid) mamba.watershedSegment(imWrk3, imWrk6, grid=grid) mamba.copyBytePlane(imWrk6, 3, imWrk3) mamba.logic(imWrk1, imWrk2, imWrk1, "sup") mamba.logic(imWrk1, imWrk3, imWrk1, "inf") mamba.threshold(imWrk1, imWrk4, 1, 255) return nbLevels
def generateSupMask3D(imIn1, imIn2, imOut, strict): """ Generates a 3D binary mask image in 'imOut' where pixels are set to 1 when they are greater (strictly if 'strict' is set to True, greater or equal otherwise) in 3D image 'imIn1' than in 3D image 'imIn2'. 'imIn1' and imIn2' can be 1-bit, 8-bit or 32-bit images of same size, length and depth. """ outl = len(imOut) in1l = len(imIn1) in2l = len(imIn2) if in1l != outl or in2l != outl: mamba.raiseExceptionOnError(core.MB_ERR_BAD_SIZE) for i in range(outl): mamba.generateSupMask(imIn1[i], imIn2[i], imOut[i], strict)
def generateSupMask3D(imIn1, imIn2, imOut, strict): """ Generates a 3D binary mask image in 'imOut' where pixels are set to 1 when they are greater (strictly if 'strict' is set to True, greater or equal otherwise) in 3D image 'imIn1' than in 3D image 'imIn2'. 'imIn1' and imIn2' can be 1-bit, 8-bit or 32-bit images of same size, length and depth. """ outl = len(imOut) in1l = len(imIn1) in2l = len(imIn2) if in1l!=outl or in2l!=outl: mamba.raiseExceptionOnError(core.MB_ERR_BAD_SIZE) for i in range(outl): mamba.generateSupMask(imIn1[i], imIn2[i], imOut[i], strict)
def floorSub(imIn1, imIn2, imOut): """ Subtracts image 'imIn2' from image 'imIn1' and puts the result in 'imOut'. If imIn1 - imIn2 is negative, the result is truncated and limited to 0. Although it is possible to use a 8-bit image for imIn2, it is recommended to use the same depth for all the images. 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(imIn1, 1) imWrk = mamba.imageMb(imIn1) mamba.sub(imIn1, imIn2, imWrk) mamba.generateSupMask(imIn1, imWrk, imMask, False) mamba.convertByMask(imMask, imOut, 0, mamba.computeMaxRange(imOut)[1]) mamba.logic(imOut, imWrk, imOut, "inf")
def ceilingAdd(imIn1, imIn2, imOut): """ Adds image 'imIn2' to image 'imIn1' and puts the result in 'imOut'. If imIn1 + imIn2 is larger than the maximal possible value in imOut, the result is truncated and limited to this maximal value. Although it is possible to use a 8-bit image for imIn2, it is recommended to use the same depth for all the images. Note that this operator is mainly useful for 32-bit images, as the result of the addition is always truncated for 8-bit images. """ imMask = mamba.imageMb(imIn1, 1) imWrk = mamba.imageMb(imIn1) mamba.add(imIn1, imIn2, imWrk) mamba.generateSupMask(imIn1, imWrk, imMask, True) mamba.convertByMask(imMask, imOut, 0, mamba.computeMaxRange(imOut)[1]) mamba.logic(imOut, imWrk, imOut, "sup")
def equalNeighbors(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 equal, 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, 1) mamba.copy(imIn, imWrk1) mamba.copy(imIn, imOut) mamba.supNeighbor(imIn, imWrk1, nb, grid=grid, edge=edge) mamba.infNeighbor(imOut, imOut, nb, grid=grid, edge=edge) mamba.generateSupMask(imOut, imWrk1, imWrk2, False) mamba.convertByMask(imWrk2, imWrk1, 0, mamba.computeMaxRange(imIn)[1]) mamba.logic(imOut, imWrk1, imOut, "inf")
def enhancedWaterfalls(imIn, imOut, grid=mamba.DEFAULT_GRID): """ Enhanced waterfall algorithm. Compared to the classical waterfalls algorithm, this one adds the contours of the watershed transform which are above the hierarchical image associated to the next level of hierarchy. This waterfalls transform also ends to an empty set. All the hierarchical levels of image 'imIn' (which is a valued watershed) are computed. 'imOut' contains all these hierarchies which are embedded, so that hierarchy i is simply obtained by a threshold [i+1, 255] of image 'imOut'. 'imIn' and 'imOut' must be greyscale images. 'imIn' and 'imOu't must be different. This transformation returns the number of hierarchical levels. """ imWrk1 = mamba.imageMb(imIn) imWrk2 = mamba.imageMb(imIn) imWrk3 = mamba.imageMb(imIn) imWrk4 = mamba.imageMb(imIn, 1) imWrk5 = mamba.imageMb(imIn, 32) mamba.copy(imIn, imWrk1) imOut.reset() nbLevels = 0 mamba.threshold(imWrk1, imWrk4, 1, 255) flag = not(mamba.checkEmptiness(imWrk4)) while flag: mamba.add(imOut, imWrk4, imOut) hierarchy(imWrk1, imWrk4, imWrk2, grid=grid) mamba.valuedWatershed(imWrk2, imWrk3, grid=grid) mamba.threshold(imWrk3, imWrk4, 1, 255) flag = not(mamba.checkEmptiness(imWrk4)) hierarchy(imWrk3, imWrk4, imWrk2, grid=grid) mamba.generateSupMask(imWrk2, imWrk1, imWrk4, strict=True) mamba.convertByMask(imWrk4, imWrk3, 255, 0) mamba.logic(imWrk1, imWrk3, imWrk3, "inf") mamba.label(imWrk4, imWrk5, grid=grid) mamba.watershedSegment(imWrk3, imWrk5, grid=grid) mamba.copyBytePlane(imWrk5, 3, imWrk1) mamba.logic(imWrk1, imWrk3, imWrk1, "inf") mamba.threshold(imWrk1, imWrk4, 1, 255) nbLevels += 1 return nbLevels
def enhancedWaterfalls(imIn, imOut, grid=mamba.DEFAULT_GRID): """ Enhanced waterfall algorithm. Compared to the classical waterfalls algorithm, this one adds the contours of the watershed transform which are above the hierarchical image associated to the next level of hierarchy. This waterfalls transform also ends to an empty set. All the hierarchical levels of image 'imIn' (which is a valued watershed) are computed. 'imOut' contains all these hierarchies which are embedded, so that hierarchy i is simply obtained by a threshold [i+1, 255] of image 'imOut'. 'imIn' and 'imOut' must be greyscale images. 'imIn' and 'imOu't must be different. This transformation returns the number of hierarchical levels. """ imWrk1 = mamba.imageMb(imIn) imWrk2 = mamba.imageMb(imIn) imWrk3 = mamba.imageMb(imIn) imWrk4 = mamba.imageMb(imIn, 1) imWrk5 = mamba.imageMb(imIn, 32) mamba.copy(imIn, imWrk1) imOut.reset() nbLevels = 0 mamba.threshold(imWrk1, imWrk4, 1, 255) flag = not (mamba.checkEmptiness(imWrk4)) while flag: mamba.add(imOut, imWrk4, imOut) hierarchy(imWrk1, imWrk4, imWrk2, grid=grid) mamba.valuedWatershed(imWrk2, imWrk3, grid=grid) mamba.threshold(imWrk3, imWrk4, 1, 255) flag = not (mamba.checkEmptiness(imWrk4)) hierarchy(imWrk3, imWrk4, imWrk2, grid=grid) mamba.generateSupMask(imWrk2, imWrk1, imWrk4, strict=True) mamba.convertByMask(imWrk4, imWrk3, 255, 0) mamba.logic(imWrk1, imWrk3, imWrk3, "inf") mamba.label(imWrk4, imWrk5, grid=grid) mamba.watershedSegment(imWrk3, imWrk5, grid=grid) mamba.copyBytePlane(imWrk5, 3, imWrk1) mamba.logic(imWrk1, imWrk3, imWrk1, "inf") mamba.threshold(imWrk1, imWrk4, 1, 255) nbLevels += 1 return nbLevels
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")
def simpleLevelling(imIn, imMask, imOut, grid=mamba.DEFAULT_GRID): """ Performs a simple levelling of image 'imIn' controlled by image 'imMask' and puts the result in 'imOut'. This operation is composed of two geodesic reconstructions. This filter tends to level regions in the image of homogeneous grey values. """ imWrk1 = mamba.imageMb(imIn) imWrk2 = mamba.imageMb(imIn) mask_im = mamba.imageMb(imIn, 1) mamba.logic(imIn, imMask, imWrk1, "inf") mamba.build(imIn, imWrk1, grid=grid) mamba.logic(imIn, imMask, imWrk2, "sup") mamba.dualBuild(imIn, imWrk2, grid=grid) mamba.generateSupMask(imIn, imMask, mask_im, False) mamba.convertByMask(mask_im, imOut, 0, mamba.computeMaxRange(imIn)[1]) mamba.logic(imOut, imWrk1, imWrk1, "inf") mamba.negate(imOut, imOut) mamba.logic(imOut, imWrk2, imOut, "inf") mamba.logic(imWrk1, imOut, imOut, "sup")