Supplementary Software 2: BudJanalysis software
/*BudJ_
- Max cell radius (MaxCellRad), Max window for cell edge (MaxWinEdge)
and Min gray change at cell edge (PixelValRelMin) must be carefully
determined by user from the image stack before using BudJ
*/
import ij.*;
import ij.plugin.filter.*;
import ij.process.*;
import ij.gui.*;
import java.awt.event.*;
import java.awt.*;
import ij.measure.ResultsTable;
import ij.measure.Calibration;
import ij.measure.Measurements;
import ij.text.*;
import javax.swing.*;
public class BudJ_ implements PlugInFilter, MouseListener, KeyListener, ImageListener {
ImagePlus Img;
ImageCanvas Canvas;
ImageWindow ImgWin;
Overlay CurrentOverlay;
CellBJ CurrentCell;
String ImgName;
double ScaleFactor, TimeInt;
String ScaleUnit, TimeUnit;
int ImgWidth;
int ImgHeight;
int ChCnt;
int SliceCnt;
int TimeCnt;
int MaxCellRad; //To be set by user
int MaxWinEdge; //To be set by user
int EdgeRelMin; //To be set by user
double ClusterThresholdSD; //To be set by user
int FociRelMin; //To be set by user
int FociSizeMin; //To be set by user
int FociSizeMax; //To be set by user
int x;
int y;
int FirstX;
int FirstY;
int ClickTimeID, FirstClickTimeID, TimeID, MaxTimeID;
int ChID, BFChID, FL1ChID, FL2ChID, SliceID;
String[] FL1Option, FL2Option, TimeDirectionOption;
int FL1OpID, FL2OpID, TimeDirectionOpID;
ImageStatistics Stats;
double Bkg;
int[] CellCtr;
int CellGroup;
Color CurrentColor;
boolean NewCell;
boolean[] XBox;
ResultsTable CellData;
Panel TextPanel1, TextPanel2, ButtonPanel;
Label MessageLabel;
Button button1, button2, button3, button4, button5, button6, button7,button8;
Font ButtonFont, PressedButtonFont;
public int setup(String arg, ImagePlus Img) {
this.Img = Img;
return DOES_ALL+NO_CHANGES;
}
public void run(ImageProcessor ip) {
// Check whether BudJ is already running on image
String ImgName = Img.getTitle();
if (ImgName.length() > 7) {
String ImgTitleF7 = Img.getTitle().substring(0, 7);
if (ImgTitleF7.equals("BudJ on")) {
IJ.error("BudJ already running on this image!");
return;
}
}
Img.setTitle("BudJ on "+Img.getTitle());
// Get image scale
Calibration oc = Img.getCalibration().copy();
ScaleFactor = (float) oc.getX(1);
ScaleUnit=oc.getUnit();
if (ScaleFactor==0 | ScaleFactor==1 | ScaleUnit.equals("")) {
ScaleFactor=1;
ScaleUnit="pixel";
MaxCellRad=80;
MaxWinEdge=20;
} else {
MaxCellRad=4;
MaxWinEdge=1;
}
TimeInt = oc.frameInterval;
TimeUnit = oc.getTimeUnit();
if (TimeInt>30 & TimeUnit.equals("sec")) {
TimeInt=Math.round(TimeInt/60);
TimeUnit="min";
}
// Get image dimensions
int[] ImgDim = new int[5];
ImgDim = Img.getDimensions();
ImgWidth = ImgDim[0];
ImgHeight = ImgDim[1];
ChCnt = ImgDim[2];
SliceCnt = ImgDim[3];
TimeCnt = ImgDim[4];
// Guess BF channel
Bkg=0;
BFChID = 1;
for (int i = 1; i <= ChCnt; i++) {
Img.setPosition(i,1,1);
Img.setRoi(0,0,ImgWidth-1,ImgHeight-1);
Stats = Img.getStatistics();
if (Stats.dmode > Bkg) {
Bkg = Stats.dmode;
BFChID = i;
}
}
Img.killRoi();
for (int i = 1; i <= ChCnt; i++) {
if (i != BFChID) {
FL1ChID = i;
break;
}
}
for (int i = 1; i <= ChCnt; i++) {
if (i != BFChID & i != FL1ChID) {
FL2ChID = i;
break;
}
}
// Set other default option values
FL1OpID = 0;
FL2OpID = 0;
EdgeRelMin = 30;
ClusterThresholdSD = 2;
FociRelMin = 20;
FociSizeMin = 2;
FociSizeMax = 25;
MaxTimeID = TimeCnt;
TimeDirectionOpID = 0;
// Set user options
SetOptions();
// Panels for messages and buttons in image window
TextPanel1 = new Panel();
TextPanel1.add(new Label("Click cell to get data (hold SHIFT key to toggle groups 1 and 2)"));
MessageLabel=new Label("");
MessageLabel.setForeground(Color.RED);
Font MessageFont=new Font("SansSerif",Font.BOLD,16);
MessageLabel.setFont(MessageFont);
TextPanel1.add(MessageLabel);
TextPanel2 = new Panel();
TextPanel2.add(new Label("Use cursor keys to scroll through time"));
ButtonPanel = new Panel();
ButtonFont=new Font("SansSerif",Font.BOLD,12);
PressedButtonFont=new Font("SansSerif",Font.BOLD,18);
button1 = new Button(" New Cell ");
button1.setFont(ButtonFont);
button1.addMouseListener(this);
ButtonPanel.add(button1);
button2 = new Button(" 1 ");
button2.setForeground(Color.RED);
button2.setFont(PressedButtonFont);
button2.addMouseListener(this);
ButtonPanel.add(button2);
button3 = new Button(" 2 ");
button3.setForeground(Color.GREEN);
button3.setFont(ButtonFont);
button3.addMouseListener(this);
ButtonPanel.add(button3);
button4 = new Button(" 3 ");
button4.setForeground(Color.BLUE);
button4.setFont(ButtonFont);
button4.addMouseListener(this);
ButtonPanel.add(button4);
button5 = new Button(" 4 ");
button5.setForeground(Color.MAGENTA);
button5.setFont(ButtonFont);
button5.addMouseListener(this);
ButtonPanel.add(button5);
button6 = new Button(" Reset ");
button6.setFont(ButtonFont);
button6.addMouseListener(this);
ButtonPanel.add(button6);
button7 = new Button(" Set Data ");
button7.setFont(ButtonFont);
button7.addMouseListener(this);
ButtonPanel.add(button7);
button8 = new Button(" Exit ");
button8.setFont(ButtonFont);
button8.addMouseListener(this);
ButtonPanel.add(button8);
ImgWin = Img.getWindow();
ImgWin.add(TextPanel1);
ImgWin.add(TextPanel2);
ImgWin.add(ButtonPanel);
// ImgWin.setLocation(10,10);
ImgWin.pack();
ImgWin.setVisible(true);
// Enable Listeners
Canvas = ImgWin.getCanvas();
ImgWin.removeKeyListener(IJ.getInstance());
Canvas.removeKeyListener(IJ.getInstance());
ImgWin.addKeyListener(this);
Canvas.addKeyListener(this);
Canvas.addMouseListener(this);
Img.addImageListener(this);
Canvas.requestFocus();
}
protected void SetOptions() {
// Initialize FL options
FL1Option = new String[3];
FL1Option[0] = "Expression level";
FL1Option[1] = "Cluster index";
FL1Option[2] = "Foci data";
FL2Option = new String[3];
FL2Option[0] = "Expression level";
FL2Option[1] = "Cluster index";
FL2Option[2] = "Foci data";
TimeDirectionOption = new String[2];
TimeDirectionOption[0] = "Forward";
TimeDirectionOption[1] = "Reverse";
// Show initial dialog box
GenericDialog BudJDialog=new GenericDialog("BudJ dialog box");
Font HeadingFont=new Font("SansSerif",Font.BOLD,12);
BudJDialog.addMessage("BF channel parameters:",HeadingFont);
BudJDialog.addNumericField("BF channel",BFChID,0,2,"");
BudJDialog.addNumericField("Scale factor",ScaleFactor,4,6,ScaleUnit+"/pixel");
BudJDialog.addNumericField("Max cell radius",MaxCellRad,0,2,ScaleUnit);
BudJDialog.addNumericField("Max window for cell edge",MaxWinEdge,0,2,ScaleUnit);
BudJDialog.addNumericField(" Min gray change at cell edge",EdgeRelMin,0,2,"%");
if (ChCnt>1) {
BudJDialog.addMessage("Fluorescence channel 1 parameters:",HeadingFont);
BudJDialog.addNumericField("FL1 channel (0 to disable)",FL1ChID,0,2,"");
BudJDialog.addChoice("FL1 data",FL1Option,FL1Option[FL1OpID]);
if (ChCnt>2) {
BudJDialog.addMessage("Fluorescence channel 2 parameters:",HeadingFont);
BudJDialog.addNumericField("FL2 channel (0 to disable)",FL2ChID,0,2,"");
BudJDialog.addChoice("FL2 data",FL2Option,FL2Option[FL2OpID]);
}
BudJDialog.addMessage("Cluster and foci parameters:",HeadingFont);
BudJDialog.addNumericField("Cluster threshold",ClusterThresholdSD ,1,2,"sdev units");
BudJDialog.addNumericField("Min FL change at foci",FociRelMin,0,2,"%");
BudJDialog.addNumericField("Min foci size",FociSizeMin,0,2,"pixels");
BudJDialog.addNumericField("Max foci size",FociSizeMax,0,2,"pixels");
}
if (TimeCnt>1) {
BudJDialog.addMessage("Time lapse parameters:",HeadingFont);
BudJDialog.addNumericField("Time points to analyze",MaxTimeID,0,2,"");
BudJDialog.addStringField("Time unit", TimeUnit, 3);
BudJDialog.addNumericField("Time interval",TimeInt,0,2,"time units");
BudJDialog.addChoice("Time direction",TimeDirectionOption,TimeDirectionOption[TimeDirectionOpID]);
}
BudJDialog.hideCancelButton();
BudJDialog.showDialog();
// Get parameters set by user
BFChID = (int) BudJDialog.getNextNumber();
ScaleFactor = BudJDialog.getNextNumber();
MaxCellRad = (int) BudJDialog.getNextNumber();
MaxWinEdge = (int) BudJDialog.getNextNumber();
EdgeRelMin = (int) BudJDialog.getNextNumber();
if (ChCnt>1) {
FL1ChID = (int) BudJDialog.getNextNumber();
FL1OpID = BudJDialog.getNextChoiceIndex();
if (ChCnt>2) {
FL2ChID = (int) BudJDialog.getNextNumber();
FL2OpID = BudJDialog.getNextChoiceIndex();
} else {
FL2ChID = 0;
FL2OpID = 0;
}
ClusterThresholdSD = BudJDialog.getNextNumber();
FociRelMin = (int) BudJDialog.getNextNumber();
FociSizeMin = (int) BudJDialog.getNextNumber();
FociSizeMax = (int) BudJDialog.getNextNumber();
} else {
FL1ChID = 0;
FL1OpID = 0;
}
if (TimeCnt>1) {
MaxTimeID = (int) BudJDialog.getNextNumber();
TimeUnit = BudJDialog.getNextString();
TimeInt = BudJDialog.getNextNumber();
TimeDirectionOpID = BudJDialog.getNextChoiceIndex();
} else {
MaxTimeID = TimeCnt;
TimeDirectionOpID = 0;
}
// Initialize other parameters
FirstClickTimeID=1;
SliceID = 1;
CellCtr = new int[5];
for (int i=1; i<=4; i++) CellCtr[i] = 0;
NewCell = true;
CellGroup=1;
CurrentColor = Color.red;
CurrentOverlay = new Overlay();
Img.setOverlay(CurrentOverlay);
Img.setPosition(BFChID,SliceID,FirstClickTimeID);
// Initialize CellBJ object
CurrentCell=new CellBJ();
CurrentCell.Img=Img;
CurrentCell.Canvas=Canvas;
CurrentCell.MaxCellRad=MaxCellRad;
CurrentCell.MaxWinEdge=MaxWinEdge;
CurrentCell.EdgeRelMin=EdgeRelMin;
CurrentCell.ClusterThresholdSD = ClusterThresholdSD;
CurrentCell.FociRelMin = FociRelMin;
CurrentCell.FociSizeMin = FociSizeMin;
CurrentCell.FociSizeMax = FociSizeMax;
CurrentCell.ScaleFactor=ScaleFactor;
CurrentCell.ScaleUnit=ScaleUnit;
CurrentCell.ImgWidth=ImgWidth;
CurrentCell.ImgHeight=ImgHeight;
CurrentCell.ChCnt=ChCnt;
CurrentCell.BFChID=BFChID;
CurrentCell.FL1ChID=FL1ChID;
CurrentCell.FL2ChID=FL2ChID;
CurrentCell.FL1OpID=FL1OpID;
CurrentCell.FL2OpID=FL2OpID;
// Set data measurements
XBox = new boolean[30];
for (int i = 0; i < 30; i++) XBox[i]=true;
SetData();
}
protected void SetData() {
// Show data dialog box
GenericDialog DataDialog=new GenericDialog("Data dialog box");
Font HeadingFont=new Font("SansSerif",Font.BOLD,12);
DataDialog.addCheckbox("cell group",XBox[0]);
DataDialog.addCheckbox("cell #",XBox[1]);
DataDialog.addCheckbox("time frame #",XBox[2]);
DataDialog.addCheckbox("time ("+TimeUnit+")",XBox[3]);
DataDialog.addCheckbox("centroid X",XBox[4]);
DataDialog.addCheckbox("centroid Y",XBox[5]);
DataDialog.addCheckbox("major radius",XBox[6]);
DataDialog.addCheckbox("minor radius",XBox[7]);
DataDialog.addCheckbox("ellipse angle",XBox[8]);
DataDialog.addCheckbox("edge index",XBox[9]);
DataDialog.addCheckbox("cell volume",XBox[10]);
if (FL1ChID>0) {
switch (FL1OpID) {
case 0:
DataDialog.addCheckbox("FL1 FL stats",XBox[11]);
break;
case 1:
DataDialog.addCheckbox("FL1 cluster index",XBox[12]);
DataDialog.addCheckbox("FL1 cluster FL stats",XBox[13]);
break;
case 2:
DataDialog.addCheckbox("FL1 foci",XBox[14]);
DataDialog.addCheckbox("FL1 doublets",XBox[15]);
DataDialog.addCheckbox("FL1 foci size",XBox[16]);
DataDialog.addCheckbox("FL1 foci FL stats",XBox[17]);
break;
}
}
if (FL2ChID>0) {
switch (FL2OpID) {
case 0:
DataDialog.addCheckbox("FL2 FL stats",XBox[21]);
break;
case 1:
DataDialog.addCheckbox("FL2 cluster index",XBox[22]);
DataDialog.addCheckbox("FL2 cluster FL stats",XBox[23]);
break;
case 2:
DataDialog.addCheckbox("FL2 foci",XBox[24]);
DataDialog.addCheckbox("FL2 doublets",XBox[25]);
DataDialog.addCheckbox("FL2 foci size",XBox[26]);
DataDialog.addCheckbox("FL2 foci FL stats",XBox[27]);
break;
}
}
DataDialog.hideCancelButton();
DataDialog.showDialog();
for (int i = 0; i <= 10; i++) XBox[i]=DataDialog.getNextBoolean();
if (FL1ChID>0) {
switch (FL1OpID) {
case 0:
XBox[11]=DataDialog.getNextBoolean();
break;
case 1:
for (int i = 12; i <=13; i++) XBox[i]=DataDialog.getNextBoolean();
break;
case 2:
for (int i = 14; i <=17; i++) XBox[i]=DataDialog.getNextBoolean();
break;
}
}
if (FL2ChID>0) {
switch (FL2OpID) {
case 0:
XBox[21]=DataDialog.getNextBoolean();
break;
case 1:
for (int i = 22; i <=23; i++) XBox[i]=DataDialog.getNextBoolean();
break;
case 2:
for (int i = 24; i <=27; i++) XBox[i]=DataDialog.getNextBoolean();
break;
}
}
// Prepare results table
CellData = new ResultsTable();
CellData.reset();
CellData.setPrecision(2);
}
// To implement the interface we have to implement the five methods it declares. We only want to react on clicks so we can leave the others empty.
// We get the coordinates of the point of the mouse click from the event object that is passed to the method.
// The image could be scaled in the window so we use the offScreenX() and offScreenY() method of ImageCanvas to receive the true coordinates.
public void mouseClicked(MouseEvent e) {
MessageLabel.setText("");
ImgWin.pack();
Object b = e.getSource();
if (b==button1) {
NewCell=true;
Img.setPosition(BFChID,SliceID,FirstClickTimeID);
Canvas.requestFocus();
return;
}
if (b==button2) {
NewCell=true;
Img.setPosition(BFChID,SliceID,FirstClickTimeID);
CellGroup=1;
CurrentColor = Color.red;
button2.setFont(PressedButtonFont);
button3.setFont(ButtonFont);
button4.setFont(ButtonFont);
button5.setFont(ButtonFont);
ImgWin.pack();
Canvas.requestFocus();
return;
}
if (b==button3) {
NewCell=true;
Img.setPosition(BFChID,SliceID,FirstClickTimeID);
CellGroup=2;
CurrentColor = Color.green;
button2.setFont(ButtonFont);
button3.setFont(PressedButtonFont);
button4.setFont(ButtonFont);
button5.setFont(ButtonFont);
ImgWin.pack();
Canvas.requestFocus();
return;
}
if (b==button4) {
NewCell=true;
Img.setPosition(BFChID,SliceID,FirstClickTimeID);
CellGroup=3;
CurrentColor = Color.blue;
button2.setFont(ButtonFont);
button3.setFont(ButtonFont);
button4.setFont(PressedButtonFont);
button5.setFont(ButtonFont);
ImgWin.pack();
Canvas.requestFocus();
return;
}
if (b==button5) {
NewCell=true;
Img.setPosition(BFChID,SliceID,FirstClickTimeID);
CellGroup=4;
CurrentColor = Color.magenta;
button2.setFont(ButtonFont);
button3.setFont(ButtonFont);
button4.setFont(ButtonFont);
button5.setFont(PressedButtonFont);
ImgWin.pack();
Canvas.requestFocus();
return;
}
if (b==button6) {
if (IJ.showMessageWithCancel("BudJ","Click OK to re-initiate BudJ on this image")) {
SetOptions();
}
Canvas.requestFocus();
return;
}
if (b==button7) {
if (IJ.showMessageWithCancel("BudJ","Click OK to set measurement data on this image")) {
SetData();
}
Canvas.requestFocus();
return;
}
if (b==button8) {
if (IJ.showMessageWithCancel("BudJ","Click OK to exit BudJ")) {
// Disable Listeners, close windows and exit
Canvas.removeMouseListener(this);
Canvas.removeKeyListener(this);
ImgWin.removeKeyListener(this);
Img.close();
}
Canvas.requestFocus();
return;
}
if (e.isShiftDown()) {
NewCell=true;
if (CellGroup==1) {
CellGroup=2;
CurrentColor = Color.green;
button1.setFont(ButtonFont);
button2.setFont(PressedButtonFont);
button3.setFont(ButtonFont);
button4.setFont(ButtonFont);
ImgWin.pack();
} else {
CellGroup=1;
CurrentColor = Color.red;
button1.setFont(PressedButtonFont);
button2.setFont(ButtonFont);
button3.setFont(ButtonFont);
button4.setFont(ButtonFont);
ImgWin.pack();
}
}
Canvas.requestFocus();
// Do not go on if zoom tool
if (Toolbar.getToolId()==11) return;
x = e.getX();
y = e.getY();
FirstX = Canvas.offScreenX(x);
FirstY = Canvas.offScreenY(y);
ClickTimeID = Img.getFrame();
// Obtain centroid coordinates of first TimeID
Img.setPosition(BFChID,SliceID,ClickTimeID);
CurrentCell.FirstX=FirstX;
CurrentCell.FirstY=FirstY;
CurrentCell.TimeID=ClickTimeID;
CurrentCell.GetData=false;
CurrentCell.GetCellData();
if (CurrentCell.CellFound) {
FirstX = (int) (CurrentCell.XCentroid/ScaleFactor);
FirstY = (int) (CurrentCell.YCentroid/ScaleFactor);
} else {
MessageLabel.setText("Cell not found!");
ImgWin.pack();
return;
}
TimeID=ClickTimeID;
boolean TimeOK=true;
while (TimeOK) {
// Initialize variable parameters of CellBJ object
CurrentCell.FirstX=FirstX;
CurrentCell.FirstY=FirstY;
CurrentCell.TimeID=TimeID;
CurrentCell.GetData=true;
CurrentCell.GetCellData();
if (CurrentCell.CellFound) {
// Plot ROI and trail
if (NewCell) {
CellCtr[CellGroup] = CellCtr[CellGroup] + 1;
NewCell = false;
FirstClickTimeID = ClickTimeID;
CurrentCell.EllipseRoi.setStrokeColor(CurrentColor);
CurrentOverlay.add (CurrentCell.EllipseRoi);
String CellCtrStr=Integer.toString(CellCtr[CellGroup]);
Font RoiFont=new Font("SansSerif",Font.BOLD,16);
TextRoi RoiLabel=new TextRoi((int) (CurrentCell.XCentroid/ScaleFactor),
(int)(CurrentCell.YCentroid/ScaleFactor),CellCtrStr,RoiFont);
RoiLabel.setStrokeColor(CurrentColor);
CurrentOverlay.add(RoiLabel);
} else {
Line CurrentLine=new Line(FirstX,FirstY,(int) (CurrentCell.XCentroid/ScaleFactor),
(int) (CurrentCell.YCentroid/ScaleFactor));;
CurrentLine.setStrokeColor(CurrentColor);
CurrentOverlay.add(CurrentLine);
}
Img.updateAndDraw();
FirstX = (int) (CurrentCell.XCentroid/ScaleFactor);
FirstY = (int) (CurrentCell.YCentroid/ScaleFactor);
// Add data to table
CellData.incrementCounter();
if (XBox[0]) CellData.addValue("Group",CellGroup);
if (XBox[1]) CellData.addValue("Cell",CellCtr[CellGroup]);
if (XBox[2]) CellData.addValue("TimeID",TimeID);
if (XBox[3]) CellData.addValue("time ("+TimeUnit+")",TimeInt*(TimeID-1));
if (XBox[4]) CellData.addValue("x",CurrentCell.XCentroid);
if (XBox[5]) CellData.addValue("y",CurrentCell.YCentroid);
if (XBox[6]) CellData.addValue("major R",CurrentCell.Major);
if (XBox[7]) CellData.addValue("minor r",CurrentCell.Minor);
if (XBox[8]) CellData.addValue("angle",CurrentCell.Angle);
if (XBox[9]) CellData.addValue("edge",CurrentCell.Edge);
if (XBox[10]) CellData.addValue("volume",CurrentCell.Volume);
if (FL1ChID>0) {
switch (FL1OpID) {
case 0:
if (XBox[11]) {
CellData.addValue("FL1 FL mean",CurrentCell.FL1Mean);
CellData.addValue("FL1 FL sdev",CurrentCell.FL1SDev);
}
break;
case 1:
if (XBox[12]) CellData.addValue("FL1 cluster index",CurrentCell.FL1Cluster);
if (XBox[13]) {
CellData.addValue("FL1 cluster FL mean",CurrentCell.FL1ClusterMean);
CellData.addValue("FL1 cluster FL sdev",CurrentCell.FL1ClusterSDev);
}
break;
case 2:
if (XBox[14]) CellData.addValue("FL1 foci",CurrentCell.FL1Foci);
if (XBox[15]) CellData.addValue("FL1 doublets",CurrentCell.FL1FociDoublets);
if (XBox[16]) {
CellData.addValue("FL1 foci size mean",CurrentCell.FL1FociSizeMean);
CellData.addValue("FL1 foci size sdev",CurrentCell.FL1FociSizeSDev);
}
if (XBox[17]) {
CellData.addValue("FL1 foci FL mean",CurrentCell.FL1FociMean);
CellData.addValue("FL1 foci FL sdev",CurrentCell.FL1FociSDev);
}
break;
}
}
if (FL2ChID>0) {
switch (FL2OpID) {
case 0:
if (XBox[21]) {
CellData.addValue("FL2 FL mean",CurrentCell.FL2Mean);
CellData.addValue("FL2 FL sdev",CurrentCell.FL2SDev);
}
break;
case 1:
if (XBox[22]) CellData.addValue("FL2 cluster index",CurrentCell.FL2Cluster);
if (XBox[23]) {
CellData.addValue("FL2 cluster FL mean",CurrentCell.FL2ClusterMean);
CellData.addValue("FL2 cluster FL sdev",CurrentCell.FL2ClusterSDev);
}
break;
case 2:
if (XBox[24]) CellData.addValue("FL2 foci",CurrentCell.FL2Foci);
if (XBox[25]) CellData.addValue("FL2 doublets",CurrentCell.FL2FociDoublets);
if (XBox[26]) {
CellData.addValue("FL2 foci size mean",CurrentCell.FL2FociSizeMean);
CellData.addValue("FL2 foci size sdev",CurrentCell.FL2FociSizeSDev);
}
if (XBox[27]) {
CellData.addValue("FL2 foci FL mean",CurrentCell.FL2FociMean);
CellData.addValue("FL2 foci FL sdev",CurrentCell.FL2FociSDev);
}
break;
}
}
CellData.show(Img.getTitle()+" Results");
} else {
if (NewCell) MessageLabel.setText("Cell not found!");
else MessageLabel.setText("Cell lost at frame "+TimeID);
ImgWin.pack();
Canvas.requestFocus();
return;
}
if (TimeDirectionOpID==0) {
TimeID++;
if (TimeID >= FirstClickTimeID+MaxTimeID | TimeID > TimeCnt) TimeOK = false;
} else {
TimeID = TimeID - 1;
if (TimeID <= FirstClickTimeID-MaxTimeID | TimeID < 1) TimeOK = false;
}
}
NewCell = true;
Img.setPosition(BFChID,SliceID,FirstClickTimeID);
Canvas.requestFocus();
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void keyPressed(KeyEvent e) {
TimeID = Img.getFrame();
ChID = Img.getChannel();
int keyCode = e.getKeyCode();
switch (keyCode) {
case 37:
if (TimeID > 0) TimeID = TimeID - 1;
Img.setPosition(ChID,SliceID,TimeID);
break;
case 39:
if (TimeID < TimeCnt) TimeID = TimeID + 1;
Img.setPosition(ChID,SliceID,TimeID);
break;
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public void imageClosed(ImagePlus Img) {
Canvas.removeMouseListener(this);
Canvas.removeKeyListener(this);
ImgWin.removeKeyListener(this);
Img.removeImageListener(this);
}
public void imageUpdated(ImagePlus Img) {}
public void imageOpened(ImagePlus Img) {}
}
//CellBJ class
import ij.*;
import ij.plugin.filter.*;
import ij.process.*;
import ij.gui.*;
import java.awt.event.*;
import java.awt.*;
import ij.measure.ResultsTable;
import ij.measure.Calibration;
import ij.measure.Measurements;
import ij.text.TextWindow;
public class CellBJ {
// Required parameters
public ImagePlus Img;
public ImageCanvas Canvas;
public int MaxCellRad;
public int MaxWinEdge;
public int EdgeRelMin;
public double ClusterThresholdSD;
public int FociRelMin;
public int FociSizeMin;
public int FociSizeMax;
public int FirstX, FirstY;
public int ImgWidth, ImgHeight;
public double ScaleFactor;
public String ScaleUnit;
public int TimeID, BFChID;
public int FL1ChID, FL2ChID;
public int FL1OpID, FL2OpID;
public int ChCnt;
public boolean GetData;
// Produced parameters
public boolean CellFound;
public Roi ItsRoi;
public Roi EllipseRoi;
public double XCentroid;
public double YCentroid;
public double Major;
public double Minor;
public double Angle;
public double Edge;
public double Volume;
public double FL1Mean, FL2Mean;
public double FL1SDev, FL2SDev;
public double FL1Cluster, FL2Cluster;
public double FL1ClusterMean, FL2ClusterMean;
public double FL1ClusterSDev, FL2ClusterSDev;
public double FL1Foci, FL2Foci;
public double FL1FociMean, FL2FociMean;
public double FL1FociSDev, FL2FociSDev;
public double FL1FociSizeMean, FL2FociSizeMean;
public double FL1FociSizeSDev, FL2FociSizeSDev;
public double FL1FociDoublets, FL2FociDoublets;
// Other variables and objects
int MaxInc;
int MaxWinInc;
double PI;
int VectorAngle;
int PixelFoundCtr;
boolean[] PixelFound;
int[] FoundX;
int[] FoundY;
int[] FoundRad;
int[] FoundDif;
int[] FoundPtrDif;
int[] FoundSlope;
int[] ThisPixelValue;
int[] VectorX;
int[] VectorY;
int[] VectorPixelValue;
int Inc, WinInc;
int LimitPtr, CurrentMaxPtr, CurrentMinPtr, PtrDif;
int MaxDif, CurrentDif;
int PixelValRelDif;
int MeanPixelValue;
double MeanRad, SDevRad;
double MeanDif, SDevDif;
double MeanPtrDif;
double MeanSlope, SDevSlope;
int WinFoundCtr, PixelJumpedCtr;
Polygon CurrentPolygon;
ImageStatistics Stats;
Ellipse CurrentEllipse;
double alpha, beta;
double sinalpha, cosalpha;
double sinbeta, cosbeta;
Rectangle EllipseBounds;
double BFBkg, FLBkg;
int MaxPixelArea;
int[] DensPixelValue;
int XCoor, YCoor, XMin, YMin, XMax, YMax;
int SumX, SumY;
int MeanX, MeanY;
double MeanDoubleDist;
int XDif, YDif;
public void GetCellData() {
// Select subimage
Img.setPosition(BFChID,1,TimeID);
// Initialize used parameters
MaxInc = (int) Math.round(MaxCellRad/ScaleFactor);
MaxWinInc = (int) Math.round(MaxWinEdge/ScaleFactor);
PI=Math.PI;
// Create arrays
VectorX = new int[MaxInc+1];
VectorY = new int[MaxInc+1];
VectorPixelValue = new int[MaxInc+1];
FoundX = new int[360];
FoundY = new int[360];
FoundRad = new int[360];
FoundDif = new int[360];
FoundPtrDif = new int[360];
FoundSlope = new int[360];
PixelFound = new boolean[360];
ThisPixelValue = new int[4];
CellFound = true;
PixelFoundCtr = 0;
// Get background value for BFCh
Img.setRoi(0,0,ImgWidth-1,ImgHeight-1);
Stats = Img.getStatistics();
BFBkg=Stats.dmode;