def __call__(self, original_image):
        dic_sp_val = SPCSOperator.__call__(self, original_image)
        vals = np.array([])
        cache_blobs = False
        X_feature_t = np.array([])
        for elem in dic_sp_val.keys():
            if self._uc == "superpixel":
                image_sp = self._spp_method(original_image)
                blobs = sp.computeBlobs(image_sp)
                list_vals = []
#                if cache_blobs == False:
#                    blobs = sp.computeBlobs(dic_sp_val[elem])
#                    cache_blobs = True
                the_vals = sp.measMinVals(dic_sp_val[elem],  blobs)
                for lbl in blobs.keys():
                    list_vals +=[int(the_vals[lbl])]
                array_vals = np.array(list_vals)
                
            elif self._uc == "pixel":
                array_vals = np.ravel(dic_sp_val[elem].getNumArray())
            else:
                raise TypeError("uc (string) should be equal to superpixel or pixel")
            X_feature_t = uf.my_concatenation(X_feature_t, array_vals)
            
        return X_feature_t
Ejemplo n.º 2
0
def one_min_per_grid_cell(im_cells_lbl, blobs, im_labelled_minima, se):
    """
    Enables to select the best marker of each cell of the grid.
    
    Input:
    im_cells_lbl (UINT16): image of labelled cells.
    blobs: definition of each connected component
    im_labelled_minima (UINT16): image of markers candidates labelled with their ranking for some given criterium (e.g. surfacic extinction), i.e. "1" is the best.
    se: structuring element.
    
    """
    ## Selection of the marker with the best ranking in each cell: 
    imtmp = sp.Image(im_cells_lbl)
    sp.test(im_labelled_minima,  im_labelled_minima, 65335,  im_labelled_minima)
    minVals = sp.measMinVals(im_labelled_minima, blobs)
    sp.applyLookup(im_cells_lbl, minVals, imtmp)
    sp.compare(im_labelled_minima, "==", imtmp, im_labelled_minima, 0, im_labelled_minima)
    ## Selection of only one marker if several met the previous requirement in the same cell:
    sp.label(im_labelled_minima, imtmp, se)
    blobs2 = sp.computeBlobs(im_labelled_minima)
    maxVals = sp.measMaxVals(imtmp, blobs)
    sp.applyLookup(im_cells_lbl, maxVals, im_labelled_minima)
    sp.compare(imtmp, "==", im_labelled_minima, imtmp, 0, imtmp)
    sp.test(im_cells_lbl, imtmp, 0, im_labelled_minima) 
    
    return
def one_min_per_grid_cell(im_cells_lbl, blobs, im_labelled_minima, se):
    """
    Enables to select the best marker of each cell of the grid.
    
    Input:
    im_cells_lbl (UINT16): image of labelled cells.
    blobs: definition of each connected component
    im_labelled_minima (UINT32): image of markers candidates labelled with their ranking for some given criterium (e.g. surfacic extinction), i.e. "1" is the best.
    se: structuring element.
    
    """
    ## Selection of the marker with the best ranking in each cell: 
    imtmp = sp.Image_UINT32(im_cells_lbl.getSize()[0], im_cells_lbl.getSize()[1])
    num_max = np.int(np.power(2, 32)-1)
    sp.test(im_labelled_minima,  im_labelled_minima, num_max ,  im_labelled_minima)
    minVals = sp.measMinVals(im_labelled_minima, blobs)
    sp.applyLookup(im_cells_lbl, minVals, imtmp)
    sp.compare(im_labelled_minima, "==", imtmp, im_labelled_minima, 0, im_labelled_minima)
    ## Selection of only one marker if several met the previous requirement in the same cell:
    sp.label(im_labelled_minima, imtmp, se)
    blobs2 = sp.computeBlobs(im_labelled_minima)
    maxVals = sp.measMaxVals(imtmp, blobs)
    sp.applyLookup(im_cells_lbl, maxVals, im_labelled_minima)
    sp.compare(imtmp, "==", im_labelled_minima, imtmp, 0, imtmp)
    sp.test(im_cells_lbl, imtmp, 0, im_labelled_minima) 
    return
