// Title of toolset: LSM Transmission Deblurring.txt 
// First version: 05/12/2006

// Description:
// This toolset allows to perform some improvements on images obtained with Laser Scanning Microscopy (LSM)
// in transmission mode:
// Deblurring with usable default parameters values or user customized settings.
// Removing of horizontal interference streaks with usable default parameters values or user customized settings.
// Complete cleaning image treatment: deblurring and removing of horizontal streaks.
// more informations, and demo images are available from the internet resources of the toolset.
// A part of this tool is based on the two following ImageJ macros:
// from http://rsb.info.nih.gov/ij/macros/FFTRemoveStreaks.txt
// from http://rsb.info.nih.gov/ij/macros/GaussianConvolution.txt

// Author : Gilles Carpentier
// Faculte des Sciences et Technologies,
// Universite Paris 12 Val de Marne, France.

var  matrixchoice =newArray ("3","5","7","15","23","33","63"),defaultmatrix="33";
var  passes=newArray ("2","3","4","5","6","7","8","9"),defaultpass="4";
var optimize=1,sigmamini=1,sigmamax=40;

var percent = 0.005, sdhight = 3.5, largeHF= 0.002,optimizefft=1;

var onlinedoclink = "http://image.bio.methods.free.fr/lsmtrans.html";
var urllist = "http://image.bio.methods.free.fr/ij/ijupdatetest/ListOfMacros.txt";// to check the internet access
var demoimagelink1 = "http://image.bio.methods.free.fr/ij/ijmacro/lsm/Myoblast-init.tif.zip",demoimagename1="Myoblast-init.tif";
var demoimagelink2 = "http://image.bio.methods.free.fr/ij/ijmacro/lsm/Nerve.tif.zip",demoimagename2="Nerve.tif";

var xx = requires138e(); // check version at install time
function requires138e() {requires("1.38e"); return 0;}

// menu popup summering every commands of the the toolset menu bar
var pmCmds = newMenu("Popup Menu", newArray("Abort Process","-","Deblurring With Default Settings or Last User Settings","Deblurring With Custom Settings","-", "Removing Streaks With Default Settings or Last User Settings","Removing Streaks With Custom Settings","-","Deblurring and Removing Horizontal Streaks","-","Download\/Open LSM Myoblast-init Image","Download\/Open Phase Contrast Nerve Image","-","About LSM Transmission Deblurring","-","On Line Documentation"));

macro "Popup Menu" {
	cmd = getArgument();
	if (cmd !="-" && cmd =="Abort process")  {abortProcess ();}
	if (cmd !="-" && cmd =="Deblurring With Default Settings or Last User Settings")  {Debluring (0);}
	if (cmd !="-" && cmd =="Deblurring With Custom Settings")  {Debluring (1);}
	if (cmd!="-" && cmd == "Removing Streaks With Default Settings or Last User Settings") {removeStreaks (0);}
	if (cmd!="-" && cmd == "Removing Streaks With Custom Settings") {removeStreaks (1);}
	if (cmd!="-" && cmd == "Download\/Open LSM Myoblast-init Image") {OpenImageLink(0,demoimagelink1,demoimagename1);}
	if (cmd!="-" && cmd == "Download\/Open Phase Contrast Nerve Image") {OpenImageLink(0,demoimagelink2,demoimagename2);}
	if (cmd!="-" && cmd == "Deblurring and Removing Horizontal Streaks") {cleanLSMTransmission ();}
	if (cmd!="-" && cmd == "About LSM Transmission Deblurring") {about1();}
	if (cmd!="-" && cmd == "On Line Documentation") {doc ();}
}

macro "Unused Tool-1 - " {}  // leave slot between text tool and magnifying glass unused

