Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
 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))
Ejemplo n.º 5
0
 def _convertIntoVTKImage(self):
     # Converts the associated sequence into a VTK image
     # structure to be able to display it using the rendering
     # mechanisms of VTK
     W, H, L = self.im_ref().getSize()
     depth = self.im_ref().getDepth()
 
     if depth==8:
         # 8-bit 3D image
         self.planeLabel.config(text="")
         raw_data = self.im_ref().extractRaw()
     elif depth==32:
         # 32-bit 3D image
         im3D_8 = m3D.image3DMb(self.im_ref(), 8)
         if self.master.bplane==4:
             self.planeLabel.config(text="Plane : all")
             m3D.convert3D(self.im_ref(), im3D_8)
         else:
             self.planeLabel.config(text="Plane : %d" % (self.master.bplane))
             m3D.copyBytePlane3D(self.im_ref(), self.master.bplane, im3D_8)
         raw_data = im3D_8.extractRaw()
     else:
         # binary 3D image
         self.planeLabel.config(text="")
         im8 = mamba.imageMb(W, H, 8)
         raw_data = b""
         for im2D in self.im_ref():
             mamba.convert(im2D, im8)
             raw_data += im8.extractRaw()
     volume = m3D.computeVolume3D(self.im_ref())
     self.vtk_im.CopyImportVoidPointer(raw_data, len(raw_data))
         
     self.vtk_im.SetNumberOfScalarComponents(1)
     extent = self.vtk_im.GetDataExtent()
     self.vtk_im.SetDataExtent(extent[0], extent[0] + W - 1,
                               extent[2], extent[2] + H - 1,
                               extent[4], extent[4] + L - 1)
     self.vtk_im.SetWholeExtent(extent[0], extent[0] + W - 1,
                                extent[2], extent[2] + H - 1,
                                extent[4], extent[4] + L - 1)
     self.volLabel.config(text="Volume = %d" % (volume))
Ejemplo n.º 6
0
 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))
Ejemplo n.º 7
0
 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()
Ejemplo n.º 8
0
 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()
Ejemplo n.º 9
0
 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))
Ejemplo n.º 10
0
# Importing mamba
import mamba
import mambaDisplay

im = mamba.imageMb("wheel.png", 1)
im1 = mamba.imageMb(im, 1)
im2 = mamba.imageMb(im, 1)

# Opening of image
mamba.opening(im, im1, 3)
# Selection of the outside region
mamba.negate(im1, im2)
mamba.removeEdgeParticles(im2, im1)
mamba.diff(im2, im1, im2)
# Extracting the wheel teeth
mamba.logic(im, im2, im2, "inf")
# Cleaning the image
mamba.opening(im2, im2)
# Counting and marking each tooth
mamba.thinD(im2, im1)
nb_teeth = mamba.computeVolume(im1)
print("Number of teeth: %d" % (nb_teeth))
mamba.dilate(im1, im1, 3, mamba.SQUARE3X3)
im1.convert(8)
im8 = mamba.imageMb(im, 8)
mamba.convert(im, im8)
mamba.subConst(im8, 1, im8)
mamba.logic(im8, im1, im8, "sup")
name = mambaDisplay.tagOneColorPalette(255, (0,0,255))
im8.save('wheel_teeth.png', palette=mambaDisplay.getPalette(name))
Ejemplo n.º 11
0
def feretDiameterLabelling(imIn, imOut, direc):
    """
    The Feret diameter of each connected component of the binary image or the
    partition image 'imIn' is computed and its value labels the corresponding
    component. The labelled image is stored in the 32-bit image 'imOut'.
    If 'direc' is "vertical", the vertical Feret diameter is computed. If it is
    set to "horizontal", the corresponding diameter is used.    
    """
    
    imWrk1 = mamba.imageMb(imIn, 1)
    imWrk2 = mamba.imageMb(imIn, 32)
    imWrk3 = mamba.imageMb(imIn, 32)
    imWrk4 = mamba.imageMb(imIn, 32)
    
    imWrk1.fill(1)
    if direc == "horizontal":
        dir = 7    
    elif direc == "vertical":
        dir = 1
    else:
        mamba.raiseExceptionOnError(core.MB_ERR_BAD_DIRECTION)
        # The above statement generates an error ('direc' is not horizontal or 
        # vertical.
    # An horizontal or vertical distance function is generated.
    mamba.linearErode(imWrk1, imWrk1, dir, grid=mamba.SQUARE, edge=mamba.EMPTY)
    mamba.computeDistance(imWrk1, imOut, grid=mamba.SQUARE, edge=mamba.FILLED)
    mamba.addConst(imOut, 1, imOut)
    if imIn.getDepth() == 1:
	    # Each particle is valued with the distance.
        mamba.convertByMask(imIn, imWrk2, 0, mamba.computeMaxRange(imWrk3)[1])
        mamba.logic(imOut, imWrk2, imWrk3, "inf")
        # The valued image is preserved.
        mamba.copy(imWrk3, imWrk4)
        # Each component is labelled by the maximal coordinate.
        mamba.build(imWrk2, imWrk3)
        # Using the dual reconstruction, we label the particles with the
        # minimal ccordinate.
        mamba.negate(imWrk2, imWrk2)
        mamba.logic(imWrk2, imWrk4, imWrk4, "sup")
        mamba.dualBuild(imWrk2, imWrk4)
        # We subtract 1 because the selected coordinate must be outside the particle.
        mamba.subConst(imWrk4, 1, imWrk4)
        mamba.negate(imWrk2, imWrk2)
        mamba.logic(imWrk2, imWrk4, imWrk4, "inf")
        # Then, the subtraction gives the Feret diameter.
        mamba.sub(imWrk3, imWrk4, imOut)
    else:
        mamba.copy(imOut, imWrk3)
        if imIn.getDepth() == 32:
            mamba.copy(imIn, imWrk2)
        else:
            mamba.convert(imIn, imWrk2)
	# Using the cells builds (direct and dual to label the cells with the maximum
        # and minimum distance.
        mamba.cellsBuild(imWrk2, imWrk3)
        mamba.cellsBuild(imWrk2, imWrk3)
        mamba.negate(imOut, imOut)
        mamba.cellsBuild(imWrk2, imOut)
        mamba.negate(imOut, imOut)
        # Subtracting 1...
        mamba.subConst(imOut, 1, imOut)
        # ... and getting the final result.
        mamba.sub(imWrk3, imOut, imOut)