def apply_with_integrator(vals_map, spp_lab, integrator_code):
    """
    Permet de calculer la valeur intégrée de chaque superpixel
    et de créer l'image de superpixels associée.
    """
    im_out = sp.Image(spp_lab)
    blobs = sp.computeBlobs(spp_lab)
    myLUT =  sp.Map_UINT16_UINT16()
    if integrator_code == "mean" or integrator_code == "std":
        if integrator_code == "mean":
            choice = 0
        else:
            choice = 1
        for lbl in blobs.keys():
            myLUT[lbl] = int(vals_map[lbl][choice])
    else:
        for lbl in blobs.keys():
            myLUT[lbl] = int(vals_map[lbl])
    sp.applyLookup(spp_lab, myLUT, im_out)
    return im_out
    def __call__(self, original_image):
        """
        Output:
        dictionnaire contenant pour chaque canal choisi l'image de superpixels,
        avec une seule valeur par superpixel.
        """
        image_sp = self._spp_method(original_image)
        blobs = sp.computeBlobs(image_sp)
        dict_integrator = {
            "mean": sp.measMeanVals,
            "std": sp.measMeanVals,
            "mode": sp.measModeVals,
            "min": sp.measMinVals,
            "max": sp.measMaxVals,
            "vol": sp.measVolumes,
            }        
        ### 
        dic_im_res={}
        if original_image.getTypeAsString()=="RGB":
            if self._channels_list == None:
                self._channels_list = [0,1,2]
            image_slices = sp.Image()
            sp.splitChannels(original_image, image_slices)
            image_transformed = sp.Image(image_slices.getSlice(0))
            for i in self._channels_list:
                self._operator_functor(image_slices.getSlice(i), image_transformed)
                vals_map = dict_integrator[self._integrator](image_transformed, blobs)
                im_out = apply_with_integrator(vals_map, image_sp, self._integrator)
                dic_im_res[i] = im_out
        elif original_image.getTypeAsString()=="UINT8" or original_image.getTypeAsString()=="UINT16":
            self._channels_list = [0]
            image_transformed = sp.Image(original_image)
            self._operator_functor(original_image, image_transformed)
            vals_map = dict_integrator[self._integrator](image_transformed, blobs)
            im_out = apply_with_integrator(vals_map, image_sp, self._integrator)
            dic_im_res[0] =  im_out
        else:
            raise TypeError('pb')

        return dic_im_res
Ejemplo n.º 6
0
import smilPython as sp
import numpy as np
from numpy import linalg as la

# get image
imIn = sp.Image("https://smil.cmm.minesparis.psl.eu/images/tools.png")

# labelize input image
imThr = sp.Image(imIn)
sp.topHat(imIn, imThr, sp.hSE(20))
sp.threshold(imThr, imThr)
imLbl = sp.Image(imIn, "UINT16")
sp.label(imThr, imLbl)

# compute blobs and get their data
blobs   = sp.computeBlobs(imLbl)
central = True
inertia = sp.blobsInertiaMatrix(imIn, blobs, central)
barys   = sp.blobsBarycenter(imIn, blobs)

nshape = (2, 2)
if imIn.getDimension() == 3:
  nshape = (3, 3)