// macro LSM Transmission and Phase Contrast Deblurring Menu Tool 
var uCmds = newMenu("LSM Transmission and Phase Contrast Deblurring Menu Tool",newArray("Deblurring With Default Settings or Last User Settings","Deblurring With Custom Settings","-","Removing Streaks With Default Settings or Last User Settings","Removing Streaks With Custom Settings","-","Deblurring and Removing Horizontal Streaks","-","Download\/Open LSM Myoblast-init Image","Download\/Open Phase Contrast Nerve Image"));
macro "LSM Transmission and Phase Contrast Deblurring Menu Tool -  "{
	cmd = getArgument();
	if (cmd!="-" && cmd == "Deblurring With Default Settings or Last User Settings") {Debluring (0);}
	if (cmd!="-" && cmd == "Deblurring With Custom Settings") {Debluring (1);}
	if (cmd!="-" && cmd == "Removing Streaks With Default Settings or Last User Settings") {removeStreaks (0);}
	if (cmd!="-" && cmd == "Removing Streaks With Custom Settings") {removeStreaks (1);}
	if (cmd!="-" && cmd == "Deblurring and Removing Horizontal Streaks") {cleanLSMTransmission ();}
	if (cmd!="-" && cmd == "Download\/Open LSM Myoblast-init Image") {OpenImageLink(0,demoimagelink1,demoimagename1);}
	if (cmd!="-" && cmd == "Download\/Open Phase Contrast Nerve Image") {OpenImageLink(0,demoimagelink2,demoimagename2);}
}

macro "Abort Process Action Tool -  " {
	abortProcess ();
}

macro "On Line Documentation Action Tool -  "{
	doc ();
} 

macro "Version and Update Infos Action Tool -  " {
	VersionInfos ();
}

macro "About LSM Transmission Deblurring Action Tool -  " {
	about1();
}

// functions like macros

function Debluring (custom) {
	setBatchMode(true);
	starttime = getTime();
	imaname = getTitle;depth = bitDepth;
	if (depth > 8) {showMessageWithCancel ("This macro works with 8 bit images. Do you want to\nconvert it and continue the process?");}
	if (depth > 8) run("8-bit");
	imagey = getHeight();imagex = getWidth();
	if (custom == 1) getdeblurParam();

	defaultmatrix=parseFloat (defaultmatrix);
	defaultpass= parseFloat (defaultpass);
	sigmamini=parseFloat (sigmamini);
	sigmamax=parseFloat (sigmamax);

	workingStack= makeStack (imaname,imagex,imagey,defaultpass);
	setPasteMode("Copy");
	selectImage(imaname);run("Select All");run("Copy");selectWindow(workingStack);setSlice(1);run("Paste");run("Select None");
	range=(sigmamax-sigmamini); steps= (range/(defaultpass-1));
	for (i=1; i<=defaultpass; i++) {
		nette (workingStack,i,defaultmatrix,(sigmamini+(i-1)*steps));
	}
	sumnette (workingStack);
	selectWindow(workingStack); setSlice(2);
	final=duplicate (workingStack,"1");
	if (lastIndexOf(imaname, ".") > 0) {imaname = substring (imaname,0,lastIndexOf(imaname, "."));}
	rename(imaname + "-Deblured" );
	if (optimize ==1) {run("Enhance Contrast", "saturated=0.5 normalize");}
	selectWindow(workingStack);close();
	setBatchMode("exit and display");
	seconds = (getTime-starttime)/1000;
	//print("Time to perform the process= "+ seconds);
}

function removeStreaks (custom) {

	// Based on http://rsb.info.nih.gov/ij/macros/FFTRemoveStreaks.txt
	nomdimage = getTitle;depth = bitDepth;
	imageid = getImageID();
	if (depth > 8) {showMessageWithCancel ("This macro works with 8 bit images. Do you want to\nconvert it and continue the process?");}
	if (depth > 8) run("8-bit");
	imagey = getHeight();
	imagex = getWidth();
	if (custom == 1) {getfftParam();}
	setBatchMode(true);
	wokimimage=duplicate (nomdimage,1);
	if (isOpen("Transmission_Filter")) {
		selectWindow("Transmission_Filter");
		run("Close");
	}
	size =imagex;
	newImage("Transmission_Filter", "8-bit black", size, size, 1);
	width=3;halfwidth=(floor(width/2));
	barre(((size/2)-halfwidth),0,width,size);
	matrice= matrix(9,40); // to adjust
	selectWindow("Transmission_Filter");
	it=4; // to adjust
	for (nconv=0;nconv <it;nconv++) {
		run("Convolve...", "text1=["+ matrice+"] normalize");
	}
	longueur=floor(size*percent);
	width=largeHF*imagex; 
	if (width<1) {width =1;}
	halfwidth=(floor(width/2)); 
	barre(((size/2)-halfwidth),0,width,longueur);
	barre(((size/2)-halfwidth),(size-longueur),width,longueur);
	matrice= matrix(13,sdhight);// to adjust
	run("Convolve...", "text1=["+ matrice+"] normalize");
	run("Enhance Contrast", "saturated=0 normalize");
	run("Invert");
	selectImage(wokimimage);
	run("32-bit");
	run("Custom Filter...", "filter=Transmission_Filter");
	run("8-bit");
	if (optimize ==1) {run("Enhance Contrast", "saturated=0.5 normalize");}
	if (lastIndexOf(nomdimage, ".") > 0) {nomdimage = substring (nomdimage,0,lastIndexOf(nomdimage, "."));}
	rename(nomdimage + "-fft" );
	run("Select None");
	selectWindow("Transmission_Filter");close();
	setBatchMode("exit and display");
}

