#@ File[]    (Label="Templates", style="file") template_files   
#@ File[]    (label="Image for which to look for the template") image_files 
#@ Boolean   (Label="Flip template vertically") flipv 
#@ Boolean   (Label="Flip template horizontally") fliph 
#@ String    (Label="Additional rotation angles separated by ," ,required=False) angles 
#@ String    (Label="Matching method",choices={"Normalised Square Difference", "Normalised cross-correlation", "Normalised 0-mean cross-correlation"}, value="Normalised 0-mean cross-correlation") method 
#@ int       (Label="Expected number of templates", min=1) n_hit 
#@ String    (visibility="MESSAGE", value="The parameters below are used only if the template is flipped/rotated and/or more than 1 template are expected in the image") doc 
#@ Float     (Label="Score Threshold (0-1)", min=0, max=1, value=0.5, stepSize=0.1) score_threshold 
#@ Float     (Label="Min height for maxima detection relative to neighbourhood (0-1, decrease to get more hits)", min=0, max=1, value=0.1, stepSize=0.1) tolerance 
#@ Float     (Label="Maximal overlap between Bounding boxes (0-1)",min=0, max=1, value=0.4, stepSize=0.1) max_overlap 
#@ String    (visibility="MESSAGE", value="Output") out 
#@ Boolean   (Label="Open images (as stack ie images must have identical dimensions)") show_images 
#@ Boolean   (Label="Add ROI to ROI Manager") show_roi 
#@ Boolean   (Label="Show result table") show_table 
'''
previous field : Boolean   (Label="Display correlation map(s)") show_map 
 
Requires ImageJ 1.52i to have the possibility to fill the background while rotating for 16-bit images 
 
FIJI macro  to do template matching 
input : 
- template_files : list of template path 
- image_files    : list of image path for which we want to search a template 
ie this macro search for N templates (with eventual flipped/rotated version) into L target images. 
 
 
First of all, additionnal versions of the template are generated (flip+rotation) 
For the resulting list of templates the search is carried out and results in a list of correlation maps 
 
Minima/maxima in the correlation map are detected, followed by Non-Maxima Supression in case of multiple correlation map/templates 
 
 
## TO DO :  
- order of the column in result table 
 
- use steerable tempalte matching see steerable detector BIG Lausanne 
 
 
## NB :  
- If open_images is true, the images must have the same dimensions 
 
- The multifile input is not yet macro recordable. An alternative is to use a folder input and to process the content of the folder (but not as flexible) 
 
- (currently no search ROi so not applicable) Delete the previous ROI for every new Run otherwise 1st ROI is used to limit the search 
 
- Method limited to normalised method to have correlation map in range 0-1 : easier to apply a treshold.  
Otherwise normalising relative to maxima of each correlation map is not good since this result in having the global maxima to always be one,  
eventhough its correlation value was not one. 
Another possibility would be to have an absolute threshold (realtive to the correlation score) and a relative threshold (relative to the maxima of this particular map)   
 
The multifile input is not yet macro recordable. An alternative is to use a folder input and to process the content of the folder (but not as flexible) 
'''
from ij import IJ 
 
## Home-Made module 
#from ROIdetection.SearchRoi			import getSearchRoi 
from ROIdetection.MatchTemplate_Module    import getHit_Template, CornerToCenter 
from ROIdetection.NonMaximaSupression_Py2 import NMS 
 
if show_images:  
	from ij import ImagePlus, ImageStack 
	Stack_Image     = ImageStack() 
	Stack_Image_ImP = ImagePlus() 
 
if show_roi: 
	from ij.plugin.frame 	import RoiManager 
	from ij.gui 			import Roi 
	RM = RoiManager() 
	rm = RM.getInstance()  
	 
if show_table: 
	from ij.measure import ResultsTable 
	from utils 		import AddToTable 
	Table = ResultsTable().getResultsTable() # allows to append to an existing table 
 