for k in inertia.keys():
    print("=" * 64)
    s = ""
    for v in barys[k]:
        s += " {:6.1f}".format(v)
    print("Blob label : {:3d} - Barycenter :{:}".format(k, s))
    # Smil returns inertia matrix as a vector. Reshape it.
    def __call__(self, original_image):
        """
        Plusieurs étapes:
        1) calculer les superpixels de l'image originale
        2) calculer le dictionnaire des imagettes de superpixels
        3) appliquer l'opérateur sur chacune de ces imagettes
        4) intégrer sur le superpixel pour n'avoir qu'une seule valeur (si besoin)
        --> inclus dans l'opérateur
        5) calculer la nouvelle image entière des superpixels,  où cette fois-ci la valeur de chaque SP n'est pas son label mais celle calculée en 4. 
        [Note: plusieurs images si plusieurs cannaux sélectionnés dans channels_list. Output: dictionnaire de ces images finales.]
        --> output plut^ot un dictionnaire car pas besoin des images.
        
        
        Ouput:
        dic_inter: un dictionnaire tel que:
                - chaque clé est un numéro de superpixel ex: i
                - chaque valeur est un dictionnaire associé au superpixel i, contenant pour chaque cannal j (clés) la valeur du feature. 
        """
        
        ### Etape 1: calcul des SP
        image_sp = self._spp_method(original_image)
        blobs = sp.computeBlobs(image_sp)
        barys = sp.measBarycenters(image_sp,  blobs)
        
        ### Etape 2 :  cacul du dictionnaire intermédiaire
        
        ### Inititation listes:
        if original_image.getTypeAsString()=="RGB":
            if self._channels_list == None:
                self._channels_list = [0,1,2]
        elif original_image.getTypeAsString()=="UINT8" or original_image.getTypeAsString()=="UINT16":
            self._channels_list = [0]
        else:
            raise TypeError('pb')
        dic_final = {}
        for i in self._channels_list:
            dic_final[i] = [] ## cette liste contiendra la valeur pour chaque superpixel
        ###
        dic_inter = {}
        nb_sp = len(blobs.keys()) ## nombre de superpixels
        bboxes_coord = sp.measBoundBoxes(image_sp) ## dictionnary of coordinates of the two points (top left, bottom right) of each bounding box.
        sim_sp = sp.Image(image_sp)## pour garder temporairement l'imagette du superpixel
        
        for elem in range(nb_sp):
            elem += 1
            sp.crop(image_sp, bboxes_coord[elem][0],  bboxes_coord[elem][1],  bboxes_coord[elem][2] - bboxes_coord[elem][0] + 1,  bboxes_coord[elem][3] - bboxes_coord[elem][1] + 1,  sim_sp)
            sp.subNoSat(sim_sp,  elem,  sim_sp)
            sp.test(sim_sp,  0, 65535, sim_sp) ## imagette masque du superpixel i