function openmyoblast () {OpenImageLink(0,demoimagelink1,demoimagename1);}

function opennerve () {OpenImageLink(0,demoimagelink2,demoimagename2);}

function abortProcess () {setKeyDown("Esc");}

function cleanLSMTransmission () {
	Debluring (0);
	removeStreaks (0);
}

function doc () {
	if (File.openUrlAsString(urllist) == "") exit("You need an internet access to run this function.");
	showMessageWithCancel  ("A notice is avaible on line. Open it with your default web browser?");
	run("URL...", "url=["+onlinedoclink +"]");
}

// Functions specific to fft remove streaks

function getfftParam() {
	Dialog.create("User Parameters for FFT Removing Streaks");
	Dialog.addMessage("Choose the frequency masks parameters:");
	Dialog.addNumber("Percent of the half vertical axis of power spectra for hight frequencies:", percent, 3, 4, "");
	Dialog.addNumber("Percent of the horizontal axis of power spectra for hight frequencies:", largeHF, 3, 4, "");
	Dialog.addNumber("Standard Deviation of gaussian transition for hight frequencies:", sdhight, 1, 3, "");
	Dialog.addCheckbox("Normalized histograms 0.5 % saturation", optimizefft);
	Dialog.show();
	percent = Dialog.getNumber();
	largeHF = Dialog.getNumber();
	sdhight = Dialog.getNumber();
	optimizefft=Dialog.getCheckbox();
}

function barre(barx,bary,largbar,hautbar) {
    makeRectangle(barx, bary, largbar, hautbar);
    setForegroundColor(255, 255, 255);
    run("Fill");
    run("Select None");
}

// Common functions, and functions specific to the deblurring

function getdeblurParam() {
	Dialog.create("User Parameters for Deblurring");
	Dialog.addMessage("Choose the size of the matrix, the number \nof passes (range size of details), and the \noptionnal enhance contrast.");
	Dialog.addChoice("Size of the matrix", matrixchoice, toString(defaultmatrix));
	Dialog.addChoice("Number of passes", passes, toString(defaultpass));
	Dialog.addNumber("Minimal Standard Deviation", sigmamini, 1, 3, "");
	Dialog.addNumber("Maximal Standard Deviation", sigmamax, 1, 3, "");
	Dialog.addCheckbox("Normalized histograms 0.5 % saturation", optimize);
	Dialog.show();
	defaultmatrix=Dialog.getChoice();
	defaultpass= Dialog.getChoice();
	sigmamini=Dialog.getNumber();
	sigmamax=Dialog.getNumber();
	optimize=Dialog.getCheckbox();
}

// square function
function carre (car) {
	car= (car * car);
	return car;
}

// gaussian convolution matrix function
// from http://rsb.info.nih.gov/ij/macros/GaussianConvolution.txt
function matrix (taille,gauss) {
	matrice="";
	for (j=0; j < taille; j++) {
		lignea="";
		for (i=0; i < taille; i++) {
			numer = -(carre(i-floor(taille/2)) + carre(j-floor(taille/2)));
			denom = 2 * carre(gauss);
			coeff=exp(numer/denom);
			lignea = lignea + " " + coeff;
		} 
	matrice = matrice + lignea + "\n";	
	}
	return matrice;
}