# Convert method string to the opencv corresponding index 
Dico_Method  = {"Square difference":0,"Normalised Square Difference":1,"Cross-Correlation":2,"Normalised cross-correlation":3,"0-mean cross-correlation":4,"Normalised 0-mean cross-correlation":5} 
Method       =  Dico_Method[method] 
	 
# Initialise list of templates as ImageProcessor (rather than opening them for every image iteration) 
List_Template = [ IJ.openImage( templ_file.getPath() ).getProcessor() for templ_file in template_files ]  
 
#nROI = 0 
## Loop over templates for template matching and maxima detection 
for i, im_file in enumerate(image_files): 
	 
	# Get the ImageProcessor for the current image 
	PathIm = im_file.getPath() 
	ImPlus = IJ.openImage(PathIm) 
	ImName = ImPlus.getTitle() 
	ImProc = ImPlus.getProcessor() 
	 
	# Initialise list before looping over templates 
	Hits_BeforeNMS = [] 
	 
	## Loop over template for matching against current image 
	for TemplateProc in List_Template: 
			 
		# Get hits for the current template (and his flipped and/or rotated versions) 
		List_Hit = getHit_Template(TemplateProc, ImProc, flipv, fliph, angles, Method, n_hit, score_threshold, tolerance) 
		 
		# Store the hits 
		Hits_BeforeNMS.extend(List_Hit) 
	 
	 
	 
	### NMS inter templates 
	print "\n-- Hits before NMS --\n", 
	for hit in Hits_BeforeNMS: print hit 
 
	# InterHit NMS if more than one hit 
	if Method in [0,1]:  
		Hits_AfterNMS = NMS(Hits_BeforeNMS, N=n_hit, maxOverlap=max_overlap, sortDescending=False) # only difference is the sorting 
 
	else: 
		Hits_AfterNMS = NMS(Hits_BeforeNMS, N=n_hit, maxOverlap=max_overlap, sortDescending=True) 
 
	print "\n-- Hits after NMS --\n" 
	for hit in Hits_AfterNMS : print hit
	 
	 
	## Loop over final hits to generate ROI, result table... 
	for hit in Hits_AfterNMS: 
		 
		if show_roi: 
			roi = Roi(*hit['BBox']) 
			roi.setName(hit['TemplateName']) 
			roi.setPosition(i+1) # set slice position 
			#nROI+=1 
			rm.add(None, roi, i+1) # Trick to be able to set slice when less images than ROI. Here i is an digit index before the Roi Name 
			 
		if show_table: 
			Xcorner, Ycorner = hit['BBox'][0], hit['BBox'][1] 
			Xcenter, Ycenter = CornerToCenter(Xcorner, Ycorner, hit['BBox'][2], hit['BBox'][3]) 
			Dico = {'Image':ImName, 'Template':hit['TemplateName'] ,'Xcorner':Xcorner, 'Ycorner':Ycorner, 'Xcenter':Xcenter, 'Ycenter':Ycenter, 'Score':hit['Score']} 
			AddToTable(Table, Dico, Order=('Image', 'Template', 'Score', 'Xcorner', 'Ycorner', 'Xcenter', 'Ycenter')) 
			Table.show("Results")
	 
	 
	## Display outputs
	if show_images: 

		# Initialise a stack of proper size if not the case before
		if Stack_Image.getSize()==0:
			 Stack_Image = ImageStack(ImProc.width, ImProc.height) # instead of using ImagePlus.getStack otherwise we loose the slice title for the 1st image
		 
		# Add images to Stack
		Stack_Image.addSlice(ImName, ImProc)  
		Stack_Image_ImP.setStack("Result", Stack_Image)

		# Update display
		Stack_Image_ImP.setSlice(i)
		Stack_Image_ImP.show()

		if show_roi:
			# Show All ROI + Associate ROI to slices 
			rm.runCommand("Associate", "true")	
			rm.runCommand("Show All with labels")