#            sim_sp.save('imagettes/bin_mask_'+str(elem)+'.png')
#            if sim_sp.getSize()[0] == 1 and sim_sp.getSize()[1] == 1 :
#                print "sup_" + str(elem) +"pos_" + str(bboxes_coord[elem][0]) + "_" + str(bboxes_coord[elem][1])
#                image_sp.save("essais/sup_" + str(elem) +"pos_" + str(bboxes_coord[elem][0]) + "_" + str(bboxes_coord[elem][1]) + "_SP.png")
#                original_image.save("essais/sup_" + str(elem) +"pos_" + str(bboxes_coord[elem][0]) + "_" + str(bboxes_coord[elem][1]) + "_orig.png")
            if original_image.getTypeAsString()=="RGB":
                image_slices = sp.Image()
                sp.splitChannels(original_image, image_slices)
                dic_orig_slices={}
                for i in self._channels_list:
                    sim_orig_slice= sp.Image(image_slices.getSlice(i))
                    sp.crop(image_slices.getSlice(i), bboxes_coord[elem][0],  bboxes_coord[elem][1],  bboxes_coord[elem][2] - bboxes_coord[elem][0] + 1,  bboxes_coord[elem][3] - bboxes_coord[elem][1] + 1,  sim_orig_slice)
                    sp.add(sim_orig_slice, 1, sim_orig_slice)
                    sp.test(sim_sp>0, sim_orig_slice, 0, sim_orig_slice)
                    dic_orig_slices[i] = sim_orig_slice
                    #sim_orig_slice.save('imagettes/orig_slice_'+str(i)+'_for_sup_'+str(elem)+'.png')
            elif original_image.getTypeAsString()=="UINT8" or original_image.getTypeAsString()=="UINT16":
                dic_orig_slices={}
                sim_orig_slice= sp.Image(original_image)
                sp.crop(original_image, bboxes_coord[elem][0],  bboxes_coord[elem][1],  bboxes_coord[elem][2] - bboxes_coord[elem][0] + 1,  bboxes_coord[elem][3] - bboxes_coord[elem][1] + 1,  sim_orig_slice)
                sp.add(sim_orig_slice, 1, sim_orig_slice)
                sp.test(sim_sp>0, sim_orig_slice, 0, sim_orig_slice)
                dic_orig_slices[0] = sim_orig_slice
            dic_inter[elem] = (sim_sp,  dic_orig_slices,  barys[elem])
            
            
        ### Etape 3: application de l'opérateur sur chaque imagette:
            dic_elem_val_={}
            for i in self._channels_list:
                dic_final[i] += [self._operator_functor(dic_orig_slices[i])]
        return dic_final
    def __call__(self, original_image):
        """
        Plusieurs étapes:
        1) calculer les superpixels de l'image originale
        2) calculer le dictionnaire des imagettes de superpixels
        3) appliquer l'opérateur sur chacune de ces imagettes
        4) intégrer sur le superpixel pour n'avoir qu'une seule valeur (si besoin)
        --> inclus dans l'opérateur
        5) calculer la nouvelle image entière des superpixels,  où cette fois-ci la valeur de chaque SP n'est pas son label mais celle calculée en 4. 
        [Note: plusieurs images si plusieurs cannaux sélectionnés dans channels_list. Output: dictionnaire de ces images finales.]
        --> output plut^ot un dictionnaire car pas besoin des images.
        
        
        Ouput:
        dic_inter: un dictionnaire tel que:
                - chaque clé est un numéro de superpixel ex: i
                - chaque valeur est un dictionnaire associé au superpixel i, contenant pour chaque cannal j (clés) la valeur du feature. 
        """
        
        ### Etape 1: calcul des SP
        image_sp = self._spp_method(original_image)
        blobs = sp.computeBlobs(image_sp)
        barys = sp.measBarycenters(image_sp,  blobs)
        
        ### Etape 2 :  cacul du dictionnaire intermédiaire
        
        ### Inititation listes:
        if original_image.getTypeAsString()=="RGB":
            if self._channels_list == None:
                self._channels_list = [0,1,2]
        elif original_image.getTypeAsString()=="UINT8" or original_image.getTypeAsString()=="UINT16":
            self._channels_list = [0]
        else:
            raise TypeError('pb')
        dic_final = {}
        #for i in self._channels_list:
        #    dic_final[i] = [] ## cette liste contiendra la valeur pour chaque superpixel
        ###
        dic_inter = {}
        nb_sp = len(blobs.keys()) ## nombre de superpixels
        bboxes_coord = sp.measBoundBoxes(image_sp) ## dictionnary of coordinates of the two points (top left, bottom right) of each bounding box.
        sim_sp = sp.Image(image_sp)## pour garder temporairement l'imagette du superpixel
        
        for elem in range(nb_sp):
            elem += 1
            sp.crop(image_sp, bboxes_coord[elem][0],  bboxes_coord[elem][1],  bboxes_coord[elem][2] - bboxes_coord[elem][0] + 1,  bboxes_coord[elem][3] - bboxes_coord[elem][1] + 1,  sim_sp)
            sp.subNoSat(sim_sp,  elem,  sim_sp)
            sp.test(sim_sp,  0, 65535, sim_sp) ## imagette masque du superpixel i