function duplicate (imaname,num) {
	selectWindow(imaname);
	run("Select None");
  	run("Duplicate...", "title=blured_"+num);
	nomwork = getTitle;
	return nomwork;
}

function makeStack (imaname,x,y,num) {
	newImage(imaname + "-work", "8-bit", x,y, (num+2));
	nomwork = getTitle;
	return nomwork;
}

function nette (stack,nbpass,matrixsize,sigma) {
	selectWindow(stack);setSlice(1);
	blured=duplicate (stack,1); matrice=matrix (matrixsize,sigma);
	run("Convolve...", "text1=["+ matrice+"] normalize");
	selectWindow(stack);setSlice(1);
	init=duplicate (stack,2); 	
	imageCalculator("subtract create 32-bit ", init, blured);
	resultimage = getTitle;rename("resultat");
	run("8-bit");
	run("Select All");run("Copy");selectWindow(stack);setSlice(2+nbpass);run("Paste");run("Select None");
	selectImage ("resultat"); close();selectWindow(blured);close();selectWindow(init);close();
}

function addnett (stack,slc1,slc2,scldest) {
	selectWindow(stack);setSlice(slc1);
	nette1=duplicate (stack,1);
	selectWindow(stack);setSlice(slc2);
	nette2=duplicate (stack,2);
	imageCalculator("Add create 32-bit ", nette1, nette2);
	resultimage = getTitle;rename("resultat"); run("8-bit");
	run("Select All");run("Copy");selectWindow(stack);setSlice(scldest);run("Paste");run("Select None");
	selectWindow(nette1);close();selectWindow(nette2);close();selectImage ("resultat"); close();
}

function sumnette (stack) {	
	selectWindow(stack);nbit=(nSlices-2);
	for (i=1; i<=nbit; i++) {
		addnett (stack,2,(i+2),2);
	}
}

function about1() {
	about="";
	about=about + "\n                                        -- LSM Transmission Deblurring --";
	about=about + "\n \n* Description:";
	about=about + "\n \nThis toolset allows to perform some improvements on images obtained with Laser Scanning";
	about=about + "\n Microscopy (LSM) in transmission mode. It can also be used in phase contrast microscopy.";
	about=about + "\n \n* Notice:";
	about=about + "\n \n   - The \"LSM Transmission and Phase Contrast Deblurring Menu\" regroups the different "; 
 	about=about + "\n   functions. These are also available by right click onto an image (control click for Macintosh";
	about=about + "\n   withsingle button user interface device):";
	about=about + "\n \n      - \"Deblurring With Default Settings or Last User Settings\" sub-menu allows to enhance";
	about=about + "\n      details in phase contrast or transmission LSM images. It also removes eventual";
	about=about + "\n      shadings. The default settings gives good results in most of cases. They can be";
	about=about + "\n      customized using the \"Deblurring With Custom Settings\" sub-menu.";
	about=about + "\n  \n     - \"Removing Streaks With Default Settings or Last User Settings\" sub-menu allows to";
	about=about + "\n      remove horizontal interference streaks, often present in transmission LSM images,";
	about=about + "\n      particularly visible after deblurring. The default settings gives good results in most of cases.";
	about=about + "\n      Optimize the removal of hight frequencies streaks using the \"Removing Streaks With";
	about=about + "\n      Custom Settings\" sub-menu.";
	about=about + "\n  \n     - \"Deblurring and Removing Horizontal Streaks\" sub-menu performs a complete cleaning";
	about=about + "\n       of transmission LSM images. If the deblurring and\/or remove streaks functions were optimized";
	about=about + "\n       by the user, these parameters will be used.";
	about=about + "\n  \n     - Demo lsm and phase contrast images for testing settings are downloadable from the two sub-"; 
	about=about + "\n       menus \"Download\/Open LSM Myoblast-init Image\" and \"Download\/Open Phase Contrast";
 	about=about + "\n       Nerve Image\".";
	about=about + "\n \n  - Click on the \"Abort Process\" ImageJ tool bar icon to cancel too long processes.";
	about=about + "\n  - Click on the \"On Line Documentation\" ImageJ tool bar icon for more details.";
	about=about + "\n  - Click on the \"Version and Update Infos\" ImageJ tool bar icon to look for new beta versions.";

	about=about + "\n-------------------------------------------------------------------------------------------------------------";
	about=about +"\nAuthor: Gilles Carpentier"+"\nFaculte des Sciences et Technologies"+"\nUniversite Paris 12 Val de Marne, France.";
	showMessage(about);
	//print(about);
}