Ejemplo n.º 12
0
def feretDiameterLabelling(imIn, imOut, direc):
    """
    The Feret diameter of each connected component of the binary image or the
    partition image 'imIn' is computed and its value labels the corresponding
    component. The labelled image is stored in the 32-bit image 'imOut'.
    If 'direc' is "vertical", the vertical Feret diameter is computed. If it is
    set to "horizontal", the corresponding diameter is used.    
    """

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

    imWrk1.fill(1)
    if direc == "horizontal":
        dir = 7
    elif direc == "vertical":
        dir = 1
    else:
        mamba.raiseExceptionOnError(core.MB_ERR_BAD_DIRECTION)
        # The above statement generates an error ('direc' is not horizontal or
        # vertical.
    # An horizontal or vertical distance function is generated.
    mamba.linearErode(imWrk1, imWrk1, dir, grid=mamba.SQUARE, edge=mamba.EMPTY)
    mamba.computeDistance(imWrk1, imOut, grid=mamba.SQUARE, edge=mamba.FILLED)
    mamba.addConst(imOut, 1, imOut)
    if imIn.getDepth() == 1:
        # Each particle is valued with the distance.
        mamba.convertByMask(imIn, imWrk2, 0, mamba.computeMaxRange(imWrk3)[1])
        mamba.logic(imOut, imWrk2, imWrk3, "inf")
        # The valued image is preserved.
        mamba.copy(imWrk3, imWrk4)
        # Each component is labelled by the maximal coordinate.
        mamba.build(imWrk2, imWrk3)
        # Using the dual reconstruction, we label the particles with the
        # minimal ccordinate.
        mamba.negate(imWrk2, imWrk2)
        mamba.logic(imWrk2, imWrk4, imWrk4, "sup")
        mamba.dualBuild(imWrk2, imWrk4)
        # We subtract 1 because the selected coordinate must be outside the particle.
        mamba.subConst(imWrk4, 1, imWrk4)
        mamba.negate(imWrk2, imWrk2)
        mamba.logic(imWrk2, imWrk4, imWrk4, "inf")
        # Then, the subtraction gives the Feret diameter.
        mamba.sub(imWrk3, imWrk4, imOut)
    else:
        mamba.copy(imOut, imWrk3)
        if imIn.getDepth() == 32:
            mamba.copy(imIn, imWrk2)
        else:
            mamba.convert(imIn, imWrk2)

# Using the cells builds (direct and dual to label the cells with the maximum
# and minimum distance.
        mamba.cellsBuild(imWrk2, imWrk3)
        mamba.cellsBuild(imWrk2, imWrk3)
        mamba.negate(imOut, imOut)
        mamba.cellsBuild(imWrk2, imOut)
        mamba.negate(imOut, imOut)
        # Subtracting 1...
        mamba.subConst(imOut, 1, imOut)
        # ... and getting the final result.
        mamba.sub(imWrk3, imOut, imOut)
Ejemplo n.º 13
0
# Importing mamba
import mamba
import mambaDisplay

im = mamba.imageMb("wheel.png", 1)
im1 = mamba.imageMb(im, 1)
im2 = mamba.imageMb(im, 1)

# Opening of image
mamba.opening(im, im1, 3)
# Selection of the outside region
mamba.negate(im1, im2)
mamba.removeEdgeParticles(im2, im1)
mamba.diff(im2, im1, im2)
# Extracting the wheel teeth
mamba.logic(im, im2, im2, "inf")
# Cleaning the image
mamba.opening(im2, im2)
# Counting and marking each tooth
mamba.thinD(im2, im1)
nb_teeth = mamba.computeVolume(im1)
print("Number of teeth: %d" % (nb_teeth))
mamba.dilate(im1, im1, 3, mamba.SQUARE3X3)
im1.convert(8)
im8 = mamba.imageMb(im, 8)
mamba.convert(im, im8)
mamba.subConst(im8, 1, im8)
mamba.logic(im8, im1, im8, "sup")
name = mambaDisplay.tagOneColorPalette(255, (0, 0, 255))
im8.save('wheel_teeth.png', palette=mambaDisplay.getPalette(name))