#            sim_sp.save('imagettes/bin_mask_'+str(elem)+'.png')
#            if sim_sp.getSize()[0] == 1 and sim_sp.getSize()[1] == 1 :
#                print "sup_" + str(elem) +"pos_" + str(bboxes_coord[elem][0]) + "_" + str(bboxes_coord[elem][1])
#                image_sp.save("essais/sup_" + str(elem) +"pos_" + str(bboxes_coord[elem][0]) + "_" + str(bboxes_coord[elem][1]) + "_SP.png")
#                original_image.save("essais/sup_" + str(elem) +"pos_" + str(bboxes_coord[elem][0]) + "_" + str(bboxes_coord[elem][1]) + "_orig.png")
            if original_image.getTypeAsString()=="RGB":
                image_slices = sp.Image()
                sp.splitChannels(original_image, image_slices)
                dic_orig_slices={}
                for i in self._channels_list:
                    sim_orig_slice= sp.Image(image_slices.getSlice(i))
                    sp.crop(image_slices.getSlice(i), bboxes_coord[elem][0],  bboxes_coord[elem][1],  bboxes_coord[elem][2] - bboxes_coord[elem][0] + 1,  bboxes_coord[elem][3] - bboxes_coord[elem][1] + 1,  sim_orig_slice)
                    sp.add(sim_orig_slice, 1, sim_orig_slice)
                    sp.test(sim_sp>0, sim_orig_slice, 0, sim_orig_slice)
                    dic_orig_slices[i] = sim_orig_slice
                    #sim_orig_slice.save('imagettes/orig_slice_'+str(i)+'_for_sup_'+str(elem)+'.png')
            elif original_image.getTypeAsString()=="UINT8" or original_image.getTypeAsString()=="UINT16":
                dic_orig_slices={}
                sim_orig_slice= sp.Image(original_image)
                sp.crop(original_image, bboxes_coord[elem][0],  bboxes_coord[elem][1],  bboxes_coord[elem][2] - bboxes_coord[elem][0] + 1,  bboxes_coord[elem][3] - bboxes_coord[elem][1] + 1,  sim_orig_slice)
                sp.add(sim_orig_slice, 1, sim_orig_slice)
                sp.test(sim_sp>0, sim_orig_slice, 0, sim_orig_slice)
                dic_orig_slices[0] = sim_orig_slice
            dic_inter[elem] = (sim_sp,  dic_orig_slices,  barys[elem])
            
            
        ### Etape 3: application de l'opérateur sur chaque imagette:
            dic_elem_val_={}
            
            for i in self._channels_list:
                # TODO: would be better to check a feature list with memory 
                feats_from_op = None
                for op in self._operator_functors:
                    # todo: remove _
                    feature_name = op.get_name()+"_"+self._spp_method.get_name()+"_for_channel_" + str(i)
                    if not feature_name in dic_final:
                        dic_final[feature_name] = []
                    dic_final[feature_name].append(op(dic_orig_slices[i], feats_from_op))
                    feats_from_op = op.feats

	# the list of all features (channel is hard coded in the feature names)
        features = self.get_name()

	# get a matrix nb_features x nb_superpixels with all feature values
        Xsp = np.array([dic_final[x] for x in features])

	if self._uc == "pixel":
	    # get a vector with a concatenation of all lines of the superpixel image (label image)
	    # the -1 comes from the fact that the label image starts with 1. 
            indices = np.ravel(image_sp.getNumArray()) - 1        
	    # we simply slice Xsp to get the final pixel features
            X = Xsp[:,indices]
        else:
	    # in case we want to classify superpixels, the initial matrix was fine. 
            X = Xsp

        return X 
Ejemplo n.º 9
0
import smilPython as sp

im = sp.Image("balls.png")
iml = sp.Image(im)

# this is just a binary image - no need to segment
sp.label(im, iml)
iml.showLabel()

# create blobs structure
blobs = sp.computeBlobs(iml)

# evaluate some measures :
areas = sp.blobsArea(blobs)
barys = sp.blobsBarycenter(im, blobs)

# print areas and barycenters of each region
print("{:3s} - {:>6s} - {:>13s}".format("ID", "Area", "Barycenter"))
for k in blobs.keys():
    bary = barys[k]
    print("{:3d} - {:6.0f} - {:6.0f} {:6.0f}".format(k, areas[k], bary[0],
                                                     bary[1]))