function OpenImageLink(question,demoimagelink,demoim) {
	// Check if already downloaded.
	if (isOpen(demoim)) exit ("The \"" + demoim + "\" is already open.");
	demoimalocation = getDirectory("startup");	
	fildestination = demoimalocation+ "Downloaded Demo Images/" + demoim;
	if (File.exists(fildestination) && ! isOpen(demoim)) {
		if (question ==1 ) showMessageWithCancel ("The \"" + demoim + "\" has already been downloaded. Open it?");
		open(fildestination);
	}
	else {
		if (! File.exists(fildestination)) {
			if (File.openUrlAsString(urllist) == "") exit("You need an internet access to run this function.");
			showMessageWithCancel ("ImageJ will download a demo image. Continue?");
			run("URL...", "url=["+demoimagelink+"]");
			imageid = getImageID();
			nomdimage = getTitle;
			// Create a <Downloaded Demo Images> repertory in ImageJ folder.
			ImaDemo = demoimalocation+"Downloaded Demo Images"+File.separator;
			File.makeDirectory(ImaDemo);
			if (!File.exists(ImaDemo)) exit("Unable to create directory, something wrong in the ImageJ folder");
			selectWindow(nomdimage);
			save(""+ImaDemo+""+ nomdimage +"");
		}     
	}
}

// --- End of code of the macro project ---//
// ----------------------------------//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
// -------------------*** Additionnal code for on line update resources ***-----------------------------

//Developer info
//Kind:Toolset
//Title:"LSM Transmission Deblurring" 
//Version:1.0
//Date: 10 December 2006
//Origin:NIH
//End info

