/* File: Smart_Projector.java Written: mars 2009 Author: Fanny Serman (fanny (dot) serman (at) gmail (dot) com written with Notepad++ http://notepad-plus.sourceforge.net/fr/site.htm Permission to use, copy, modify, and distribute this software for any purpose without fee is hereby granted, provided that this entire notice is included in all copies of any software which is or includes a copy or modification of this software and in all copies of the supporting documentation for such software. Any for profit use of this software is expressly forbidden without first obtaining the explicit consent of the author. THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTY. */ import ij.*; import ij.gui.*; import ij.plugin.*; import ij.process.*; import java.io.*; import ij.io.*; import java.*; import java.util.*; import java.awt.*; import java.awt.image.*; import java.io.*; import java.awt.event.*; import ij.measure.*; import java.awt.event.*; import java.lang.*; /*This plugin is developed to project "smartly" several series of stacks *in order to obtain quickly a good projection of your time-lapse movies. * *For each slice of the stack, the plugin will calculate the function *"focus_index" whose maxima should correspond to the sharpest structures *in the stack. If your stack corresponds to a thin and simple specimen, *the focus_index will have only one maximum along the Z (which will *hopefully be the structure you really want to see and not the noise you *have acquired under and above your tissue / organ...) Projection can be *made using this maximum (= "autofocus" slice) with different options : * *- around the autofocus: the given parameter is the number of slices *projected around the maximum (3 or 4 will correspond to the projection *of 3 slices : the one with the maximal focus_index, one before and one *after). You can activate tracking of the maximum which forces the *program to search the maximum in the next stack only in the slices close *to previous found maximum index. * *- near a % of the autofocus: keeps for *the projection all the slices which have a focus_index at least equal to *a certain percentage of the maximum (can give some rough results if you *have several interesing structures in you stack) *- around the first peak *of autofocus: sometimes two structures are recognised (for example *membranes and nuclei) and this option forces the program to keep only *the first maximum and to project around it (the % parameter checks that *the first maximum is big enough to be considered). * *When you launch *Smart_Projector, the plugin asks you to open one file among your *selected directory (as in the Import>ImageSequence command of ImageJ). *Then you give the number of different stacks you want to proceed, the *kind of projection (same options as in the Z-project plugin of ImageJ) *and the option of projection (see above). * *You can avoid all calculation *by choosing to project all slices of each stack. Can be handy if you *have several kind of stacks (with different number of slices in each) *and can' t directly use Concatenate_ and Grouped_ZProjector to compile *your film. Can help too if your files are too big to be all concatenated *because the plugin will handle each one separately. Example : * *See also : for more information about the calculation of focus_index, *see " Digital autofocus methods for automated microscopy", Shen F, *Hodgson L, Hahn K., Methods Enzymol. 2006;414:620-32. */ public class Smart_Projector implements PlugIn, ItemListener { /** Strings denoting the possible projection methods. These should * be the same as those supported by ZProjector. */ // Note: This will need to be updated if the projection methods supported // by ZProjector changes. */ static public final String[] methodStrings ={"Average Intensity", "Max Intensity", "Min Intensity","Sum slices","Standard deviation", "Median"}; static private int defaultMethod = ZProjector.MAX_METHOD; static private int progress = 0 ; static private int finalprogress = 1 ; // Pairs of instance / static variables for user options Vector checkboxes ; Vector numericfields ; Checkbox allstacks ; Checkbox normalize ; Checkbox peakautofocus ; Checkbox tracklisten ; Checkbox criteriumautofocus ; Checkbox lastoption ; Checkbox last2option ; TextField num1; TextField num2; TextField num3; TextField num2A; TextField num4; TextField num5; TextField num6; TextField num7; public Smart_Projector() {;} //Nothing to do. //--------------------------------------------------------------------------------------------------- //prog principal /* This method will be called when the plugin is loaded. */ public void run(String arg) { //***************************** //kernel definition float[] kernel={-1,0,1}; int lengkernel=3; int heigkernel=1; //******************************* //other 2D kernel //float[] kernel={{-1,-2,1},{-2,12,-2},{-1,-2,-1}}; //int lengkernel=3; //int heigkernel=3; //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° // first dialog to select directory // the user opens whatever images he wants in the good directory OpenDialog od = new OpenDialog("Open image ...", arg); if( od.getFileName()==null ) return; //The user pushed the cancel button. String initialfilmname = od.getFileName(); // get film name to initialize output //IJ.write("debug-initialfilmname-"+initialfilmname); String directory = od.getDirectory(); // get directory name String[] fileslist2 = (new File(directory)).list(); // get list of files in the directory if (fileslist2==null) return; fileslist2 = sortFileList (fileslist2); // sort files //for(int i=0;i100 || criterium < 0) { IJ.error("Criterium no included between 0 and 100"); return; } //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° //°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° // third dialog to pu root names GenericDialog gd2 = new GenericDialog("Write your file names"); if (filmnumber == 1){ if (initialfilmname.length()>14){ gd2.addStringField("File name contains ", initialfilmname.substring(0,9), 11); } else{ gd2.addStringField("File name contains ", initialfilmname.substring(0,initialfilmname.length()-4), 11); } } else { for (int l=0; l initial_stack.getSize()){IJ.error("Tracking begin number is not included between 0 and number of slices ");return;} int paratracking = -1; if (beginnumber != 0 ) {paratracking = beginnumber;} for (int i = 0; i < filmnumber; i++){ String[] fileslist = (new File(directory)).list(); fileslist = sortFileList (fileslist); filmname[i] = gd2.getNextString(); //builds lists that contains file names of each group if (filmname[i]!=null && (filmname[i].equals("") || filmname[i].equals("*"))) filmname[i] = null; if (filmname[i]==null) { IJ.error("You did not enter a file name"); return; } int filteredImages = 0; for (int m=0; m=0 && fileslist[m].endsWith(".txt") == false){ filteredImages++; } else { fileslist[m] = null; } } if (filteredImages==0) { IJ.error("None of the "+fileslist.length+" files contain\n the string '"+filmname[i]+"' in their name."); return; } String[] grouplist = new String[filteredImages]; int j = 0; for (int k=0; k= 0){ if( (paratracking-trackingnumber)<0){firstnumero = 0 ;}else{firstnumero =paratracking-trackingnumber;} if( (paratracking+trackingnumber)>image.getSize()-1){lastnumero = image.getSize();}else{lastnumero = paratracking+trackingnumber+1;} }else{ firstnumero = 0 ; lastnumero = image.getSize(); } if (normoption == true){ for (int numero=firstnumero; numero maxfocus){ maxfocus = focusindex[numero]; indicemax = numero; } } //implements new paratracking for next stack paratracking = indicemax; //........................................................ if( peak_option ==true){ //the goal is to project slices around the index indicemax ZProjector zproj = new ZProjector(improjectionplus); if((indicemax-(int)(projnumber/2))<0){ zproj.setStartSlice(1); } else{ zproj.setStartSlice((indicemax-(int)(projnumber/2)+1)); } if((indicemax+(int)(projnumber/2))>(improjectionplus.getStackSize()-1)){ zproj.setStopSlice(improjectionplus.getStackSize()); } else{ zproj.setStopSlice((indicemax+(int)(projnumber/2)+1)); } zproj.setMethod(defaultMethod); //if (isRGB) //zproj.doRGBProjection(); //else zproj.doProjection(); ImagePlus projection = zproj.getProjection(); ImageProcessor improc = projection.getProcessor(); out_stack.addSlice("Film-"+filmname[i]+"-proj-"+(n+1), improc); IJ.showProgress(progress, finalprogress); IJ.showStatus("-------------------- slice "+progress+" / "+finalprogress+" (group "+(i+1)+")"); }//end of peak_option==true else{ if ( criterium_option == true){ //in this case we project only slices with focusindex>(focusindex*criterium) //so we put black images in others ImageStack stackimprojectionplus = improjectionplus.getStack(); for(int numero=0 ; numerofocusindex[numero-1] && focusindex[numero] > secondmaxfocus){ secondmaxfocus = focusindex[numero]; secondindicemax = numero; } //IJ.write(numero+" 2indicemax "+secondindicemax+" 2maxfocus "+secondmaxfocus); } }else{ if (indicemax >= focusindex.length-2){ //IJ.write("2e cas"); for (int numero = indicemax-1 ; numero > 0 ; numero--){ if(focusindex[numero-1]>focusindex[numero] && focusindex[numero-1] > secondmaxfocus){ secondmaxfocus = focusindex[numero-1]; secondindicemax = numero-1; } //IJ.write(numero+" 2indicemax "+secondindicemax+" 2maxfocus "+secondmaxfocus); } }else{ //IJ.write("3e cas"); for (int numero = indicemax+2 ; numero < focusindex.length ; numero++){ if(focusindex[numero]>focusindex[numero-1] && focusindex[numero] > secondmaxfocus){ secondmaxfocus = focusindex[numero]; secondindicemax = numero; } } for (int numero = indicemax-1 ; numero > 0 ; numero--){ if(focusindex[numero-1]>focusindex[numero] && focusindex[numero-1] > secondmaxfocus){ secondmaxfocus = focusindex[numero-1]; secondindicemax = numero-1; } } } } if (last_option == true){ //condition to check if the second peak is big enough and if it is in the first position //if not we keep the maximal peak if ( secondmaxfocus < (1-paraecart/100) * maxfocus || secondindicemax > indicemax){ secondindicemax = indicemax; } //the goal is to project slices around the index secondindicemax ZProjector zproj = new ZProjector(improjectionplus); if((secondindicemax-(int)(firstprojnumber/2))<0){ zproj.setStartSlice(1); } else{ zproj.setStartSlice((secondindicemax-(int)(firstprojnumber/2)+1)); } if((secondindicemax+(int)(firstprojnumber/2))>(improjectionplus.getStackSize()-1)){ zproj.setStopSlice(improjectionplus.getStackSize()); } else{ zproj.setStopSlice((secondindicemax+(int)(firstprojnumber/2)+1)); } zproj.setMethod(defaultMethod); //if (isRGB) //zproj.doRGBProjection(); //else zproj.doProjection(); ImagePlus projection = zproj.getProjection(); ImageProcessor improc = projection.getProcessor(); //IJ.write("debug-filmname"+filmname[i]); out_stack.addSlice("Film-"+filmname[i]+"-proj-"+(n+1), improc); IJ.showProgress(progress, finalprogress); IJ.showStatus("-------------------- slice "+progress+" / "+finalprogress+" (group "+(i+1)+")"); }else{//end of if (last_option == true) //condition to check if the second peak is big enough and if it is in the first position //if not we keep the maximal peak if ( secondmaxfocus < (1-secondparaecart/100) * maxfocus || secondindicemax < indicemax){ secondindicemax = indicemax; } //the goal is to project slices around the index secondindicemax ZProjector zproj = new ZProjector(improjectionplus); if((secondindicemax-(int)(secondprojnumber/2))<0){ zproj.setStartSlice(1); } else{ zproj.setStartSlice((secondindicemax-(int)(secondprojnumber/2)+1)); } if((secondindicemax+(int)(secondprojnumber/2))>(improjectionplus.getStackSize()-1)){ zproj.setStopSlice(improjectionplus.getStackSize()); } else{ zproj.setStopSlice((secondindicemax+(int)(secondprojnumber/2)+1)); } zproj.setMethod(defaultMethod); //if (isRGB) //zproj.doRGBProjection(); //else zproj.doProjection(); ImagePlus projection = zproj.getProjection(); ImageProcessor improc = projection.getProcessor(); //IJ.write("debug-filmname"+filmname[i]); out_stack.addSlice("Film-"+filmname[i]+"-proj-"+(n+1), improc); IJ.showProgress(progress, finalprogress); IJ.showStatus("-------------------- slice "+progress+" / "+finalprogress+" (group "+(i+1)+")"); }//end of else (last_option == false) }//end of else (criterium_option == false) }//end of else (peak_option == false) }//end of else (all_option == false) //---------------------------------------------------------------------------------------------------- if (filetypet == 0){improjectionplus.close();} }//end of loops for all stacks inside a group }//end of loop for each groups of files ImagePlus out_image = new ImagePlus("Projection", out_stack); out_image.show(); } //function sortfilelist who sorts all files in selected folder String[] sortFileList(String[] list) { int listLength = list.length; //IJ.write("debug "+listLength); int first = listLength>1?1:0; //IJ.write("debug "+first); //IJ.write("debug "+listLength); //IJ.write(" "+(list[first].length())+" "+(list[listLength-1].length())+" "+(list[listLength/2].length())); //for(int i=0;i=48&&ch<=57) num += ch; } if (list2==null) list2 = new String[listLength]; num = "000000000000000" + num; // prepend maxDigits leading zeroes num = num.substring(num.length()-maxDigits); list2[i] = num + list[i]; } if (list2!=null) { ij.util.StringSorter.sort(list2); for (int i=0; i