Ejemplo n.º 10
0
def demo_m_waterpixels(imin,  step,  d_weight, filter_ori):
    """ 
    Compute m-waterpixels, i.e. superpixels based on the watershed transformation. 
    Flooding starts form the best minimum of each cell of a regular grid. 
    The gradient used to be flooded is regularized using the distance function to these minima.
    Cells of the grid are chosen here to be squares.
    
    Input :
    imin (image UINT8): original image, to be segmented into superpixels
    step (UINT8) : grid step, i.e. distance between two cell centers of the grid
    d_weight (UINT8) : constant to be multiplied with function distance before addition to gradient image.
        If d_weight <=0, then only the gradient is taken into account.
    filter_ori (BOOLEAN) : do we filter the input image?

    Output:
    image (UINT16) : labelled superpixels
    image (UINT8) : distance weighted gradient function
    image (UINT16) : minima used in the computation
    """
    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------   
    # Connexity:
    basicse = sp.CrossSE()
    gridse = sp.SquSE()

    # Ori filtering
    if filter_ori is True:
        my_area_filtering(imin, step*step/16)

    # Gradient computation
    im_grad = my_gradient(imin, basicse,  True)

    ## Pool of working images:
    imwrk0 = sp.Image(im_grad)
    imwrk1 = sp.Image(im_grad,  "UINT16")
    imwrk2 = sp.Image(im_grad,  "UINT16")

    # Compute cell centers and cells
    size = imin.getSize()
    im_markers, im_cells = im_labelled_square_grid_points(size, step, step/6) 

    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------
    ## Choice of the markers : one per grid cell
    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------

    # Step 1 : Computation of the minima of the gradient
    im_minima = sp.Image(im_grad)
    sp.minima(im_grad, im_minima, basicse)
    #Step 2 : Imposing minimum distance between minima (= Removing minima candidates which fall on cell margins )
    sp.test(im_cells, im_minima, 0, imwrk0)
    sp.label(imwrk0, imwrk1, basicse)
    #Step 3 : Evaluation of the importance of minima ( = computation of their surfacic extinction)
    im_minima_val = sp.Image(imwrk1)
    sp.watershedExtinction( im_grad, imwrk1, im_minima_val, "a", basicse)
    # Step 4 : Taking back at value 2 the minima of null-volumic extinction 
    sp.test( imwrk0,  2,  0,  imwrk2)
    sp.test( im_minima_val,  im_minima_val, imwrk2, im_minima_val )
    # Step 5 : Coping with the potential absence of minimum in cells (= choosing the minimum value inside this cell as its marker if necessary)
    imwrk00=sp.Image(imwrk0)
    blobs = sp.computeBlobs(im_cells)
    sp.test(im_cells, im_grad, 0, imwrk00)
    minVals = sp.measMinVals(imwrk00, blobs)
    sp.applyLookup(im_cells, minVals, imwrk0)
    sp.test(imwrk00==imwrk0, 1, 0, imwrk1)
    maxVals = sp.measMaxVals(im_minima_val, blobs)
    sp.applyLookup(im_cells, maxVals, imwrk2)
    sp.test(imwrk2, im_minima_val, imwrk1, im_minima_val)
    # Step 6 : Selection of one marker per cell
    one_min_per_grid_cell(im_cells, blobs, im_minima_val, basicse)

    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------
    ## Spatial regularization of the gradient
    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------  
    
    #Step 1 : Computation of the distance function to the markers
    immask = sp.Image(im_markers, "UINT8")
    sp.test(im_minima_val, 0, 1, immask)
    imdist = sp.Image(immask, "UINT8")
    sp.dist(immask, imdist, gridse)
    #Step 2 : Adding the distance function to the gradient
    if d_weight > 0:
        weight = d_weight * float(2)/step
        sp.mul(imdist, weight, imdist)
        sp.add(imdist, im_grad, im_grad)

    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------
    ## Superpixel segmentation : watershed transformation, flooding from selected minima on the regularized gradient
    ##-----------------------------------------------------------------------------------------
    ##----------------------------------------------------------------------------------------- 
    sp.copy(im_minima_val, imwrk1)
    sp.label(imwrk1,  im_minima_val, basicse)
    imout = sp.Image(im_minima_val)
    sp.basins(im_grad, im_minima_val, imout, basicse) 
    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------  
    return imout,  im_grad,  im_minima_val
