#@ File (label="Path to image") impath
#@ 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 = "Add regions to ROI manager", value=true) as_roi
#@ Boolean (Label = "Generate mask", value=true) make_mask
'''
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 Hull 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 (directly in opencv for better performance), the ones inside others are just overwritten/covered by the largest (like in the Knime worklow)
Will also fix the cases for which the convexHull do not work
However it will cut regions that might overlap

NB : image kept not with capital I to stick to the IMage input version for which variable image is a script parameters and therefore should be small
'''
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.process                             import ByteProcessor
from ij.plugin 								import LutLoader
from ij.plugin.frame						import RoiManager 
from ImageConverter							import ImProcToMat
from ijopencv.opencv 						import PointVectorPointRoiConverter
from java.lang.System 				     	import getProperty # to get the path to a LUT
import os

if as_roi:
	# Initialise ROI manager 
	RM = RoiManager() 
	rm = RM.getRoiManager() 

	 
# 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) 


# Open ImagePLus
image = IJ.openImage(impath.getPath())

# Get ImageProcessor from ImagePlus 
ImProc = image.getProcessor()
 
# Detect stable regions 
if method == "Dark": 
	ImProc = ImProc.duplicate() # detach fron the original image to prevent in place change
	# 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) 

if make_mask:
	# intialise a mask of same size than the image
	Width, Height = image.width, image.height
	Mask = ByteProcessor(Width, Height)


# Loop over regions
color = 1 # later used for mask to fill ROI
for i in range(N): 

	# HULL # not done in opencv because the input of the function should be a Mat while we have a PointVector
	
	# Recover the Point cloud as a PointVector
	PointVec = Regions.get(i) 							
	
	# Test to draw contour
	#drawContours(ImCV, PointVec, -1, 255, -1, 0, Mat(),0,Point(0,0))

	# Convert to a IJ PointROI  
	PointRoi = ROIconverter.convert(PointVec, float)    
	
	# Do a convex Hull to prevent hollow shapes and reduce the number of points. 
	Hull = PointRoi.getConvexHull()  # Returned object is a Java Polygon (not a ROI)
	
	# Fix whem Hull fails
	if not Hull:  # getConvexHull returns None sometime
		
		# Create a line connecting the points (allow to fit spline)
		LinePolygon = PointRoi.getContainedFloatPoints() 

		# Convert this line back to a ROI (to be able to apply the spline)
		LineRoi  = PolygonRoi(LinePolygon, 2) 
		LineRoi.fitSpline()

		# Apply then the convexHull on this spline (directly on the 
		Hull = LineRoi.getConvexHull()
	
	
	# Convert Polygon object back to a ROI (in both cases)
	HullRoi = PolygonRoi(Hull, 2)
	


	if as_roi:
		rm.addRoi(HullRoi)	
	
	'''
	if showBox: # Bounding box can be obtained by "Selection to bounding box"
		# Bounding Boxes
		box = BBox.get(i) 
		BoxRoi = Roi(box.x(), box.y(), box.width(), box.height()) 
		rm.addRoi(BoxRoi)  
	'''
	
	
	if make_mask:
				
		# Set fill color
		Mask.setColor(color)
		
		# Set current Roi on the image and fill
		#Mask.setRoi(roi)
		Mask.fill(HullRoi)
		
		# Update color for next ROI
		color+=1
		if color==256: color=1 # reset color counter to stay in a 8-bit range
		



# once looping over ROI is done
if make_mask:
	
	# Set LUT to Glasbey
	PathLut = os.path.join(getProperty('fiji.dir'),'luts','glasbey_on_dark.lut') 
	Lut     = LutLoader.openLut(PathLut)
	Mask.setLut(Lut)

	# Display mask
	ImMask = ImagePlus("Mask", Mask)
	ImMask.show()

	
if as_roi:
	# Bring image back in focus 
	image.show()
	rm.runCommand("Show All with labels") 