def upperGeodesicDilate3D(imIn, imMask, imOut, n=1, se=m3D.CUBOCTAHEDRON1): """ Performs a upper geodesic dilation of 3D 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 (CUBOCTAHEDRON by default). Warning! 'imMask' and 'imOut' must be different. """ m3D.logic3D(imIn, imMask, imOut, "sup") if imIn.getDepth() == 1: for i in range(n): m3D.diff3D(imOut, imMask, imOut) m3D.dilate3D(imOut, imOut, se=se) m3D.logic3D(imMask, imOut, imOut, "sup") else: imWrk1 = m3D.image3DMb(imIn) imWrk2 = m3D.image3DMb(imIn, 1) for i in range(n): m3D.generateSupMask3D(imOut, imMask, imWrk2, True) m3D.convertByMask3D(imWrk2, imWrk1, 0, m3D.computeMaxRange3D(imWrk1)[1]) m3D.logic3D(imOut, imWrk1, imOut, "inf") m3D.dilate3D(imOut, imOut, se=se) m3D.logic3D(imOut, imMask, imOut, "sup")
def mosaic3D(imIn, imOut, imWts, grid=m3D.DEFAULT_GRID3D): """ Builds the mosaic 3D image of 'imIn' and puts the results into 'imOut'. The watershed line (pixel values set to 255) is stored in the greytone 3D 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 = m3D.image3DMb(imIn, 1) imWrk2 = m3D.image3DMb(imIn) m3D.copy3D(imIn, imWrk2) im_mark = m3D.image3DMb(imIn, 32) se = m3D.structuringElement3D(m3D.getDirections3D(grid), grid) m3D.gradient3D(imIn, imOut, se=se) m3D.minima3D(imOut, imWrk1, grid=grid) m3D.add3D(im_mark, imWrk1, im_mark) imWrk1.convert(8) m3D.build3D(imWrk1, imWrk2, grid=grid) m3D.add3D(im_mark, imWrk2, im_mark) m3D.watershedSegment3D(imOut, im_mark, grid=grid) m3D.copyBytePlane3D(im_mark, 3, imWts) m3D.subConst3D(im_mark, 1, im_mark) m3D.copyBytePlane3D(im_mark, 0, imOut)
def lowerGeodesicErode3D(imIn, imMask, imOut, n=1, se=m3D.CUBOCTAHEDRON1): """ Performs a lower geodesic erosion of 3D 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 (CUBOCTAHEDRON 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: m3D.diff3D(imMask, imIn, imOut) lowerGeodesicDilate3D(imOut, imMask, imOut, n, se=se) m3D.diff3D(imMask, imOut, imOut) else: imWrk1 = m3D.image3DMb(imIn) imWrk2 = m3D.image3DMb(imIn, 1) m3D.logic3D(imIn, imMask, imOut, "inf") for i in range(n): m3D.generateSupMask3D(imOut, imMask, imWrk2, False) m3D.convertByMask3D(imWrk2, imWrk1, 0, m3D.computeMaxRange3D(imWrk1)[1]) m3D.logic3D(imOut, imWrk1, imOut, "sup") m3D.erode3D(imOut, imOut, se=se) m3D.logic3D(imOut, imMask, imOut, "inf")
def mosaicGradient3D(imIn, imOut, grid=m3D.DEFAULT_GRID3D): """ Builds the mosaic-gradient 3D image of 'imIn' and puts the result in 'imOut'. The mosaic-gradient image is built by computing the differences of two mosaic images generated from 'imIn', the first one having its watershed lines valued by the suprema of the adjacent catchment basins values, the second one been valued by the infima. """ imWrk1 = m3D.image3DMb(imIn) imWrk2 = m3D.image3DMb(imIn) imWrk3 = m3D.image3DMb(imIn) imWrk4 = m3D.image3DMb(imIn) imWrk5 = m3D.image3DMb(imIn) mosaic3D(imIn, imWrk2, imWrk3, grid=grid) m3D.sub3D(imWrk2, imWrk3, imWrk1) m3D.logic3D(imWrk2, imWrk3, imWrk2, "sup") m3D.negate3D(imWrk2, imWrk2) se = m3D.structuringElement3D(m3D.getDirections3D(grid), grid) while m3D.computeVolume3D(imWrk3) != 0: m3D.dilate3D(imWrk1, imWrk4, 2, se=se) m3D.dilate3D(imWrk2, imWrk5, 2, se=se) m3D.logic3D(imWrk4, imWrk3, imWrk4, "inf") m3D.logic3D(imWrk5, imWrk3, imWrk5, "inf") m3D.logic3D(imWrk1, imWrk4, imWrk1, "sup") m3D.logic3D(imWrk2, imWrk5, imWrk2, "sup") m3D.erode3D(imWrk3, imWrk3, 2, se=se) m3D.negate3D(imWrk2, imWrk2) m3D.sub3D(imWrk1, imWrk2, imOut)
def _dualBuild3D_1(imMask, imInout, grid): # Build function for binary 3D images if imMask.getDepth()!=1: mamba.raiseExceptionOnError(core.MB_ERR_BAD_DEPTH) imMask_8 = m3D.image3DMb(imMask, 8) imInout_8= m3D.image3DMb(imInout, 8) m3D.convert3D(imMask, imMask_8) m3D.convert3D(imInout, imInout_8) err = core.MB3D_HierarDualBld(imMask_8.mb3DIm, imInout_8.mb3DIm, grid.getCValue()) mamba.raiseExceptionOnError(err) m3D.convert3D(imMask_8, imMask) m3D.convert3D(imInout_8, imInout)
def _dualBuild3D_1(imMask, imInout, grid): # Build function for binary 3D images if imMask.getDepth() != 1: mamba.raiseExceptionOnError(core.MB_ERR_BAD_DEPTH) imMask_8 = m3D.image3DMb(imMask, 8) imInout_8 = m3D.image3DMb(imInout, 8) m3D.convert3D(imMask, imMask_8) m3D.convert3D(imInout, imInout_8) err = core.MB3D_HierarDualBld(imMask_8.mb3DIm, imInout_8.mb3DIm, grid.getCValue()) mamba.raiseExceptionOnError(err) m3D.convert3D(imMask_8, imMask) m3D.convert3D(imInout_8, imInout)
def markerControlledWatershed3D(imIn, imMarkers, imOut, grid=m3D.DEFAULT_GRID3D): """ Marker-controlled watershed transform of greyscale or 32-bit 3D image 'imIn'. The binary 3D image 'imMarkers' contains the markers which control the flooding process. 'imOut' contains the valued watershed. """ im_mark = m3D.image3DMb(imIn, 32) imWrk = m3D.image3DMb(imIn) label3D(imMarkers, im_mark, grid=grid) watershedSegment3D(imIn, im_mark, grid=grid) m3D.copyBytePlane3D(im_mark, 3, imWrk) m3D.logic3D(imWrk, imIn, imOut, 'inf')
def mamba_ws(self, NEED_WL, res_type): imDist = image3DMb(*self.dist.shape, 32) fillImageWithArray_3D(self.dist, imDist) imMarkers = image3DMb(*self.markers.shape, 32) fillImageWithArray_3D(self.markers.astype(np.uint32), imMarkers) if NEED_WL: labels, res = decorator(watershedSegment3D, res_type)(imDist, imMarkers, grid=CUBIC) else: labels, res = decorator(basinSegment3D,res_type)(imDist, imMarkers, grid=CUBIC) tmp = image3DMb(*self.markers.shape, 8) copyBytePlane3D(tmp, 3, imMarkers) self.labels = getArrayFromImage_3D(imMarkers, self.size) return res
def linearClose3D(imIn, imOut, dir, n, grid=m3D.DEFAULT_GRID3D, edge=mamba.FILLED): """ Performs a closing by a segment of size 'n' in direction 'dir'. If 'edge' is set to 'EMPTY', the operation must be modified to remain extensive. """ imWrk = m3D.image3DMb(imIn) if edge == mamba.EMPTY: m3D.copy3D(imIn, imWrk) m3D.linearDilate3D(imIn, imOut, dir, n, grid=grid) m3D.linearErode3D(imOut, imOut, m3D.transposeDirection3D(dir, grid=grid), n, edge=edge, grid=grid) if edge == mamba.EMPTY: m3D.logic3D(imOut, imWrk, imOut, "sup")
def hitOrMiss3D(imIn, imOut, dse, edge=mamba.EMPTY): """ Performs a binary Hit-or-miss operation on 3D image 'imIn' using the doubleStructuringElement3D 'dse'. Result is put in 'imOut'. WARNING! 'imIn' and 'imOut' must be different images. """ (width, height, length) = imIn.getSize() depth = imIn.getDepth() if depth != 1: mamba.raiseExceptionOnError(core.MB_ERR_BAD_DEPTH) if length != len(imOut): mamba.raiseExceptionOnError(core.MB_ERR_BAD_SIZE) zext = dse.grid.getZExtension() imWrk = m3D.image3DMb(width, height, length + zext * 2, depth) # Border handling imWrk.reset() m3D.copy3D(imIn, imWrk, firstPlaneOut=1) if edge == mamba.FILLED: m3D.negate3D(imWrk, imWrk) for i in range(zext): imWrk[i].reset() imWrk[length + zext * 2 - 1 - i].reset() dse = dse.flip() # Central point if dse.se1.hasZero(): m3D.copy3D(imWrk, imOut, firstPlaneIn=1) else: if dse.se0.hasZero(): for i in range(length): mamba.negate(imWrk[i + 1], imOut[i]) else: imOut.fill(1) # Other directions dirs = m3D.getDirections3D(dse.getGrid(), True) dirs0 = dse.se0.getDirections() dirs1 = dse.se1.getDirections() grid2D = dse.getGrid().get2DGrid() for d in dirs: if d in dirs1: for i in range(length): (planeOffset, dc) = dse.getGrid().convertFromDir(d, i) mamba.infNeighbor(imWrk[i + 1 + planeOffset], imOut[i], 1 << dc, grid=grid2D, edge=edge) elif d in dirs0: for i in range(length): (planeOffset, dc) = dse.getGrid().convertFromDir(d, i) mamba.diffNeighbor(imWrk[i + 1 + planeOffset], imOut[i], 1 << dc, grid=grid2D, edge=edge)
def autoMedian3D(imIn, imOut, n, se=m3D.CUBOCTAHEDRON1): """ Morphological automedian filter performed with alternate sequential filters. """ oc_im = m3D.image3DMb(imIn) co_im = m3D.image3DMb(imIn) imWrk = m3D.image3DMb(imIn) alternateFilter3D(imIn, oc_im, n, True, se=se) alternateFilter3D(imIn, co_im, n, False, se=se) m3D.copy3D(imIn, imOut) m3D.copy3D(oc_im, imWrk) m3D.logic3D(co_im, imWrk, imWrk, "sup") m3D.logic3D(imWrk, imOut, imOut, "inf") m3D.copy3D(oc_im, imWrk) m3D.logic3D(co_im, imWrk, imWrk, "inf") m3D.logic3D(imWrk, imOut, imOut, "sup")
def buildClose3D(imIn, imOut, n=1, se=m3D.CUBOCTAHEDRON1): """ Performs a closing by dual reconstruction operation on 3D image 'imIn' and puts the result in 'imOut'. 'n' controls the size of the closing. """ imWrk = m3D.image3DMb(imIn) m3D.copy3D(imIn, imWrk) m3D.dilate3D(imIn, imOut, n, se=se) m3D.dualBuild3D(imWrk, imOut, grid=se.getGrid())
def buildOpen3D(imIn, imOut, n=1, se=m3D.CUBOCTAHEDRON1): """ Performs an opening by reconstruction operation on 3D image 'imIn' and puts the result in 'imOut'. 'n' controls the size of the opening. """ imWrk = m3D.image3DMb(imIn) m3D.copy3D(imIn, imWrk) m3D.erode3D(imIn, imOut, n, se=se) m3D.build3D(imWrk, imOut, grid=se.getGrid())
def valuedWatershed3D(imIn, imOut, grid=m3D.DEFAULT_GRID3D): """ Returns the valued watershed of greyscale or 32-bit 3D image 'imIn' into greyscale 3D image 'imOut'. Each pixel of the watershed lines is given its corresponding value in initial image 'imIn'. """ im_min = m3D.image3DMb(imIn, 1) m3D.minima3D(imIn, im_min, grid=grid) markerControlledWatershed3D(imIn, im_min, imOut, grid=grid)
def thick3D(imIn, imOut, dse): """ Elementary thickening operator with 'dse' double structuring element. 'imIn' and 'imOut' are binary 3D images. The edge is always EMPTY (as for mamba.hitOrMiss). """ imWrk = m3D.image3DMb(imIn) hitOrMiss3D(imIn, imWrk, dse) m3D.logic3D(imIn, imWrk, imOut, "sup")
def thin3D(imIn, imOut, dse, edge=mamba.EMPTY): """ Elementary thinning operator with 'dse' double structuring element. 'imIn' and 'imOut' are binary 3D images. 'edge' is set to EMPTY by default. """ imWrk = m3D.image3DMb(imIn) hitOrMiss3D(imIn, imWrk, dse, edge=edge) m3D.diff3D(imIn, imWrk, imOut)
def fastSKIZ3D(imIn, imOut, grid=m3D.DEFAULT_GRID3D): """ Fast skeleton by zones of influence of binary 3D image 'imIn'. Result is put in binary 3D image 'imOut'. The transformation is faster as it uses the watershed transform by hierarchical queues. """ imWrk = m3D.image3DMb(imIn, 8) m3D.convertByMask3D(imIn, imWrk, 1, 0) markerControlledWatershed3D(imWrk, imIn, imWrk, grid=grid) m3D.threshold3D(imWrk, imOut, 0, 0)
def blackTopHat3D(imIn, imOut, n, se=m3D.CUBOCTAHEDRON1): """ Performs a black Top Hat operation on 'imIn' and puts the result in 'imOut'. This operator extracts from 'imIn' the dark objects thinner than 2*'n'+1. The structuring element used is defined by 'se' ('CUBOCTAHEDRON1' by default). """ imWrk = m3D.image3DMb(imIn) m3D.closing3D(imIn, imWrk, n, se=se) m3D.sub3D(imWrk, imIn, imOut)
def supBlackTopHat3D(imIn, imOut, n, grid=m3D.DEFAULT_GRID3D): """ Performs a black Top Hat operation with the infimum of directional openings on 'imIn' and puts the result in 'imOut'. This operator partly extracts from 'imIn' the dark objects whose extension in at least one direction of 'grid' is smaller than 'n'. """ imWrk = m3D.image3DMb(imIn) m3D.infClose3D(imIn, imWrk, n, grid=grid) m3D.sub3D(imWrk, imIn, imOut)
def simpleLevelling3D(imIn, imMask, imOut, grid=m3D.DEFAULT_GRID3D): """ Performs a simple levelling of 3D 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 = m3D.image3DMb(imIn) imWrk2 = m3D.image3DMb(imIn) mask_im = m3D.image3DMb(imIn, 1) m3D.logic3D(imIn, imMask, imWrk1, "inf") m3D.build3D(imIn, imWrk1, grid=grid) m3D.logic3D(imIn, imMask, imWrk2, "sup") m3D.dualBuild3D(imIn, imWrk2, grid=grid) m3D.generateSupMask3D(imIn, imMask, mask_im, False) m3D.convertByMask3D(mask_im, imOut, 0, m3D.computeMaxRange3D(imIn)[1]) m3D.logic3D(imOut, imWrk1, imWrk1, "inf") m3D.negate3D(imOut, imOut) m3D.logic3D(imOut, imWrk2, imOut, "inf") m3D.logic3D(imWrk1, imOut, imOut, "sup")
def gradient3D(imIn, imOut, n=1, se=m3D.CUBOCTAHEDRON1): """ Computes the morphological gradient of 3D image 'imIn' and puts the result in 'imOut'. The thickness can be controlled using parameter 'n' (1 by default). The structuring element used by the erosion and dilation is defined by 'se' (CUBOCTAHEDRON1 by default). """ imWrk = m3D.image3DMb(imIn) m3D.erode3D(imIn, imWrk, n, se=se) m3D.dilate3D(imIn, imOut, n, se=se) m3D.sub3D(imOut, imWrk, imOut)
def supOpen3D(imIn, imOut, n, grid=m3D.DEFAULT_GRID3D): """ 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 = m3D.image3DMb(imIn) imWrk2 = m3D.image3DMb(imIn) imWrk1.reset() # Default grid is a proxy for an actual grid if grid == m3D.CUBIC: # First neighbors located at a sqrt(2) distance from the center size = int((1.4142 * n + 1) / 2) for d in [2, 4, 10, 12, 14, 16]: linearOpen3D(imIn, imWrk2, d, size, grid, edge=mamba.EMPTY) m3D.logic3D(imWrk1, imWrk2, imWrk1, "sup") # First neighbors located at a sqrt(3) distance from the center size = int((1.7320 * n + 1) / 2) for d in [11, 13, 15, 17]: linearOpen3D(imIn, imWrk2, d, size, grid, edge=mamba.EMPTY) m3D.logic3D(imWrk1, imWrk2, imWrk1, "sup") # Finally neighbors located at a 1 distance from the center size = n for d in [1, 3, 9]: linearOpen3D(imIn, imWrk2, d, size, grid, edge=mamba.EMPTY) m3D.logic3D(imWrk1, imWrk2, imWrk1, "sup") elif grid == m3D.FACE_CENTER_CUBIC: for d in [1, 3, 5, 7, 8, 9]: linearOpen3D(imIn, imWrk2, d, n, grid, edge=mamba.EMPTY) m3D.logic3D(imWrk1, imWrk2, imWrk1, "sup") else: mamba.raiseExceptionOnError(core.MB_ERR_BAD_PARAMETER) m3D.copy3D(imWrk1, imOut)
def infClose3D(imIn, imOut, n, grid=m3D.DEFAULT_GRID3D): """ 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 = m3D.image3DMb(imIn) imWrk2 = m3D.image3DMb(imIn) imWrk1.fill(m3D.computeMaxRange3D(imIn)[1]) # Default grid is a proxy for an actual grid if grid == m3D.CUBIC: # First neighbors located at a sqrt(2) distance from the center size = int((1.4142 * n + 1) / 2) for d in [2, 4, 10, 12, 14, 16]: linearClose3D(imIn, imWrk2, d, size, grid) m3D.logic3D(imWrk1, imWrk2, imWrk1, "inf") # First neighbors located at a sqrt(3) distance from the center size = int((1.7320 * n + 1) / 2) for d in [11, 13, 15, 17]: linearClose3D(imIn, imWrk2, d, size, grid) m3D.logic3D(imWrk1, imWrk2, imWrk1, "inf") # Finally neighbors located at a 1 distance from the center size = n for d in [1, 3, 9]: linearClose3D(imIn, imWrk2, d, size, grid) m3D.logic3D(imWrk1, imWrk2, imWrk1, "inf") elif grid == m3D.FACE_CENTER_CUBIC: for d in [1, 3, 5, 7, 8, 9]: linearClose3D(imIn, imWrk2, d, n, grid) m3D.logic3D(imWrk1, imWrk2, imWrk1, "inf") else: mamba.raiseExceptionOnError(core.MB_ERR_BAD_PARAMETER) m3D.copy3D(imWrk1, imOut)
def hitOrMiss3D(imIn, imOut, dse, edge=mamba.EMPTY): """ Performs a binary Hit-or-miss operation on 3D image 'imIn' using the doubleStructuringElement3D 'dse'. Result is put in 'imOut'. WARNING! 'imIn' and 'imOut' must be different images. """ (width,height,length) = imIn.getSize() depth = imIn.getDepth() if depth!=1: mamba.raiseExceptionOnError(core.MB_ERR_BAD_DEPTH) if length!=len(imOut): mamba.raiseExceptionOnError(core.MB_ERR_BAD_SIZE) zext = dse.grid.getZExtension() imWrk = m3D.image3DMb(width, height, length+zext*2, depth) # Border handling imWrk.reset() m3D.copy3D(imIn, imWrk, firstPlaneOut=1) if edge==mamba.FILLED: m3D.negate3D(imWrk, imWrk) for i in range(zext): imWrk[i].reset() imWrk[length+zext*2-1-i].reset() dse = dse.flip() # Central point if dse.se1.hasZero(): m3D.copy3D(imWrk, imOut, firstPlaneIn=1) else: if dse.se0.hasZero(): for i in range(length): mamba.negate(imWrk[i+1], imOut[i]) else: imOut.fill(1) # Other directions dirs = m3D.getDirections3D(dse.getGrid(), True) dirs0 = dse.se0.getDirections() dirs1 = dse.se1.getDirections() grid2D = dse.getGrid().get2DGrid() for d in dirs: if d in dirs1: for i in range(length): (planeOffset, dc) = dse.getGrid().convertFromDir(d,i) mamba.infNeighbor(imWrk[i+1+planeOffset], imOut[i], 1<<dc, grid=grid2D, edge=edge) elif d in dirs0: for i in range(length): (planeOffset, dc) = dse.getGrid().convertFromDir(d,i) mamba.diffNeighbor(imWrk[i+1+planeOffset], imOut[i], 1<<dc, grid=grid2D, edge=edge)
def minPartialBuild3D(imIn, imMask, imOut, grid=m3D.DEFAULT_GRID3D): """ Performs the partial reconstruction of 'imIn' with its minima which are contained in the binary mask 'imMask'. The result is put in 'imOut'. 'imIn' and 'imOut' must be different and greyscale images. """ imWrk = m3D.image3DMb(imIn, 1) minima3D(imIn, imWrk, 1, grid=grid) m3D.logic3D(imMask, imWrk, imWrk, "inf") m3D.convertByMask3D(imWrk, imOut, mamba.computeMaxRange(imIn[0])[1], 0) m3D.logic3D(imIn, imOut, imOut, "sup") m3D.dualBuild3D(imIn, imOut)
def closeHoles3D(imIn, imOut, grid=m3D.DEFAULT_GRID3D): """ Close holes in 3D image 'imIn' and puts the result in 'imOut'. This operator works on binary and greytone images. In this case, however, it should be used cautiously. """ imWrk = m3D.image3DMb(imIn) m3D.negate3D(imIn, imIn) m3D.drawEdge3D(imWrk) m3D.logic3D(imIn, imWrk, imWrk, "inf") build3D(imIn, imWrk, grid=grid) m3D.negate3D(imIn, imIn) m3D.negate3D(imWrk, imOut)
def regularisedGradient3D(imIn, imOut, n, grid=m3D.DEFAULT_GRID3D): """ Computes the regularized gradient of 3D image 'imIn' of size 'n'. The result is put in 'imOut'. A regularized gradient of size 'n' extracts in the 3D image contours thinner than 'n' while avoiding false detections. This operation is only valid for omnidirectional structuring elements. """ imWrk = m3D.image3DMb(imIn) se = m3D.structuringElement3D(m3D.getDirections3D(grid), grid) gradient3D(imIn, imWrk, n, se=se) whiteTopHat3D(imWrk, imWrk, n, se=se) m3D.erode3D(imWrk, imOut, n-1, se=se)
def removeEdgeParticles3D(imIn, imOut, grid=m3D.DEFAULT_GRID3D): """ Removes particles (connected components) touching the edge in 3D image 'imIn'. The resulting image is put in image 'imOut'. Although this operator may be used with greytone images, it should be considered with caution. """ imWrk = m3D.image3DMb(imIn) se = m3D.structuringElement3D(m3D.getDirections3D(grid), grid) m3D.dilate3D(imWrk, imWrk, se=se, edge=mamba.FILLED) m3D.logic3D(imIn, imWrk, imWrk, "inf") build3D(imIn, imWrk, grid=grid) m3D.diff3D(imIn, imWrk, imOut)
def maxima3D(imIn, imOut, h=1, grid=m3D.DEFAULT_GRID3D): """ Computes the maxima of 'imIn' using a build operation and puts the result in 'imOut'. 'h' can be used to define the maxima height. Grid used by the build operation can be specified by 'grid'. Only works with 8-bit or 32-bit as input. 'imOut' must be binary. """ imWrk = m3D.image3DMb(imIn) m3D.subConst3D(imIn, h, imWrk) m3D.build3D(imIn, imWrk, grid=grid) m3D.sub3D(imIn, imWrk, imWrk) m3D.threshold3D(imWrk, imOut, 1, mamba.computeMaxRange(imIn[0])[1])
def dilateByCylinder3D(imInOut, height, section): """ Dilates 3D image 'imInOut' using a cylinder with an hexagonal section of size 2x'section' and a height of 2x'height'. The image is modified by this function. The edge is always set to EMPTY. """ l = len(imInOut) for im in imInOut: mamba.dilate(im, im, section, se=mamba.HEXAGON) provIm3D = m3D.image3DMb(imInOut) for i in range(l): mamba.copy(imInOut[i], provIm3D[i]) for j in range(max(0,i-height), min(l,i+height+1)): mamba.logic(provIm3D[i], imInOut[j], provIm3D[i], "sup") m3D.copy3D(provIm3D, imInOut)
def deepMinima3D(imIn, imOut, h, grid=m3D.DEFAULT_GRID3D): """ Computes the minima of the dual reconstruction of image 'imIn' by imIn + h and puts the result in 'imOut'. Grid used by the dual build operation can be specified by 'grid'. Only works with 8-bit or 32-bit images as input. 'imOut' must be binary. """ imWrk = m3D.image3DMb(imIn) if imIn.getDepth() == 8: m3D.addConst3D(imIn, h, imWrk) else: m3D.ceilingAddConst3D(imIn, h, imWrk) m3D.dualBuild3D(imIn, imWrk, grid=grid) minima3D(imWrk, imOut, 1, grid=grid)
def closing3D(imIn, imOut, n=1, se=m3D.CUBOCTAHEDRON1, edge=mamba.FILLED): """ Performs a closing operation on 3D image 'imIn' and puts the result in 'imOut'. 'n' controls the size of the closing and 'se' the structuring element used. The default edge is set to 'FILLED'. If 'edge' is set to 'EMPTY', the operation is slightly modified to avoid errors (non extensivity). """ imWrk = m3D.image3DMb(imIn) if edge == mamba.EMPTY: m3D.copy3D(imIn, imWrk) m3D.dilate3D(imIn, imOut, n, se=se) m3D.erode3D(imOut, imOut, n, se=se.transpose(), edge=edge) if edge == mamba.EMPTY: m3D.logic3D(imOut, imWrk, imOut, "sup")
def highMaxima3D(imIn, imOut, h, grid=m3D.DEFAULT_GRID3D): """ Computes the maxima of the reconstruction of image 'imIn' by imIn - h and puts the result in 'imOut'. Grid used by the build operation can be specified by 'grid'. Only works with 8-bit or 32-bit images as input. 'imOut' must be binary. """ imWrk = m3D.image3DMb(imIn) if imIn.getDepth() == 8: m3D.subConst3D(imIn, h, imWrk) else: m3D.floorSubConst3D(imIn, h, imWrk) m3D.build3D(imIn, imWrk, grid=grid) m3D.maxima3D(imWrk, imOut, 1, grid=grid)