def demo_m_waterpixels(imin,  step,  d_weight, filter_ori):
    """ 
    Compute m-waterpixels, i.e. superpixels based on the watershed transformation. 
    Flooding starts form the best minimum of each cell of a regular grid. 
    The gradient used to be flooded is regularized using the distance function to these minima.
    Cells of the grid are chosen here to be squares.
    
    Input :
    imin (image UINT8): original image, to be segmented into superpixels
    step (UINT8) : grid step, i.e. distance between two cell centers of the grid
    d_weight (UINT8) : constant to be multiplied with function distance before addition to gradient image.
        If d_weight <=0, then only the gradient is taken into account.
    filter_ori (BOOLEAN) : do we filter the input image?

    Output:
    image (UINT16) : labelled superpixels
    image (UINT8) : distance weighted gradient function
    image (UINT16) : minima used in the computation
    """
    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------   
    # Connexity:
    basicse = sp.CrossSE()
    gridse = sp.SquSE()

    # Ori filtering
    if filter_ori is True:
        my_area_filtering(imin, step*step/16)

    # Gradient computation
    im_grad = my_gradient(imin, basicse,  True)

    ## Pool of working images:
    imwrk0 = sp.Image(im_grad)
    imwrk1 = sp.Image_UINT32(im_grad.getSize()[0],  im_grad.getSize()[1])
    #imwrk2 = sp.Image(im_grad,  "UINT16")
    imwrk2 = sp.Image_UINT32(im_grad.getSize()[0],  im_grad.getSize()[1])
    imwrk3 = sp.Image(im_grad,  "UINT16")
    imwrk4 = sp.Image(im_grad,  "UINT16")

    # Compute cell centers and cells
    size = imin.getSize()
    im_markers, im_cells = im_labelled_square_grid_points(size, step, step/6) 

    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------
    ## Choice of the markers : one per grid cell
    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------

    # Step 1 : Computation of the minima of the gradient
    im_minima = sp.Image(im_grad)
    sp.minima(im_grad, im_minima, basicse)
    #Step 2 : Imposing minimum distance between minima (= Removing minima candidates which fall on cell margins )
    sp.test(im_cells, im_minima, 0, imwrk0)
    sp.label(imwrk0, imwrk1, basicse)
    #Step 3 : Evaluation of the importance of minima ( = computation of their surfacic extinction)
    im_minima_val = sp.Image_UINT32(imwrk1)
    sp.watershedExtinction( im_grad, imwrk1, im_minima_val, "a", basicse)
    # Step 4 : Taking back at value 2 the minima of null-volumic extinction 
    sp.test( imwrk0,  2,  0,  imwrk2)
    sp.test( im_minima_val,  im_minima_val, imwrk2, im_minima_val )
    # Step 5 : Coping with the potential absence of minimum in cells (= choosing the minimum value inside this cell as its marker if necessary)
    imwrk00=sp.Image(imwrk0)
    blobs = sp.computeBlobs(im_cells)
    sp.test(im_cells, im_grad, 0, imwrk00)
    minVals = sp.measMinVals(imwrk00, blobs)
    sp.applyLookup(im_cells, minVals, imwrk0)
    sp.test(imwrk00==imwrk0, 1, 0, imwrk1)
    maxVals = sp.measMaxVals(im_minima_val, blobs)
    sp.applyLookup(im_cells, maxVals, imwrk2)
    sp.test(imwrk2, im_minima_val, imwrk1, im_minima_val)
    # Step 6 : Selection of one marker per cell
    one_min_per_grid_cell(im_cells, blobs, im_minima_val, basicse)

    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------
    ## Spatial regularization of the gradient
    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------  
    
    #Step 1 : Computation of the distance function to the markers
    immask = sp.Image(im_markers, "UINT8")
    sp.test(im_minima_val, 0, 1, immask)
    imdist = sp.Image(immask, "UINT8")
    sp.dist(immask, imdist, gridse)
    #Step 2 : Adding the distance function to the gradient
    if d_weight > 0:
        weight = d_weight * float(2)/step
        if im_grad.getTypeAsString()!=imdist.getTypeAsString():
            imdist2 = sp.Image(imdist,  "UINT16")
            sp.copy(imdist,  imdist2)
            sp.mul(imdist2, weight, imdist2)
            sp.add(imdist2, im_grad, im_grad)
        else:
            sp.mul(imdist, weight, imdist)
            sp.add(imdist, im_grad, im_grad)

    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------
    ## Superpixel segmentation : watershed transformation, flooding from selected minima on the regularized gradient
    ##-----------------------------------------------------------------------------------------
    ##----------------------------------------------------------------------------------------- 
#    sp.copy(im_minima_val, imwrk1)
#    sp.label(imwrk1,  im_minima_val, basicse)
#    imout = sp.Image(im_minima_val)
#    sp.basins(im_grad, im_minima_val, imout, basicse) 
    
    sp.copy(im_minima_val,  imwrk3)
    sp.label(imwrk3,  imwrk4,  basicse)
    imout = sp.Image(imwrk4)
    sp.basins(im_grad,  imwrk4,  imout,  basicse)
    ##-----------------------------------------------------------------------------------------
    ##-----------------------------------------------------------------------------------------  
    return imout,  im_grad,  im_minima_val