morhpolibJ jython implementation of Morphological Segmentation

jython
morpholibj
development
segmentation
Tags: #<Tag:0x00007fb87d6a57b0> #<Tag:0x00007fb87d6a55f8> #<Tag:0x00007fb87d6a5490> #<Tag:0x00007fb87d6a5238>

#1

Dear all,
I am implementing a workflow in a jython plugin.
At a certain point I would like to do a segmentation step using the morphological segmentation from the very nice morpholibJ suite.
I tested with the plugin and I’ve found a nice setting of parameters and I recorded that:

call(“inra.ijpb.plugins.MorphologicalSegmentation.setGradientRadius”, “2”);
call(“inra.ijpb.plugins.MorphologicalSegmentation.segment”, “tolerance=3”, “calculateDams=true”, “connectivity=6”);
call(“inra.ijpb.plugins.MorphologicalSegmentation.setDisplayFormat”, “Catchment basins”);
call(“inra.ijpb.plugins.MorphologicalSegmentation.createResultImage”);

for what I’ve understood from the javadocs all those operations are inside this API:
http://ijpb.github.io/MorphoLibJ/javadoc/inra/ijpb/plugins/MorphologicalSegmentation.html

this class is to use with GUI.

How can I do the same but without the MorpholibJ GUI?
I surfed a little the javadoc but I am not able to understand which is the algorithm used in the Morphological Segmentation plugin.

Thank you,
Emanuele


#2

Hello Emanuele!

I believe what you are looking for is exactly the scripting example in the MorphoLibJ’s site. There you are all the commands from the MorphoLibJ API to perform the exact same segmentation as in the Morphological Segmentation plugin.

Let me know if you have more questions!

ignacio


#3

Dear @iarganda,

I’ve read that it seems similar but not exactly the same, anyway I am just testing now and in next days and let you know and come back to the forum.

Thank a lot
Emanuele


#4

OK, I believe the following Beanshell code would do exactly the same as your macro calls :wink:

// @ImagePlus(label="Input image", description="Image to segment") imp
// @int(label="Gradient radius", description="Radius of the morphological gradient", value=2) radius
// @int(label="Tolerance", description="Local extrema dynamic", value=3) tolerance
// @String(label="Connectivity", description="Local connectivity", choices={"6","26"}) strConn
// @Boolean(label="Calculate dams", description="Flag to use dams in watershed",value=true) dams
// @OUTPUT ImagePlus resultImage
  
// ImageJ imports
import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
// MorphoLibJ imports
import inra.ijpb.binary.BinaryImages;
import inra.ijpb.morphology.MinimaAndMaxima3D;
import inra.ijpb.morphology.Morphology;
import inra.ijpb.morphology.Strel3D;
import inra.ijpb.watershed.Watershed;

// convert connectivity string to int
conn = Integer.parseInt( strConn );

// create structuring element (cube of radius 'radius')
strel = Strel3D.Shape.CUBE.fromRadius( radius );
// apply morphological gradient to input image
image = Morphology.gradient( imp.getImageStack(), strel );
// find regional minima on gradient image with dynamic value of 'tolerance' and 'conn'-connectivity
regionalMinima = MinimaAndMaxima3D.extendedMinima( image, tolerance, conn );
// impose minima on gradient image
imposedMinima = MinimaAndMaxima3D.imposeMinima( image, regionalMinima, conn );
// label minima using connected components (32-bit output)
labeledMinima = BinaryImages.componentsLabeling( regionalMinima, conn, 32 );
// apply marker-based watershed using the labeled minima on the minima-imposed 
// gradient image (the last value indicates the use of dams in the output)
resultStack = Watershed.computeWatershed( imposedMinima, labeledMinima, conn, dams );
   
// create image with watershed result
resultImage = new ImagePlus( "watershed", resultStack );
// assign right calibration
resultImage.setCalibration( imp.getCalibration() );

#5

This is the first result against my images:

  1. with the plugin GUI morphological Segmentation

  1. with the script with my script:
    #morph settings
    radius_gradient = 2
    tolerance = 3 
    connectivity = 8;    
    # morph algo    
    se_gradient = Strel.Shape.DISK.fromRadius(radius_gradient)
    image = Morphology.gradient( imp_i.getImageStack(), se_gradient );    
    regionalMinima = MinimaAndMaxima.extendedMinima( image.getProcessor(1), tolerance, connectivity );
    #impose minima on gradient image
    imposedMinima = MinimaAndMaxima.imposeMinima(image.getProcessor(1), regionalMinima, connectivity);
    #impose minima on gradient image
    labeledMinima = BinaryImages.componentsLabeling( regionalMinima, connectivity, 32 );
    # apply marker-based watershed using the labeled minima on the minima-imposed gradient image (the true value indicates the use of dams in the output)
    ip_segmented = Watershed.computeWatershed( imposedMinima, labeledMinima, connectivity, True );
    imp_segmented = ImagePlus(imp_i.getTitle()+"_MorphSegmented",ip_segmented)

So they seem more or less the same, but not exactly.
I think there is some additional steps or maybe the structural element for the gradient isn’t a DISK,
here I can find something about it but not completely descriptive (imho)


In anycase it’s not a big issue, I will tune the parameters to the script method and thank you for this beatiful library and your replies :wink:

have a nice day,
Emanuele


#6

You are completely right, the structuring element is a CUBE in MorphologicalSegmentation. Just change DISK by CUBE (or SQUARE in 2D) and it should work :slight_smile: