import ij.*; import ij.gui.*; import ij.plugin.*; import ij.process.*; import ij.measure.*; import java.awt.*; import java.awt.event.*; import java.lang.Math.*; import java.awt.image.*; import ij.plugin.filter.Analyzer; // FRETcalc plugin version 1.0 // for analysis of FRET by acceptor photobleaching images using ImageJ program // written by David Stepensky (david.stepensky@yale.edu) May 2006 // Modified to add bleaching corrections etc by Ben Corry 2007 public class FRETcalc_ben extends Dialog implements ActionListener, WindowListener, Runnable { private Thread threadProcess = null; ImagePlus imp_orig, imp; ImageProcessor ip; int DPre = 1; int DPost = 2; int APre = 3; int APost = 4; int XYsize = 1; // sub-ROI size int Donor_th = 40; //Thresholds int Acceptor_th = 20; boolean Choice_donor_th = true; double Bleach_Control = 0.03; boolean Choice_Bleach_th = true; boolean Choice_Bleach_th_sign=false; int Bleach_th=70; boolean Choice_FRET_th = true; int FRET_th = -10; boolean Choice_FRET = true; //Plots output boolean Choice_Bleach = false; boolean Choice_DonAcc = false; boolean Choice_FRET_Bleach=false; boolean Choice_FRET_Don = false; boolean Choice_FRET_Acc = false; boolean Choice_FRET_DonAcc = false; boolean Choice_FRETHis = true; //Histograms output boolean Choice_DonHis = false; boolean Choice_AccHis = false; boolean Choice_Results = true; //Results table output boolean Choice_RawResults = false; public FRETcalc_ben () { super(new Frame(), "FRETcalc v1"); if (IJ.versionLessThan("1.21a")) return; imp_orig = WindowManager.getCurrentImage(); if (imp_orig == null) { IJ.showMessage("Image required."); return; } ip = imp_orig.getProcessor(); doDialog(); } public void run() { } // Build the dialog box. private GridBagLayout layout; private GridBagConstraints constraint; private Button bnSmooth; private Button bnA_B; private Button bnBg; private Button bnLUT; private Button bnSettings; private Button bnOutput; private Button bnCalc; private Button bnHelp; private Button bnSave; private Button bnClose; private void doDialog() { // Layout layout = new GridBagLayout(); constraint = new GridBagConstraints(); bnSmooth = new Button("Smooth"); bnA_B = new Button("Px by Px subtract"); bnBg = new Button("Bg subtraction"); bnLUT = new Button("LUT"); bnSettings = new Button("Settings"); bnOutput = new Button("Options"); bnCalc = new Button("Calculate"); bnHelp = new Button("Help"); bnSave = new Button("Save Image as"); bnClose = new Button("Close"); // Panel parameters Panel pnMain = new Panel(); pnMain.setLayout(layout); addComponent(pnMain, 0, 0, 2, 1, 2, new Label("Image manipulations:")); addComponent(pnMain, 1, 0, 1, 1, 5, bnBg); //Bg addComponent(pnMain, 1, 1, 1, 1, 5, bnSmooth); //Smooth addComponent(pnMain, 2, 0, 1, 1, 5, bnLUT); //LUT change to Rainbow2 addComponent(pnMain, 2, 1, 1, 1, 5, bnA_B); //A-B addComponent(pnMain, 3, 0, 2, 1, 2, new Label("--------------------------------------------------")); addComponent(pnMain, 4, 0, 2, 1, 2, new Label("FRET data analysis settings:")); addComponent(pnMain, 5, 1, 1, 1, 5, bnSettings);//Settings addComponent(pnMain, 6, 0, 2, 1, 2, new Label("Output options:")); addComponent(pnMain, 7, 1, 1, 1, 5, bnOutput); //Output addComponent(pnMain, 8, 0, 2, 1, 2, new Label("--------------------------------------------------")); addComponent(pnMain, 12, 0, 2, 1, 2, new Label("FRET calculation:")); addComponent(pnMain, 13, 1, 1, 1, 5, bnCalc); //FRET calc addComponent(pnMain, 14, 0, 2, 1, 2, new Label("--------------------------------------------------")); addComponent(pnMain, 15, 0, 1, 1, 5, bnHelp); //Help addComponent(pnMain, 16, 0, 1, 1, 5, bnSave); //Save addComponent(pnMain, 16, 1, 1, 1, 5, bnClose); //Close // Add Listeners bnBg.addActionListener(this); bnSmooth.addActionListener(this); bnLUT.addActionListener(this); bnA_B.addActionListener(this); bnSettings.addActionListener(this); bnOutput.addActionListener(this); bnCalc.addActionListener(this); bnHelp.addActionListener(this); bnSave.addActionListener(this); bnClose.addActionListener(this); // Build panel add(pnMain); pack(); setResizable(false); GUI.center(this); setVisible(true); IJ.wait(250); // work around for Sun/WinNT bug } final private void addComponent( final Panel pn, final int row, final int col, final int width, final int height, final int space, final Component comp) { constraint.gridx = col; constraint.gridy = row; constraint.gridwidth = width; constraint.gridheight = height; constraint.anchor = GridBagConstraints.NORTHWEST; constraint.insets = new Insets(space, space, space, space); constraint.weightx = IJ.isMacintosh()?90:100; constraint.fill = constraint.HORIZONTAL; layout.setConstraints(comp, constraint); pn.add(comp); } // Implement the listeners public synchronized void actionPerformed(ActionEvent e) { if (e.getSource() == bnClose) { dispose(); } else if (e.getSource() == bnLUT){ //Change LUT IJ.run("Rainbow_fret4"); } else if (e.getSource() == bnSave){ //Save imp = WindowManager.getCurrentImage(); IJ.run("Save"); imp.updateAndDraw(); } else if (e.getSource() == bnSettings){ //Change the settings GenericDialog gd = new GenericDialog("FRET calculation settings"); gd.addMessage("Pre & post-bleach images\n(slice numbers):"); gd.addNumericField("Donor Pre-",DPre,0 ); gd.addNumericField("Donor Post-",DPost,0 ); gd.addNumericField("Acceptor Pre-",APre,0 ); gd.addNumericField("Acceptor Post-",APost,0 ); gd.addMessage("Settings for data analysis:"); gd.addNumericField("sub-ROI size (pixels):", XYsize, 0); gd.addNumericField("Donor threshold:", Donor_th, 0); gd.addNumericField("Acceptor threshold:", Acceptor_th, 0); gd.addCheckbox("Use donor threshold pre and post?",Choice_donor_th); gd.addNumericField("fraction donor gets bleached:", Bleach_Control, 2); gd.addCheckbox("Use %bleached threshold?",Choice_Bleach_th); gd.addCheckbox("Analyze data below threshold?",Choice_Bleach_th_sign); gd.addNumericField("%bleached threshold:", Bleach_th, 0); gd.addCheckbox("Use %FRET threshold?",Choice_FRET_th); gd.addNumericField("%FRET threshold:", FRET_th, 0); gd.showDialog(); if (gd.wasCanceled()) return; DPre = (int) gd.getNextNumber(); DPost = (int) gd.getNextNumber(); APre = (int) gd.getNextNumber(); APost = (int) gd.getNextNumber(); XYsize=(int) gd.getNextNumber(); Donor_th = (int) gd.getNextNumber(); Acceptor_th = (int) gd.getNextNumber(); Choice_donor_th = gd.getNextBoolean(); Bleach_Control = (double) gd.getNextNumber(); Choice_Bleach_th = gd.getNextBoolean(); Choice_Bleach_th_sign = gd.getNextBoolean(); Bleach_th = (int) gd.getNextNumber(); Choice_FRET_th = gd.getNextBoolean(); FRET_th = (int) gd.getNextNumber(); } else if (e.getSource() == bnOutput){ //Set the output options GenericDialog gd = new GenericDialog("Output options:"); gd.addMessage("Plots:"); gd.addCheckbox("%FRET plot",Choice_FRET); gd.addCheckbox("%Bleached plot",Choice_Bleach); gd.addCheckbox("Donor vs. Acceptor plot",Choice_DonAcc); gd.addCheckbox("%FRET vs. %Bleached plot",Choice_FRET_Bleach); gd.addCheckbox("%FRET vs. Donor plot",Choice_FRET_Don); gd.addCheckbox("%FRET vs. Acceptor plot",Choice_FRET_Acc); gd.addCheckbox("%FRET vs. Donor/Acceptor ratio plot",Choice_FRET_DonAcc); gd.addMessage("Histograms:"); gd.addCheckbox("%FRET histogram",Choice_FRETHis); gd.addCheckbox("Donor histogram",Choice_DonHis); gd.addCheckbox("Acceptor histogram",Choice_AccHis); gd.addMessage("Tables:"); gd.addCheckbox("Summary Results table",Choice_Results); gd.addCheckbox("Raw Results table",Choice_RawResults); gd.showDialog(); if (gd.wasCanceled()) return; Choice_FRET = gd.getNextBoolean(); Choice_Bleach = gd.getNextBoolean(); Choice_DonAcc = gd.getNextBoolean(); Choice_FRET_Bleach = gd.getNextBoolean(); Choice_FRET_Don = gd.getNextBoolean(); Choice_FRET_Acc = gd.getNextBoolean(); Choice_FRET_DonAcc = gd.getNextBoolean(); Choice_FRETHis = gd.getNextBoolean(); Choice_DonHis = gd.getNextBoolean(); Choice_AccHis = gd.getNextBoolean(); Choice_Results = gd.getNextBoolean(); Choice_RawResults = gd.getNextBoolean(); } else if (e.getSource() == bnSmooth){ // Smooth the image -> new image ImagePlus imp_orig = WindowManager.getCurrentImage(); ImageStack stack = imp_orig.getStack(); String title = imp_orig.getTitle(); IJ.run("Smooth"); imp_orig.hide(); new ImagePlus(title+"_smoothed",stack).show(); ImagePlus imp_sm = WindowManager.getCurrentImage(); imp_sm.updateAndDraw(); } else if (e.getSource() == bnA_B){ // Pixel to pixel difference: Slice A - Slice B ImagePlus imp = WindowManager.getCurrentImage(); ImageStack stack = imp.getStack(); String label = "Donor Post-Pre"; GenericDialog gd = new GenericDialog("Pixel by pixel A-B"); gd.addStringField("New slice name:", label ); gd.addNumericField("sliceA",1,0 ); gd.addNumericField("sliceB",2,0 ); gd.showDialog(); if (gd.wasCanceled()) return; label = gd.getNextString(); int A = (int) gd.getNextNumber(); int B = (int) gd.getNextNumber(); ImageProcessor ipA, ipB, ipC; ipA = stack.getProcessor(A); ipB = stack.getProcessor(B); int width = ipA.getWidth(); int height = ipA.getHeight(); int v; stack.addSlice(label, ip.createProcessor(width, height),stack.getSize()); ipC = stack.getProcessor(stack.getSize()); for (int x=0; x 255) v=255; if (v < 0) v=0; ipC.putPixelValue(x, y, v); } } imp.updateAndDraw(); imp.setSlice(stack.getSize()); } else if (e.getSource() == bnBg){ // Background subtraction -> new image ImagePlus imp_orig = WindowManager.getCurrentImage(); ImageStack stack = imp_orig.getStack(); String title = imp_orig.getTitle(); Roi roi = imp_orig.getRoi(); if(imp_orig.getRoi()==null) {IJ.showMessage("Error", "No ROI"); return;} if(roi.getType() != 0) {IJ.showMessage("Error", "Rectangular ROI is required"); return;} Rectangle r = roi.getBounds(); GenericDialog gd = new GenericDialog("Bg subtraction"); gd.addNumericField("From slice",1,0 ); gd.addNumericField("To slice",4,0 ); gd.showDialog(); if (gd.wasCanceled()) return; int A = (int) gd.getNextNumber(); int B = (int) gd.getNextNumber(); imp_orig.hide(); new ImagePlus(title+"-bg",stack).show(); ImagePlus imp_bg = WindowManager.getCurrentImage(); ImageStack stack_bg = imp_bg.getStack(); ImageProcessor ip_bg; for (int Z=A; Z<=B; Z++) { // loop for all the selected slices ip_bg = stack.getProcessor(Z); int width = ip_bg.getWidth(); int height = ip_bg.getHeight(); int v; int Sum=0; int PxCount=0; int MeanBg=0; for (int i=r.x; i 255) v=255; if (v < 0) v=0; ip_bg.putPixelValue(x, y, v); } } } imp_bg.updateAndDraw(); } else if (e.getSource() == bnCalc){ // FRET calculation & output ImagePlus imp = WindowManager.getCurrentImage(); ImageStack stack = imp.getStack(); String title = imp.getTitle(); Roi roi = imp.getRoi(); if(imp.getRoi()==null) {IJ.showMessage("Error", "No ROI"); return;} if(roi.getType() != 0) {IJ.showMessage("Error", "Rectangular ROI is required"); return;} Rectangle r = roi.getBounds(); ImageProcessor ipDPre, ipDPost, ipAPre, ipAPost; ipDPre = stack.getProcessor(DPre); ipDPost = stack.getProcessor(DPost); ipAPre = stack.getProcessor(APre); ipAPost = stack.getProcessor(APost); int width = ipDPre.getWidth(); int height = ipDPre.getHeight(); int count=0;double bleach_v; double FRET_v; double DonPre, AccPre, DonPost, AccPost, DP; int npixels; for (int i=r.x; i=Donor_th && DonPost>=Donor_th && AccPre>=Acceptor_th) || (Choice_donor_th == false && DonPost>=Donor_th && AccPre>=Acceptor_th)) { bleach_v=(double) 100*(1-AccPost/AccPre); if(bleach_v>0 && bleach_v<200) { if(Choice_Bleach_th == false || (Choice_Bleach_th == true && Choice_Bleach_th_sign==false && bleach_v >= Bleach_th) || (Choice_Bleach_th == true && Choice_Bleach_th_sign==true && bleach_v < Bleach_th)) { DonPost=DonPost*(1+Bleach_Control); // Ben's addition for corrections (2 lines) DonPost=DonPost+(DonPost-DonPre)*(AccPost/(AccPre-AccPost)); FRET_v=100*(DonPost-DonPre)/DonPost; if(Choice_FRET_th == false || (Choice_FRET_th == true && FRET_v >= FRET_th)) { count++; } } } } } } int [][] Data_px = new int[count][4]; double [] DPre_px = new double[count]; double [] DPost_px = new double[count]; double [] APre_px = new double[count]; double [] APost_px = new double[count]; double [] DA_ratio_px = new double[count]; double[] Bleach_px = new double[count]; double[] FRET_px = new double[count]; int [] FRET_to_plot = new int[count]; count=0; for (int i=r.x; i=Donor_th && DonPost>=Donor_th && AccPre>=Acceptor_th) || (Choice_donor_th == false && DonPost>=Donor_th && AccPre>=Acceptor_th)) { bleach_v=(double) 100*(1-AccPost/AccPre); if(bleach_v>0 && bleach_v<200) { if(Choice_Bleach_th == false || (Choice_Bleach_th == true && Choice_Bleach_th_sign==false && bleach_v >= Bleach_th) || (Choice_Bleach_th == true && Choice_Bleach_th_sign==true && bleach_v < Bleach_th)) { DonPost=DonPost*(1 + Bleach_Control); // Ben's addition for corrections (2 lines) DonPost=DonPost+(DonPost-DonPre)*(AccPost/(AccPre-AccPost)); FRET_v=100*(DonPost-DonPre)/DonPost; if(Choice_FRET_th == false || (Choice_FRET_th == true && FRET_v >= FRET_th)) { //add the data to the arrays Data_px[count][1] =1; //ROIno Data_px[count][2] =i; //Xstart Data_px[count][3] =j; //Ystart DPre_px[count] =DonPre; //Dpre DPost_px[count] = DonPost; //DPost APre_px[count] = AccPre; //APre APost_px[count] =AccPost; //APost DA_ratio_px[count] =DonPost/AccPre; //D/A ratio Bleach_px[count]=bleach_v; //%bleaching FRET_px[count] =FRET_v; //%FRET FRET_to_plot[count]=(int) Math.round((double) 2.55*FRET_v); if (FRET_to_plot[count]>255) FRET_to_plot[count]=255; if (FRET_to_plot[count]<0) FRET_to_plot[count]=0; count++; } } } } } } //Statistical analysis via histograms ImageProcessor ip_FRET_His = new FloatProcessor(1,count,FRET_px); ImageProcessor ip_Bleach_His = new FloatProcessor(1,count,Bleach_px); ImageProcessor ip_DPre_His = new FloatProcessor(1,count,DPre_px); ImageProcessor ip_APre_His = new FloatProcessor(1,count,APre_px); ImageProcessor ip_DPost_His = new FloatProcessor(1,count,DPost_px); ImageProcessor ip_APost_His = new FloatProcessor(1,count,APost_px); ImageProcessor ip_DA_ratio_His = new FloatProcessor(1,count,DA_ratio_px); ImagePlus imp_FRET_His = new ImagePlus("Temp", ip_FRET_His); ImagePlus imp_Bleach_His = new ImagePlus("Temp", ip_Bleach_His); ImagePlus imp_DPre_His = new ImagePlus("Temp", ip_DPre_His); ImagePlus imp_APre_His = new ImagePlus("Temp", ip_APre_His); ImagePlus imp_DPost_His = new ImagePlus("Temp", ip_DPost_His); ImagePlus imp_APost_His = new ImagePlus("Temp", ip_APost_His); ImagePlus imp_DA_ratio_His = new ImagePlus("Temp", ip_DA_ratio_His); //Histograms output if(Choice_FRETHis==true) new HistogramWindow("FRET", imp_FRET_His, 50, ip_FRET_His.getMin(), ip_FRET_His.getMax()); if(Choice_DonHis==true) new HistogramWindow("Donor", imp_DPost_His, 50, 0, ip_DPost_His.getMax()); if(Choice_AccHis==true) new HistogramWindow("Acceptor", imp_APre_His, 50, 0, ip_APre_His.getMax()); // Plots output double [] stama=new double[1]; double [] stamb=new double[1]; ImageProcessor ip_FRET, ip_DonAcc; if (Choice_FRET == true) { stack.addSlice("%FRET", ip.createProcessor(width, height),stack.getSize()); ip_FRET = stack.getProcessor(stack.getSize()); for (int i=0; iSmooth command\n"+ "LUT->Rainbow2 - changes the LUT of each slice to Rainbow2\n"+ "Px by Px subtract - subtracts pixel-wise one slice from another and plots the result as a new slice\n"+ " \n"+ "Settings - allows input of the slice order and the thresholds for data analysis\n"+ "Options - allows choice of the output options\n"+ "Calculate - performs the calculation & outputs the results for the pre-selected rectangular ROI\n"+ " \n"+ "Save Image as - allows saving of the active image file only, Histograms, Results Table & ROIs should be saved separately\n"+ "Close - quits the FRETcalc plugin\n"); } notify(); } public void windowActivated(WindowEvent e) { } public void windowClosing(WindowEvent e) { dispose(); } public void windowClosed(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } public void windowDeiconified(WindowEvent e){ } public void windowIconified(WindowEvent e){ } public void windowOpened(WindowEvent e){ } }