function VersionInfos () {
	// variables for on line update resources
	beginsign="//Developer info";endsign="//End info"; 
	kind="toolsets/"; 
	urlrep="http://image.bio.methods.free.fr/ij/ijmacro/lsm/";
	name="LSM Transmission Deblurring.txt"; 
	namedev="LSM Transmission Deblurring-dev.txt"; 
	favoritefoldername= "Image.Bio.Methods";

	version=versionMessage();
	if (indexOf(version, "install it?" ) > 0 ) {
		macrotext=getdistantmacro (namedev,urlrep);macrolocal="";
		macropath=getDirectory("macros")+kind+namedev;
		if (File.exists(macropath)) {macrolocal=File.openAsString(macropath);}
		if (macrotext != macrolocal) {
			//perfom the installation
			Dialog.create("New version installation option");
			Dialog.addMessage(version);
			Dialog.addCheckbox("Install a Plugin Shortcut?", 0);
			Dialog.addMessage("(This option provides a shortcut in the plugins menu of ImageJ, making easier\nthe next use of the new installed version).");
			Dialog.show();
			plugin= Dialog.getCheckbox();
			f= File.open(macropath);
			print (f,macrotext);
			File.close(f);
			if (plugin ==1) {InstallPluginsStarter(namedev);}
			message="The installation of the "+giveDevInfo (macrotext,1)+ " "+ giveDevInfo (macrotext,2)+ "is completed.";
			message=message+ " Do you want to run it?";
			showMessageWithCancel(message);
			run("Install...", "install=["+macropath+"]");
		}
	} else {showMessage (version); // comment without installation available}
}

function versionMessage() {
	
	version="";
	if (getDirectory("startup") == 0) exit ("Unable to find the startup directory, something wrong in the ImageJ folder");
	if (getDirectory("macros") == 0) exit ("Unable to find the macros directory, something wrong in the ImageJ folder");
	MacroPath=getDirectory("macros");thismacropath=MacroPath+kind+name;
	if (! File.exists(thismacropath)) exit ("This macro has to be recorded under the name of \"" +name+"\"\ninto the \"macros/"+kind+"\" folder of ImageJ.");

	macrotext=File.openAsString(thismacropath);
	macrotextdistant=getdistantmacro (namedev,urlrep);

	version="";macrolocal="";
	version=version + "\n \nThis version of the " + giveDevInfo (macrotext,1) + " " + giveDevInfo (macrotext,2);
	version=version + "is provided by the " + giveDevInfo (macrotext,5)+ " web site.";
	version=version + "\nVersion number: " + giveDevInfo (macrotext,3)+ " - " + giveDevInfo (macrotext,4) +".";
	
	if (macrotextdistant !="" ) {
		new=giveDevInfo (macrotextdistant,3);old=giveDevInfo (macrotext,3);
		if (new > old) {
			macropath=getDirectory("macros")+kind+namedev;
			if (File.exists(macropath)) {macrolocal=File.openAsString(macropath);}
			if (macrotextdistant != macrolocal) {
				update="\n \nA new beta version "+new+ " is available on the "  +giveDevInfo (macrotextdistant,5)+ " web site: ";
				update=update+ "\n \nDo you want to install it?";
			} else {
				update ="\n \nThe new "+new+" beta version called \"" +namedev+ "\" provided by \nthe "+giveDevInfo (macrotextdistant,5) +" web site has already be installed";
				update = update+ " in the \"" +kind+ "\" repertory \nof ImageJ.";
			}
		} else {
			update="No new Beta version available.";
		}
		version=version +"\n" + update ;
	} 
	return version; 
}

function giveDevInfo (text,n) {
	lines=split(text,"\n");
	if ( (indexOf(text, beginsign)<0) || (indexOf(text, endsign)<0) ) exit ("Not upgradable macro code.");
	for (i=0; lines[i] != endsign; i ++) {}
	for (j=i; lines[j] != beginsign; j --) {}
	infotext=newArray(i-j-1);
	for (i=0; i < infotext.length; i ++) {infotext[i]=lines[i+j+1];}
	info=infotext[n-1]; signature=":";
	cut = indexOf(info, signature);
	info = substring(info,(cut+lengthOf(signature)),lengthOf(info));
	return info;
}

// Function giving the content of a distant macro (name) located at the distant repertory (urlrep).
function getdistantmacro (name,urlrep) {
	macrotextnih="";
	if (File.openUrlAsString("http://rsb.info.nih.gov/ij/macros/Arrays.txt") != "") {
		distantmacrolink = urlrep + name;
		if (indexOf(distantmacrolink, " ") > -1) {
			while (indexOf(distantmacrolink, " ") > -1) {
				distantmacrolink=substring(distantmacrolink, 0, (indexOf(distantmacrolink, " ")))+"%20"+substring(distantmacrolink, (indexOf(distantmacrolink, " ")+1),lengthOf(distantmacrolink) );
			}
		}
		showStatus("Internet link...");
		macrotextnih =File.openUrlAsString(distantmacrolink);
		showStatus("");
	} else { showMessage ("No internet connection to looks for beta version.");}
	return macrotextnih;
}

function InstallPluginsStarter(macroname) {
	// from MacroPluginShortcutsTool.txt
	codestarter = "run\(\"Install...\", \"install=[\"+getDirectory(\"macros\")+\""+kind+ macroname + "\]\"\);";
	if (getDirectory("plugins") == "") exit ("Unable to find the Plugins directory; something wrong in the ImageJ folder.");
	if (endsWith(macroname, ".txt") || endsWith(macroname, ".ijm")) pluginname = substring(macroname, 0, (lengthOf(macroname)-4));
	StarterDir = getDirectory("plugins")+favoritefoldername+File.separator;
	File.makeDirectory(StarterDir);
	if (!File.exists(StarterDir)) exit ("Unable to create "+favoritefoldername+" Macros directory, something wrong in the ImageJ folder.");
	starterplugin = StarterDir + pluginname +"_ .ijm";
	f= File.open(StarterDir + pluginname +"_ .ijm");
	print (f,codestarter);
	File.close(f);
	showMessage ("The plugin shortcut \"" +pluginname+ "\" will be available after\nImageJ restarting, in the \"Plugins->" + favoritefoldername + "\" menu.");
}

// *** End of additionnal code for on line update ressources ***



