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)
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)
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)
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")
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")
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)
def measureLabelling(imIn, imMeasure, imOut): """ Labelling each particle of the binary image or each cell of the partition 'imIn' with the number of pixels in the binary image 'imMeasure' contained in each particle or each cell of the partition. The result is put is the 32-bit image 'imOut'. """ imWrk1 = mamba.imageMb(imIn, 32) imWrk2 = mamba.imageMb(imIn, 1) imWrk3 = mamba.imageMb(imIn, 8) imWrk4 = mamba.imageMb(imIn, 8) imWrk5 = mamba.imageMb(imIn, 8) imWrk6 = mamba.imageMb(imIn, 32) # Output image is emptied. imOut.reset() # Labelling the initial image. if imIn.getDepth() == 1: nbParticles = mamba.label(imIn, imWrk1) else: nbParticles = partitionLabel(imIn, imWrk1) # Defining output LUTs. outLuts = [[0 for i in range(256)] for i in range(4)] # Converting the imMeasure image to 8-bit. mamba.convert(imMeasure, imWrk4) while nbParticles > 0: # Particles with labels between 1 and 255 are extracted. mamba.threshold(imWrk1, imWrk2, 0, 255) mamba.convert(imWrk2, imWrk3) mamba.copyBytePlane(imWrk1, 0, imWrk5) mamba.logic(imWrk3, imWrk5, imWrk3, "inf") # The points contained in each particle are labelled. mamba.logic(imWrk3, imWrk4, imWrk5, "inf") # The histogram is computed. histo = mamba.getHistogram(imWrk5) # The same operation is performed for the 255 particles. for i in range(1, 256): # The number of points in each particle is obtained from the histogram. value = histo[i] j = 3 # This value is splitted in powers of 256 and stored in the four # output LUTs. while j >= 0: n = 2**(8 * j) outLuts[j][i] = value // n value = value % n j -= 1 # Each LUT is used to label each byte plane of a temporary image with the # corresponding value. for i in range(4): mamba.lookup(imWrk3, imWrk5, outLuts[i]) mamba.copyBytePlane(imWrk5, i, imWrk6) # The intermediary result is accumulated in the final image. mamba.logic(imOut, imWrk6, imOut, "sup") # 255 is subtracted from the initial labelled image in order to process # the next 255 particles. mamba.floorSubConst(imWrk1, 255, imWrk1) nbParticles -= 255
def measureLabelling(imIn, imMeasure, imOut): """ Labelling each particle of the binary image or each cell of the partition 'imIn' with the number of pixels in the binary image 'imMeasure' contained in each particle or each cell of the partition. The result is put is the 32-bit image 'imOut'. """ imWrk1 = mamba.imageMb(imIn, 32) imWrk2 = mamba.imageMb(imIn, 1) imWrk3 = mamba.imageMb(imIn, 8) imWrk4 = mamba.imageMb(imIn, 8) imWrk5 = mamba.imageMb(imIn, 8) imWrk6 = mamba.imageMb(imIn, 32) # Output image is emptied. imOut.reset() # Labelling the initial image. if imIn.getDepth() == 1: nbParticles = mamba.label(imIn, imWrk1) else: nbParticles = partitionLabel(imIn, imWrk1) # Defining output LUTs. outLuts = [[0 for i in range(256)] for i in range(4)] # Converting the imMeasure image to 8-bit. mamba.convert(imMeasure, imWrk4) while nbParticles > 0: # Particles with labels between 1 and 255 are extracted. mamba.threshold(imWrk1, imWrk2, 0, 255) mamba.convert(imWrk2, imWrk3) mamba.copyBytePlane(imWrk1, 0, imWrk5) mamba.logic(imWrk3, imWrk5, imWrk3, "inf") # The points contained in each particle are labelled. mamba.logic(imWrk3, imWrk4, imWrk5, "inf") # The histogram is computed. histo = mamba.getHistogram(imWrk5) # The same operation is performed for the 255 particles. for i in range(1, 256): # The number of points in each particle is obtained from the histogram. value = histo[i] j = 3 # This value is splitted in powers of 256 and stored in the four # output LUTs. while j >= 0: n = 2 ** (8 * j) outLuts[j][i] = value // n value = value % n j -= 1 # Each LUT is used to label each byte plane of a temporary image with the # corresponding value. for i in range(4): mamba.lookup(imWrk3, imWrk5, outLuts[i]) mamba.copyBytePlane(imWrk5, i, imWrk6) # The intermediary result is accumulated in the final image. mamba.logic(imOut, imWrk6, imOut, "sup") # 255 is subtracted from the initial labelled image in order to process # the next 255 particles. mamba.floorSubConst(imWrk1, 255, imWrk1) nbParticles -= 255
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 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")
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')
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
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 copyBytePlane3D(imIn, plane, imOut): """ Inserts or extracts a byte plane in a 3D image. If 'imIn' is a greyscale image, it is inserted at 'plane' position in 32-bit 'imOut'. If 'imIn' is a 32-bit image, its byte plane at 'plane' position is extracted and put into 'imOut'. Plane values are 0 (LSByte) to 3 (MSByte). """ outl = len(imOut) inl = len(imIn) if inl!=outl: mamba.raiseExceptionOnError(core.MB_ERR_BAD_SIZE) for i in range(outl): mamba.copyBytePlane(imIn[i], plane, imOut[i])
def copyBytePlane3D(imIn, plane, imOut): """ Inserts or extracts a byte plane in a 3D image. If 'imIn' is a greyscale image, it is inserted at 'plane' position in 32-bit 'imOut'. If 'imIn' is a 32-bit image, its byte plane at 'plane' position is extracted and put into 'imOut'. Plane values are 0 (LSByte) to 3 (MSByte). """ outl = len(imOut) inl = len(imIn) if inl != outl: mamba.raiseExceptionOnError(core.MB_ERR_BAD_SIZE) for i in range(outl): mamba.copyBytePlane(imIn[i], plane, imOut[i])
def updateim(self): # Updates the display (perform a rendering) depth = self.im_ref().getDepth() volume = 0 if depth == 1: # binary 3D image self.planeLabel.config(text="") im8 = mamba.imageMb(self.W, self.H, 8) self.raw = b"" for im2D in self.im_ref(): mamba.convert(im2D, im8) self.raw += im8.extractRaw() volume += mamba.computeVolume(im2D) elif depth == 32: # 32-bit 3D image if self.master.bplane == 4: self.planeLabel.config(text="Plane : all") im3D_8 = m3D.image3DMb(self.im_ref(), 8) m3D.convert3D(self.im_ref(), im3D_8) self.raw = im3D_8.extractRaw() volume = m3D.computeVolume3D(self.im_ref()) else: self.planeLabel.config(text="Plane : %d" % (self.master.bplane)) im8 = mamba.imageMb(self.W, self.H, 8) self.raw = b"" for im2D in self.im_ref(): mamba.copyBytePlane(im2D, self.master.bplane, im8) self.raw += im8.extractRaw() volume += mamba.computeVolume(im2D) else: # Greyscale image self.planeLabel.config(text="") self.raw = self.im_ref().extractRaw() volume = m3D.computeVolume3D(self.im_ref()) self.setImagePlaneZ() self.setImagePlaneY() self.setImagePlaneX() self.planex.eraseTarget() self.planey.eraseTarget() self.planez.eraseTarget() self.volLabel.config(text="Volume : %d" % (volume)) value = self.im_ref().getPixel((self.x, self.y, self.z)) self.posLabel.config(text="At (%d,%d,%d) = %d" % (self.x, self.y, self.z, value))
def updateim(self): # Updates the display (perform a rendering) depth = self.im_ref().getDepth() volume = 0 if depth==1: # binary 3D image self.planeLabel.config(text="") im8 = mamba.imageMb(self.W, self.H, 8) self.raw = b"" for im2D in self.im_ref(): mamba.convert(im2D, im8) self.raw += im8.extractRaw() volume += mamba.computeVolume(im2D) elif depth==32: # 32-bit 3D image if self.master.bplane==4: self.planeLabel.config(text="Plane : all") im3D_8 = m3D.image3DMb(self.im_ref(), 8) m3D.convert3D(self.im_ref(), im3D_8) self.raw = im3D_8.extractRaw() volume = m3D.computeVolume3D(self.im_ref()) else: self.planeLabel.config(text="Plane : %d" % (self.master.bplane)) im8 = mamba.imageMb(self.W, self.H, 8) self.raw = b"" for im2D in self.im_ref(): mamba.copyBytePlane(im2D, self.master.bplane, im8) self.raw += im8.extractRaw() volume += mamba.computeVolume(im2D) else: # Greyscale image self.planeLabel.config(text="") self.raw = self.im_ref().extractRaw() volume = m3D.computeVolume3D(self.im_ref()) self.setImagePlaneZ() self.setImagePlaneY() self.setImagePlaneX() self.planex.eraseTarget() self.planey.eraseTarget() self.planez.eraseTarget() self.volLabel.config(text="Volume : %d" % (volume)) value = self.im_ref().getPixel((self.x, self.y, self.z)) self.posLabel.config(text="At (%d,%d,%d) = %d" % (self.x,self.y,self.z,value))
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 updateim(self): # Updates the display (perform a rendering) volume = m3D.computeVolume3D(self.im_ref()) if self.im_ref().getDepth() == 32: immb = mamba.imageMb(self.im_ref()[self.z], 8) if self.master.bplane == 4: mamba.convert(self.im_ref()[self.z], immb) self.planeLabel.config(text="Plane : all") else: mamba.copyBytePlane(self.im_ref()[self.z], self.master.bplane, immb) self.planeLabel.config(text="Plane : %d" % (self.master.bplane)) im = utils.convertToPILFormat(immb.mbIm) else: self.planeLabel.config(text="") im = utils.convertToPILFormat(self.im_ref()[self.z].mbIm) if self.master.palname: im.putpalette(palette.getPalette(self.master.palname)) self.planez.display(im) self.volLabel.config(text="Volume : %d" % (volume)) value = self.im_ref().getPixel((self.x, self.y, self.z)) self.posLabel.config(text="At (%d,%d,%d) = %d" % (self.x, self.y, self.z, value))
def updateim(self): # Updates the display (perform a rendering) volume = m3D.computeVolume3D(self.im_ref()) if self.im_ref().getDepth()==32: immb = mamba.imageMb(self.im_ref()[self.z], 8) if self.master.bplane==4: mamba.convert(self.im_ref()[self.z], immb) self.planeLabel.config(text="Plane : all") else: mamba.copyBytePlane(self.im_ref()[self.z],self.master.bplane,immb) self.planeLabel.config(text="Plane : %d" % (self.master.bplane)) im = utils.convertToPILFormat(immb.mbIm) else: self.planeLabel.config(text="") im = utils.convertToPILFormat(self.im_ref()[self.z].mbIm) if self.master.palname: im.putpalette(palette.getPalette(self.master.palname)) self.planez.display(im) self.volLabel.config(text="Volume : %d" % (volume)) value = self.im_ref().getPixel((self.x, self.y, self.z)) self.posLabel.config(text="At (%d,%d,%d) = %d" % (self.x, self.y, self.z,value))
def updateim(self): # Updates the display with the new contents of the mamba image. if self.im_ref() and self.state()=="normal" and not self.frozen: if self.im_ref().getDepth()==32: im = mamba.imageMb(self.im_ref(), 8) if self.bplane==4: mamba.convert(self.im_ref(), im) self.infos[1].set("plane : all") else: mamba.copyBytePlane(self.im_ref(),self.bplane,im) self.infos[1].set("plane : %d" % (self.bplane)) self.pilImage = utils.convertToPILFormat(im.mbIm) else: self.infos[1].set("") self.pilImage = utils.convertToPILFormat(self.im_ref().mbIm) if self.palname: self.pilImage.putpalette(palette.getPalette(self.palname)) volume = mamba.computeVolume(self.im_ref()) self.infos[0].set("volume : "+str(volume)) self.icon = ImageTk.PhotoImage(self.pilImage.resize(self.icon_size, Image.NEAREST)) self.tk.call('wm','iconphoto', self._w, self.icon) self.drawImage()
def updateim(self): # Updates the display with the new contents of the mamba image. if self.im_ref() and self.state() == "normal" and not self.frozen: if self.im_ref().getDepth() == 32: im = mamba.imageMb(self.im_ref(), 8) if self.bplane == 4: mamba.convert(self.im_ref(), im) self.infos[1].set("plane : all") else: mamba.copyBytePlane(self.im_ref(), self.bplane, im) self.infos[1].set("plane : %d" % (self.bplane)) self.pilImage = utils.convertToPILFormat(im.mbIm) else: self.infos[1].set("") self.pilImage = utils.convertToPILFormat(self.im_ref().mbIm) if self.palname: self.pilImage.putpalette(palette.getPalette(self.palname)) volume = mamba.computeVolume(self.im_ref()) self.infos[0].set("volume : " + str(volume)) self.icon = ImageTk.PhotoImage( self.pilImage.resize(self.icon_size, Image.NEAREST)) self.tk.call('wm', 'iconphoto', self._w, self.icon) self.drawImage()
def _watershed_using_quasi_distance(self): """ 疑似ユークリッド距離(Quasi Distance) に基づく Watershed 領域分割 Returns ------- numpy.ndarray 領域分割線の画像 """ from mamba import ( imageMb, gradient, add, negate, quasiDistance, copyBytePlane, subConst, build, maxima, label, watershedSegment, logic, mix, ) from utils.convert import mamba2np, np2mamba # Channel Split if self.src_img.ndim == 3: b, g, r = [np2mamba(self.src_img[:, :, i]) for i in range(3)] elif self.src_img.ndim == 2: b, g, r = [np2mamba(self.src_img)] * 3 # We will perform a thick gradient on each color channel (contours in original # picture are more or less fuzzy) and we add all these gradients gradient = imageMb(r) tmp_1 = imageMb(r) gradient.reset() gradient(r, tmp_1, 2) add(tmp_1, gradient, gradient) gradient(g, tmp_1, 2) add(tmp_1, gradient, gradient) gradient(b, tmp_1, 2) add(tmp_1, gradient, gradient) # Then we invert the gradient image and we compute its quasi-distance quasi_dist = imageMb(gradient, 32) negate(gradient, gradient) quasiDistance(gradient, tmp_1, quasi_dist) if self.is_logging: self.logger.logging_img(tmp_1, "quasi_dist_gradient") self.logger.logging_img(quasi_dist, "quasi_dist") # The maxima of the quasi-distance are extracted and filtered (too close maxima, # less than 6 pixels apart, are merged) tmp_2 = imageMb(r) marker = imageMb(gradient, 1) copyBytePlane(quasi_dist, 0, tmp_1) subConst(tmp_1, 3, tmp_2) build(tmp_1, tmp_2) maxima(tmp_2, marker) # The marker-controlled watershed of the gradient is performed watershed = imageMb(gradient) label(marker, quasi_dist) negate(gradient, gradient) watershedSegment(gradient, quasi_dist) copyBytePlane(quasi_dist, 3, watershed) # The segmented binary and color image are stored logic(r, watershed, r, "sup") logic(g, watershed, g, "sup") logic(b, watershed, b, "sup") segmented_image = mix(r, g, b) if self.is_logging: self.logger.logging_img(segmented_image, "segmented_image") watershed = mamba2np(watershed) return watershed