#@ ImagePlus Image #@ int (label="Delta (relative difference between threshold levels)", min=0, value=1) Delta #@ int (label="Minimum region area", min=0, value=500) MinArea #@ int (label="Maximum region area", min=0, value=2000) MaxArea #@ float (label="Maximum variation of stability for the region", min=0, value=0.5) MaxVar #@ String (label = "Identify bright/dark regions", choices={"Both (Default)", "Bright", "Dark"}, value = "Both (Default)") Method #@ Boolean (label = "Show bounding boxes as ROI", value=False) showBox #@ Boolean (Label = "Show free shapes as ROI", value=true) showHull ''' MSER : Maximally Stable Extremal Region Detector This detector performs successive thresholding with different thresholds : from bright to dark AND dark to bright by default (but one can optionnally choose only one direction too) The Bright to Dark option rather identify bright regions and vice-versa For each threshold it performs a connected component analysis Then it compare the evolution of a connected region over the level of thresholds : the more variation in the size of the region over the threshold levels levels, the less stable is the region. Finally the script retruns a set of stable regions that fits in the criterium of area and stability defined by the user It retruns this region as a cloud of point, as well as a bounding box for the region. In this macro, the bounding boxes is returned as a ROI stored into the roi manager A nice use can be to combine with the mask of the object using "AND" arithmetic so that we only retain the MSER region on the object ! TO DO : to prevent inclusion of regions within others, just paint all of them, the ones inside others are just overwritten/covered by the largest (like in the Knime worklow) ''' from org.bytedeco.javacpp.opencv_features2d import MSER from org.bytedeco.javacpp.opencv_core import RectVector, PointVectorVector #from org.bytedeco.javacpp.opencv_imgproc import convexHull, drawContours from ij import IJ, ImagePlus from ij.gui import Roi, PolygonRoi from ij.plugin.frame import RoiManager from ImageConverter import ImProcToMat from ijopencv.opencv import PointVectorPointRoiConverter # Initialise ROI manager RM = RoiManager() rm = RM.getRoiManager() rm.runCommand("Show All") # Define defaut paramters for detector - according to doc those are used only for color images so lets use the default only min_diversity = 1 max_evolution = 10 area_threshold = 1.01 min_margin = 0.003 edge_blur_size = 5 # Initialise detector detector = MSER.create(Delta,MinArea,MaxArea,MaxVar,min_diversity,max_evolution,area_threshold,min_margin,edge_blur_size) # Set unilateral threshold if selected if Method != "Both (Default)": print "Set to unidirectionnal thresholding" detector.setPass2Only(True) # Get ImageProcessor from ImagePlus ImProc = Image.getProcessor().duplicate() # Detect stable regions if Method == "Dark": # invert the image before doing the unidirectionnal detection print "Invert image before unidirectionnal thresholding" ImProc.invert() # Convert image to 8-bit (scaling) opencv matrix ImCV = ImProcToMat(ImProc, Bit=8) # Initialise result vectors Regions = PointVectorVector() # Regions contains n cloud of points (one/region). Each cloud of points is a PointVector, hence Regions is a Vector of PointVEctor BBox = RectVector() # detect MSER regions detector.detectRegions(ImCV, Regions, BBox) # Initialise ROI converter ROIconverter = PointVectorPointRoiConverter() # Report the number of detected BBoxes (rather report it in a result table ?) N = BBox.size() message = "Found {} stable regions".format(N) print message IJ.log(message) # Turn the detection into ROI for i in range(N): if showHull: # HULL PointVec = Regions.get(i) # Recover the Point cloud as a PointVector PointRoi = ROIconverter.convert(PointVec, float) # Convert to a IJ PointROI Hull = PointRoi.getConvexHull() # Do a convex Hull to prevent hollow shapes and reduce the number of points Hull_Roi = PolygonRoi(Hull, 2) # Convert the Polygon to a ROI (2 for type polygon) rm.addRoi(Hull_Roi) if showBox: # Bounding Boxes box = BBox.get(i) BoxRoi = Roi(box.x(), box.y(), box.width(), box.height()) rm.addRoi(BoxRoi) # Bring image back in focus IJ.selectWindow(Image.getTitle())