/******************************************************
ParticlePicker V1.0
9-2-2003
*******************************************************/
import ij.gui.GUI;
import ij.gui.ImageCanvas;
import ij.gui.Roi;
import ij.gui.Toolbar;
import ij.gui.GenericDialog;
import ij.IJ;
import ij.ImagePlus;
import ij.measure.Calibration;
import ij.plugin.PlugIn;
import ij.WindowManager;
import java.awt.Button;
import java.awt.Canvas;
import java.awt.CheckboxGroup;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Event;
import java.awt.FileDialog;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Label;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.InputEvent;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Vector;
import ij.plugin.filter.ParticleAnalyzer;
import ij.process.ImageProcessor;
import ij.process.ImageStatistics;
import java.awt.image.*;
import ij.LookUpTable;
/*====================================================================
| ParticlePicker_
\===================================================================*/
/*********************************************************************
* This class is the only one that is accessed directly by imageJ;
* it attaches listeners and dies. Note that it implements
* PlugIn
rather than PlugInFilter
.
********************************************************************/
public class ParticlePicker_
implements
PlugIn
{ /* begin class ParticlePicker_ */
/*..................................................................*/
/* Public methods */
/*..................................................................*/
/*------------------------------------------------------------------*/
public void run (
final String arg
) {
final ImagePlus imp = WindowManager.getCurrentImage();
if (imp == null) {
IJ.noImage();
return;
}
final ImageCanvas ic = imp.getWindow().getCanvas();
final ParticleToolbar tb = new ParticleToolbar(Toolbar.getInstance());
final ParticleHandler ph = new ParticleHandler(imp, tb);
tb.setWindow(ph, imp);
} /* end run */
} /* end class ParticlePicker_ */
/*====================================================================
| ParticleAction
\===================================================================*/
/*********************************************************************
* This class is responsible for dealing with the mouse events relative
* to the image window.
********************************************************************/
class ParticleAction
extends
ImageCanvas
implements
KeyListener,
MouseListener,
MouseMotionListener
{ /* begin class ParticleAction */
/*....................................................................
Public variables
....................................................................*/
public static final int ADD_CIRCLE = 0;
public static final int MOVE_CIRCLE = 1;
public static final int FILE = 2;
public static final int TERMINATE = 5;
public static final int MAGNIFIER = 11;
public static final int FINDER = 3;
public static final int CLUSTER = 4;
public static final int HAND = 12;
/*....................................................................
Private variables
....................................................................*/
private ImagePlus imp;
private ParticleHandler ph;
private ParticleToolbar tb;
private boolean frontmost = false;
/*....................................................................
Public methods
....................................................................*/
/*********************************************************************
* Return true if the window is frontmost.
********************************************************************/
public boolean isFrontmost (
) {
return(frontmost);
} /* end isFrontmost */
/*********************************************************************
* Listen to keyPressed
events.
*
* @param e The expected key codes are as follows:
*
KeyEvent.VK_DELETE
: remove the current landmark;KeyEvent.VK_BACK_SPACE
: remove the current landmark;KeyEvent.VK_DOWN
: move down the current landmark;KeyEvent.VK_LEFT
: move the current landmark to the left;KeyEvent.VK_RIGHT
: move the current landmark to the right;KeyEvent.VK_TAB
: activate the next landmark;KeyEvent.VK_UP
: move up the current landmark.keyReleased
events.
*
* @param e Ignored.
********************************************************************/
public void keyReleased (
final KeyEvent e
) {
frontmost = true;
} /* end keyReleased */
/*********************************************************************
* Listen to keyTyped
events.
*
* @param e Ignored.
********************************************************************/
public void keyTyped (
final KeyEvent e
) {
frontmost = true;
} /* end keyTyped */
/*********************************************************************
* Listen to mouseClicked
events.
*
* @param e Ignored.
********************************************************************/
public void mouseClicked (
final MouseEvent e
) {
frontmost = true;
} /* end mouseClicked */
/*********************************************************************
* Listen to mouseDragged
events. Move the current point
* and refresh the image window.
*
* @param e Event.
********************************************************************/
public void mouseDragged (
final MouseEvent e
) {
frontmost = true;
final int x = e.getX();
final int y = e.getY();
if (tb.getCurrentTool() == MOVE_CIRCLE) {
ph.movePoint(x, y);
imp.setRoi(ph);
}
mouseMoved(e);
} /* end mouseDragged */
/*********************************************************************
* Listen to mouseEntered
events.
*
* @param e Ignored.
********************************************************************/
public void mouseEntered (
final MouseEvent e
) {
frontmost = true;
WindowManager.setCurrentWindow(imp.getWindow());
imp.getWindow().toFront();
imp.setRoi(ph);
} /* end mouseEntered */
/*********************************************************************
* Listen to mouseExited
events. Clear the ImageJ status
* bar.
*
* @param e Event.
********************************************************************/
public void mouseExited (
final MouseEvent e
) {
frontmost = false;
imp.getWindow().toBack();
IJ.getInstance().toFront();
imp.setRoi(ph);
IJ.showStatus("");
} /* end mouseExited */
/*********************************************************************
* Listen to mouseMoved
events. Update the ImageJ status
* bar.
*
* @param e Event.
********************************************************************/
public void mouseMoved (
final MouseEvent e
) {
frontmost = true;
setControl();
final int x = imp.getWindow().getCanvas().offScreenX(e.getX());
final int y = imp.getWindow().getCanvas().offScreenY(e.getY());
IJ.showStatus(imp.getLocationAsString(x, y) + getValueAsString(x, y));
} /* end mouseMoved */
/*********************************************************************
* Listen to mousePressed
events. Perform the relevant
* action.
*
* @param e Event.
********************************************************************/
public void mousePressed (
final MouseEvent e
) {
frontmost = true;
final int x = e.getX();
final int y = e.getY();
int currentPoint;
switch (tb.getCurrentTool()) {
case ADD_CIRCLE:
if(e.getModifiers()==InputEvent.BUTTON1_MASK) {
ph.addPoint(imp.getWindow().getCanvas().offScreenX(x),
imp.getWindow().getCanvas().offScreenY(y));
ph.FNone();
}
if(e.getModifiers()==InputEvent.BUTTON3_MASK) {
ph.findClosest(x, y);
ph.removePoint();
ph.FPone();
}
break;
case MAGNIFIER:
final int flags = e.getModifiers();
if ((flags & (Event.ALT_MASK | Event.META_MASK | Event.CTRL_MASK)) != 0) {
imp.getWindow().getCanvas().zoomOut(x, y);
}
else {
imp.getWindow().getCanvas().zoomIn(x, y);
}
break;
case MOVE_CIRCLE:
ph.findClosest(x, y);
break;
case HAND:
int ox = imp.getWindow().getCanvas().offScreenX(x);
int oy = imp.getWindow().getCanvas().offScreenY(y);
//scroll(ox,oy);
break;
}
imp.setRoi(ph);
} /* end mousePressed */
/*********************************************************************
* Listen to mouseReleased
events.
*
* @param e Ignored.
********************************************************************/
public void mouseReleased (
final MouseEvent e
) {
frontmost = true;
} /* end mouseReleased */
/*********************************************************************
* This constructor stores a local copy of its parameters and initializes
* the current control.
*
* @param imp ImagePlus object where points are being picked.
* @param ph pointHandler object that handles operations.
* @param tb pointToolbar object that handles the toolbar.
********************************************************************/
public ParticleAction (
final ImagePlus imp,
final ParticleHandler ph,
final ParticleToolbar tb
) {
super(imp);
this.imp = imp;
this.ph = ph;
this.tb = tb;
} /* end ParticleAction */
/*....................................................................
Private methods
....................................................................*/
/*------------------------------------------------------------------*/
private String getValueAsString (
final int x,
final int y
) {
final Calibration cal = imp.getCalibration();
final int[] v = imp.getPixel(x, y);
switch (imp.getType()) {
case ImagePlus.GRAY8:
case ImagePlus.GRAY16:
final double cValue = cal.getCValue(v[0]);
if (cValue==v[0]) {
return(", value=" + v[0]);
}
else {
return(", value=" + IJ.d2s(cValue) + " (" + v[0] + ")");
}
case ImagePlus.GRAY32:
return(", value=" + Float.intBitsToFloat(v[0]));
case ImagePlus.COLOR_256:
return(", index=" + v[3] + ", value=" + v[0] + "," + v[1] + "," + v[2]);
case ImagePlus.COLOR_RGB:
return(", value=" + v[0] + "," + v[1] + "," + v[2]);
default:
return("");
}
} /* end getValueAsString */
/*------------------------------------------------------------------*/
private void setControl (
) {
switch (tb.getCurrentTool()) {
case ADD_CIRCLE:
imp.getWindow().getCanvas().setCursor(crosshairCursor);
break;
case FILE:
case MAGNIFIER:
case MOVE_CIRCLE:
imp.getWindow().getCanvas().setCursor(defaultCursor);
break;
}
} /* end setControl */
} /* end class ParticleAction */
/*====================================================================
| ParticleHandler
\===================================================================*/
/*********************************************************************
* This class is responsible for dealing with the list of point
* coordinates and for their visual appearance.
********************************************************************/
class ParticleHandler
extends
Roi
{ /* begin class ParticleHandler */
private int CIRCLE_HALFSIZE = 2;
private final Vector listPoints = new Vector(512, 512);
private ImagePlus imp;
private ParticleAction pa;
private ParticleToolbar tb;
private int currentPoint = -1;
private int numPoints = 0;
private boolean started = false;
private int fp =0;
private int fn =0;
/*....................................................................
Public methods
....................................................................*/
/*********************************************************************
* This method adds a new point to the list, with a color that is as
* different as possible from all those that are already in use. The
* points are stored in pixel units rather than canvas units to cope
* for different zooming factors.
*
* @param x Horizontal coordinate, in canvas units.
* @param y Vertical coordinate, in canvas units.
********************************************************************/
public void addPoint (
final int x,
final int y
) {
final Point p = new Point(x, y);
listPoints.addElement(p);
currentPoint = numPoints;
numPoints++;
} /* end addPoint */
/*********************************************************************
* Restore the listeners
********************************************************************/
public void cleanUp (
) {
removePoints();
final ImageCanvas ic = imp.getWindow().getCanvas();
ic.removeKeyListener(pa);
ic.removeMouseListener(pa);
ic.removeMouseMotionListener(pa);
ic.addMouseMotionListener(ic);
ic.addMouseListener(ic);
ic.addKeyListener(IJ.getInstance());
} /* end cleanUp */
/*********************************************************************
* Draw the landmarks and outline the current point if there is one.
*
* @param g Graphics environment.
********************************************************************/
public void draw (
final Graphics g
) {
if (started) {
final float mag = (float)ic.getMagnification();
Calibration cal = imp.getCalibration();
double oldScale = cal.pixelWidth!=0?1.0/cal.pixelWidth:0;
//CIRCLE_HALFSIZE = (int) oldScale*2/137;
CIRCLE_HALFSIZE = 5;
int radius;
final int dx = (int)(mag / 2.0);
final int dy = (int)(mag / 2.0);
for (int k = 0; (k < listPoints.size()); k++) {
final Point p = (Point)listPoints.elementAt(k);
radius = ic.screenX(p.x+CIRCLE_HALFSIZE)-ic.screenX(p.x-CIRCLE_HALFSIZE);
g.setColor(Color.red);
if (k == currentPoint) {
if (pa.isFrontmost()) {
g.drawLine(ic.screenX(p.x - CIRCLE_HALFSIZE) + dx,
ic.screenY(p.y) + dy,
ic.screenX(p.x + CIRCLE_HALFSIZE) + dx,
ic.screenY(p.y) + dy);
g.drawLine(ic.screenX(p.x) + dx,
ic.screenY(p.y - CIRCLE_HALFSIZE) + dy,
ic.screenX(p.x) + dx,
ic.screenY(p.y + CIRCLE_HALFSIZE) + dy);
g.drawOval(ic.screenX(p.x-CIRCLE_HALFSIZE) + dx,
ic.screenY(p.y-CIRCLE_HALFSIZE) + dy,
radius,radius);
}
else {
g.drawLine(ic.screenX(p.x - CIRCLE_HALFSIZE + 1) + dx,
ic.screenY(p.y - CIRCLE_HALFSIZE + 1) + dy,
ic.screenX(p.x + CIRCLE_HALFSIZE - 1) + dx,
ic.screenY(p.y + CIRCLE_HALFSIZE - 1) + dy);
g.drawLine(ic.screenX(p.x - CIRCLE_HALFSIZE + 1) + dx,
ic.screenY(p.y + CIRCLE_HALFSIZE - 1) + dy,
ic.screenX(p.x + CIRCLE_HALFSIZE - 1) + dx,
ic.screenY(p.y - CIRCLE_HALFSIZE + 1) + dy);
g.drawOval(ic.screenX(p.x-CIRCLE_HALFSIZE) + dx,
ic.screenY(p.y-CIRCLE_HALFSIZE) + dy,
radius,radius);
}
}
else {
g.drawOval(ic.screenX(p.x-CIRCLE_HALFSIZE) + dx,
ic.screenY(p.y-CIRCLE_HALFSIZE) + dy,
radius,radius);
}
}
if (updateFullWindow) {
updateFullWindow = false;
imp.draw();
}
}
} /* end draw */
/*********************************************************************
* Let the point that is closest to the given coordinates become the
* current landmark.
*
* @param x Horizontal coordinate, in canvas units.
* @param y Vertical coordinate, in canvas units.
********************************************************************/
public void findClosest (
int x,
int y
) {
if (listPoints.size() == 0) {
currentPoint = -1;
return;
}
x = ic.offScreenX(x);
y = ic.offScreenY(y);
Point p = new Point((Point)listPoints.elementAt(currentPoint));
float distance = (float)(x - p.x) * (float)(x - p.x)
+ (float)(y - p.y) * (float)(y - p.y);
for (int k = 0; (k < listPoints.size()); k++) {
p = (Point)listPoints.elementAt(k);
final float candidate = (float)(x - p.x) * (float)(x - p.x)
+ (float)(y - p.y) * (float)(y - p.y);
if (candidate < distance) {
distance = candidate;
currentPoint = k;
}
}
} /* end findClosest */
/*********************************************************************
* Return the current point as a Point
object.
********************************************************************/
public Point getPoint (
) {
return((0 <= currentPoint) ? (Point)listPoints.elementAt(currentPoint) : (null));
} /* end getPoint */
/*********************************************************************
* Return the list of points.
********************************************************************/
public Vector getPoints (
) {
return(listPoints);
} /* end getPoints */
public int getNum(){
return numPoints;
}
public int getFP(){
return fp;
}
public int getFN(){
return fn;
}
public void FPone(){
fp++;
}
public void FNone(){
fn++;
}
/*********************************************************************
* Modify the location of the current point. Clip the admissible range
* to the image size.
*
* @param x Desired new horizontal coordinate in canvas units.
* @param y Desired new vertical coordinate in canvas units.
********************************************************************/
public void movePoint (
int x,
int y
) {
if (0 <= currentPoint) {
x = ic.offScreenX(x);
y = ic.offScreenY(y);
x = (x < 0) ? (0) : (x);
x = (imp.getWidth() <= x) ? (imp.getWidth() - 1) : (x);
y = (y < 0) ? (0) : (y);
y = (imp.getHeight() <= y) ? (imp.getHeight() - 1) : (y);
listPoints.removeElementAt(currentPoint);
final Point p = new Point(x, y);
listPoints.insertElementAt(p, currentPoint);
}
} /* end movePoint */
/*********************************************************************
* Change the current point.
********************************************************************/
public void nextPoint (
) {
currentPoint = (currentPoint == (numPoints - 1)) ? (0) : (currentPoint + 1);
} /* end nextPoint */
/*********************************************************************
* This constructor stores a local copy of its parameters and initializes
* the current spectrum. It also creates the object that takes care of
* the interactive work.
*
* @param imp ImagePlus object where points are being picked.
* @param tb pointToolbar object that handles the toolbar.
********************************************************************/
public ParticleHandler (
final ImagePlus imp,
final ParticleToolbar tb
) {
super(0, 0, imp.getWidth(), imp.getHeight(), imp);
this.imp = imp;
this.tb = tb;
pa = new ParticleAction(imp, this, tb);
final ImageCanvas ic = imp.getWindow().getCanvas();
ic.removeKeyListener(IJ.getInstance());
ic.removeMouseListener(ic);
ic.removeMouseMotionListener(ic);
ic.addMouseMotionListener(pa);
ic.addMouseListener(pa);
ic.addKeyListener(pa);
started = true;
} /* end ParticleHandler */
/*********************************************************************
* Remove the current point. Make its color available again.
********************************************************************/
public void removePoint (
) {
if (0 < listPoints.size()) {
listPoints.removeElementAt(currentPoint);
numPoints--;
}
currentPoint = numPoints - 1;
if (currentPoint < 0) {
tb.setTool(pa.ADD_CIRCLE);
}
} /* end removePoint */
/*********************************************************************
* Remove all points and make every color available.
********************************************************************/
public void removePoints (
) {
listPoints.removeAllElements();
numPoints = 0;
currentPoint = -1;
tb.setTool(pa.ADD_CIRCLE);
imp.setRoi(this);
} /* end removePoints */
} /* end class ParticleHandler */
/*====================================================================
| ParticlePickerClearAll
\===================================================================*/
/*********************************************************************
* This class creates a dialog to remove every point.
********************************************************************/
class ParticlePickerClearAll
extends
Dialog
implements
ActionListener
{ /* begin class ParticlePickerClearAll */
/*....................................................................
Private variables
....................................................................*/
private ParticleHandler ph;
/*....................................................................
Public methods
....................................................................*/
/*********************************************************************
* This method processes the button actions.
*
* @param ae The expected actions are as follows:
* Clear All
: Remove everything;
* Cancel
: Do nothing.
********************************************************************/
public void actionPerformed (
final ActionEvent ae
) {
if (ae.getActionCommand().equals("Clear All")) {
ph.removePoints();
setVisible(false);
}
else if (ae.getActionCommand().equals("Cancel")) {
setVisible(false);
}
} /* end actionPerformed */
/*********************************************************************
* Return some additional margin to the dialog, for aesthetic purposes.
* Necessary for the current MacOS X Java version, lest the first item
* disappears from the frame.
********************************************************************/
public Insets getInsets (
) {
return(new Insets(0, 20, 20, 20));
} /* end getInsets */
/*********************************************************************
* This constructor stores a local copy of its parameters and prepares
* the layout of the dialog.
*
* @param parentWindow Parent window.
* @param ph pointHandler object that handles operations.
********************************************************************/
ParticlePickerClearAll (
final Frame parentWindow,
final ParticleHandler ph
) {
super(parentWindow, "Removing Points", true);
this.ph = ph;
setLayout(new GridLayout(0, 1));
final Button removeButton = new Button("Clear All");
removeButton.addActionListener(this);
final Button cancelButton = new Button("Cancel");
cancelButton.addActionListener(this);
final Label separation1 = new Label("");
final Label separation2 = new Label("");
add(separation1);
add(removeButton);
add(separation2);
add(cancelButton);
pack();
} /* end ParticlePickerClearAll */
} /* end class ParticlePickerClearAll */
/*====================================================================
| ParticlePickerFile
\===================================================================*/
/*********************************************************************
* This class creates a dialog to store and retrieve points into and
* from a text file, respectively.
********************************************************************/
class ParticlePickerFile
extends
Dialog
implements
ActionListener
{ /* begin class ParticlePickerFile */
/*....................................................................
Private variables
....................................................................*/
private final CheckboxGroup choice = new CheckboxGroup();
private ImagePlus imp;
private ParticleHandler ph;
/*....................................................................
Public methods
....................................................................*/
/*********************************************************************
* This method processes the button actions.
*
* @param ae The expected actions are as follows:
* Save as
: Save points into a text file;
* Show
: Display the coordinates in ImageJ's window;
* Open
: Retrieve points from a text file;
* Cancel
: Do nothing.
********************************************************************/
public void actionPerformed (
final ActionEvent ae
) {
this.setVisible(false);
if (ae.getActionCommand().equals("Save as")) {
final Frame f = new Frame();
final FileDialog fd = new FileDialog(f, "Point list", FileDialog.SAVE);
final String path;
String filename = imp.getTitle();
final int dot = filename.lastIndexOf('.');
if (dot == -1) {
fd.setFile(filename + ".txt");
}
else {
filename = filename.substring(0, dot);
fd.setFile(filename + ".txt");
}
fd.setVisible(true);
path = fd.getDirectory();
filename = fd.getFile();
if ((path == null) || (filename == null)) {
return;
}
try {
final FileWriter fw = new FileWriter(path + filename);
final Vector list = ph.getPoints();
Point p;
String n;
String x;
String y;
fw.write("point x y\n");
for (int k = 0; (k < list.size()); k++) {
n = "" + k;
while (n.length() < 5) {
n = " " + n;
}
p = (Point)list.elementAt(k);
x = "" + p.x;
while (x.length() < 5) {
x = " " + x;
}
y = "" + p.y;
while (y.length() < 5) {
y = " " + y;
}
fw.write(n + " " + x + " " + y + "\n");
}
fw.close();
} catch (IOException e) {
IJ.error("IOException exception");
} catch (SecurityException e) {
IJ.error("Security exception");
}
}
else if (ae.getActionCommand().equals("Show")) {
final Vector list = ph.getPoints();
Point p;
String n;
String x;
String y;
IJ.getTextPanel().setFont(new Font("Monospaced", Font.PLAIN, 12));
IJ.setColumnHeadings(" point\t x\t y\t");
for (int k = 0; (k < list.size()); k++) {
n = "" + k;
while (n.length() < 6) {
n = " " + n;
}
p = (Point)list.elementAt(k);
x = "" + p.x;
while (x.length() < 7) {
x = " " + x;
}
y = "" + p.y;
while (y.length() < 7) {
y = " " + y;
}
IJ.write(n + "\t" + x + "\t" + y + "\t");
}
//IJ.write("fasle positive : "+ph.getFP()+"\nfalse negtive : "+ph.getFN()+"\n");
}
else if (ae.getActionCommand().equals("Open")) {
final Frame f = new Frame();
final FileDialog fd = new FileDialog(f, "Point list", FileDialog.LOAD);
fd.setVisible(true);
final String path = fd.getDirectory();
final String filename = fd.getFile();
if ((path == null) || (filename == null)) {
return;
}
try {
final FileReader fr = new FileReader(path + filename);
final BufferedReader br = new BufferedReader(fr);
ph.removePoints();
String line;
String pString;
String xString;
String yString;
int separatorIndex;
int x;
int y;
if ((line = br.readLine()) == null) {
fr.close();
return;
}
while ((line = br.readLine()) != null) {
line = line.trim();
separatorIndex = line.indexOf(' ');
if (separatorIndex == -1) {
fr.close();
IJ.error("Invalid file");
return;
}
line = line.substring(separatorIndex);
line = line.trim();
separatorIndex = line.indexOf(' ');
if (separatorIndex == -1) {
fr.close();
IJ.error("Invalid file");
return;
}
xString = line.substring(0, separatorIndex);
xString = xString.trim();
line = line.substring(separatorIndex);
line = line.trim();
separatorIndex = line.indexOf(' ');
if (separatorIndex == -1) {
separatorIndex = line.length();
}
yString = line.substring(0, separatorIndex);
yString = yString.trim();
x = Integer.parseInt(xString);
y = Integer.parseInt(yString);
ph.addPoint(x, y);
}
fr.close();
} catch (FileNotFoundException e) {
IJ.error("File not found exception");
} catch (IOException e) {
IJ.error("IOException exception");
} catch (NumberFormatException e) {
IJ.error("Number format exception");
}
}
else if (ae.getActionCommand().equals("Cancel")) {
}
} /* end actionPerformed */
/*********************************************************************
* Return some additional margin to the dialog, for aesthetic purposes.
* Necessary for the current MacOS X Java version, lest the first item
* disappears from the frame.
********************************************************************/
public Insets getInsets (
) {
return(new Insets(0, 20, 20, 20));
} /* end getInsets */
/*********************************************************************
* This constructor stores a local copy of its parameters and prepares
* the layout of the dialog.
*
* @param parentWindow Parent window.
* @param ph pointHandler object that handles operations.
* @param imp ImagePlus object where points are being picked.
********************************************************************/
ParticlePickerFile (
final Frame parentWindow,
final ParticleHandler ph,
final ImagePlus imp
) {
super(parentWindow, "Point List", true);
this.ph = ph;
this.imp = imp;
setLayout(new GridLayout(0, 1));
final Button saveAsButton = new Button("Save as");
final Button showButton = new Button("Show");
final Button openButton = new Button("Open");
final Button cancelButton = new Button("Cancel");
saveAsButton.addActionListener(this);
showButton.addActionListener(this);
openButton.addActionListener(this);
cancelButton.addActionListener(this);
final Label separation1 = new Label("");
final Label separation2 = new Label("");
add(separation1);
add(saveAsButton);
add(showButton);
add(openButton);
add(separation2);
add(cancelButton);
pack();
} /* end ParticlePickerFile */
} /* end class ParticlePickerFile */
/*====================================================================
| ParticlePickerTerminate
\===================================================================*/
/*********************************************************************
* This class creates a dialog to return to ImageJ.
********************************************************************/
class ParticlePickerTerminate
extends
Dialog
implements
ActionListener
{ /* begin class ParticlePickerTerminate */
/*....................................................................
Private variables
....................................................................*/
private final CheckboxGroup choice = new CheckboxGroup();
private boolean cancel = false;
/*....................................................................
Public methods
....................................................................*/
/*********************************************************************
* This method processes the button actions.
*
* @param ae The expected actions are as follows:
* Done
: Return to ImageJ;
* Cancel
: Do nothing.
********************************************************************/
public void actionPerformed (
final ActionEvent ae
) {
this.setVisible(false);
if (ae.getActionCommand().equals("Done")) {
}
else if (ae.getActionCommand().equals("Cancel")) {
cancel = true;
}
} /* end actionPerformed */
/*********************************************************************
* Return true
only if the user chose Cancel
.
********************************************************************/
public boolean choseCancel (
) {
return(cancel);
} /* end choseCancel */
/*********************************************************************
* Return some additional margin to the dialog, for aesthetic purposes.
* Necessary for the current MacOS X Java version, lest the first item
* disappears from the frame.
********************************************************************/
public Insets getInsets (
) {
return(new Insets(0, 40, 20, 40));
} /* end getInsets */
/*********************************************************************
* This constructor prepares the layout of the dialog.
*
* @param parentWindow Parent window.
********************************************************************/
ParticlePickerTerminate (
final Frame parentWindow
) {
super(parentWindow, "Back to ImageJ", true);
setLayout(new GridLayout(0, 1));
final Button doneButton = new Button("Done");
final Button cancelButton = new Button("Cancel");
doneButton.addActionListener(this);
cancelButton.addActionListener(this);
final Label separation1 = new Label("");
final Label separation2 = new Label("");
add(separation1);
add(doneButton);
add(separation2);
add(cancelButton);
pack();
} /* end ParticlePickerTerminate */
} /* end class ParticlePickerTerminate */
class ParticleFinder extends ParticleAnalyzer {
boolean error;
Vector listPoints = new Vector(512,512);
int numPoints = 0;
public void run2(ImagePlus imp, ImageProcessor ip) {
error = !analyze(imp, ip);
}
public void addPoint(final int x, final int y){
final Point p = new Point(x,y);
listPoints.addElement(p);
numPoints++;
}/* end addPoint */
public void showPoints(){
int i;
Point p;
String n;
String x;
String y;
String z = ""+imp.getCurrentSlice();
while(z.length()<7){
z=" "+z;
}
Calibration cal = imp.getCalibration();
IJ.setColumnHeadings(" point\t x\t y\t slice");
IJ.write(imp.getWidth()*cal.pixelWidth + " " + imp.getHeight()*cal.pixelHeight +"\n");
for (i=0;imouseClicked
events.
*
* @param e Ignored.
********************************************************************/
public void mouseClicked (
final MouseEvent e
) {
} /* end mouseClicked */
/*********************************************************************
* Listen to mouseEntered
events.
*
* @param e Ignored.
********************************************************************/
public void mouseEntered (
final MouseEvent e
) {
} /* end mouseEntered */
/*********************************************************************
* Listen to mouseExited
events.
*
* @param e Ignored.
********************************************************************/
public void mouseExited (
final MouseEvent e
) {
} /* end mouseExited */
/*********************************************************************
* Listen to mousePressed
events. Test for single or double
* clicks and perform the relevant action.
*
* @param e Event.
********************************************************************/
public void mousePressed (
final MouseEvent e
) {
final int x = e.getX();
final int y = e.getY();
final int previousTool = currentTool;
int newTool = 0;
for (int i = 0; (i < NUM_TOOLS); i++) {
if (((i * SIZE) < x) && (x < (i * SIZE + SIZE))) {
newTool = i;
}
}
final boolean doubleClick = ((newTool == getCurrentTool())
&& ((System.currentTimeMillis() - mouseDownTime) <= 500L));
mouseDownTime = System.currentTimeMillis();
setTool(newTool);
if (doubleClick) {
switch (newTool) {
case ParticleAction.ADD_CIRCLE:
ParticlePickerClearAll clearAllDialog
= new ParticlePickerClearAll(IJ.getInstance(), ph);
GUI.center(clearAllDialog);
clearAllDialog.setVisible(true);
clearAllDialog.dispose();
break;
}
}
switch (newTool) {
case ParticleAction.FILE:
ParticlePickerFile fileDialog
= new ParticlePickerFile(IJ.getInstance(), ph, imp);
GUI.center(fileDialog);
fileDialog.setVisible(true);
setTool(previousTool);
fileDialog.dispose();
break;
case ParticleAction.TERMINATE:
ParticlePickerTerminate terminateDialog
= new ParticlePickerTerminate(IJ.getInstance());
GUI.center(terminateDialog);
terminateDialog.setVisible(true);
if (terminateDialog.choseCancel()) {
setTool(previousTool);
}
else {
ph.cleanUp();
restorePreviousToolbar();
Toolbar.getInstance().repaint();
}
terminateDialog.dispose();
break;
case ParticleAction.FINDER:
ParticleFinder pf = new ParticleFinder();
int code = pf.setup("",this.imp);
ImageProcessor ip = imp.getProcessor();
pf.run2(this.imp,ip);
for (int k=0;kmouseReleased
events.
*
* @param e Ignored.
********************************************************************/
public void mouseReleased (
final MouseEvent e
) {
} /* end mouseReleased */
/*********************************************************************
* Draw the tools of the toolbar.
*
* @param g Graphics environment.
********************************************************************/
public void paint (
final Graphics g
) {
for (int i = 0; (i < NUM_TOOLS); i++) {
drawButton(g, i);
}
} /* paint */
/*********************************************************************
* This constructor substitutes ImageJ's toolbar by that of ParticlePicker_.
*
* @param previousToolbar ImageJ's toolbar.
********************************************************************/
public ParticleToolbar (
final Toolbar previousToolbar
) {
previousInstance = previousToolbar;
instance = this;
final Container container = previousToolbar.getParent();
final Component component[] = container.getComponents();
for (int i = 0; (i < component.length); i++) {
if (component[i] == previousToolbar) {
container.remove(previousToolbar);
container.add(this, i);
break;
}
}
resetButtons();
down[currentTool] = true;
setTool(currentTool);
setForeground(evenDarker);
setBackground(gray);
addMouseListener(this);
container.validate();
} /* end ParticleToolbar */
/*********************************************************************
* Setup the Particle handler.
*
* @param ph ParticleHandler object that handles operations.
* @param imp ImagePlus object where points are being picked.
********************************************************************/
public void setWindow (
final ParticleHandler ph,
final ImagePlus imp
) {
this.ph = ph;
this.imp = imp;
} /* end setWindow */
/*********************************************************************
* Setup the current tool. The selection of non-functional tools is
* honored but leads to a no-op action.
*
* @param tool Admissible tools belong to [0
,
* NUM_TOOLS - 1
]
********************************************************************/
public void setTool (
final int tool
) {
if (tool == currentTool) {
return;
}
down[tool] = true;
down[currentTool] = false;
final Graphics g = this.getGraphics();
drawButton(g, currentTool);
drawButton(g, tool);
g.dispose();
showMessage(tool);
currentTool = tool;
} /* end setTool */
/*....................................................................
Private methods
....................................................................*/
/*------------------------------------------------------------------*/
private void d (
int x,
int y
) {
x += xOffset;
y += yOffset;
g.drawLine(this.x, this.y, x, y);
this.x = x;
this.y = y;
} /* end d */
/*------------------------------------------------------------------*/
private void drawButton (
final Graphics g,
final int tool
) {
fill3DRect(g, tool * SIZE + 1, 1, SIZE, SIZE - 1, !down[tool]);
g.setColor(Color.black);
int x = tool * SIZE + OFFSET;
int y = OFFSET;
if (down[tool]) {
x++;
y++;
}
this.g = g;
switch (tool) {
case ParticleAction.ADD_CIRCLE:
xOffset = x;
yOffset = y;
m(7, 0);
d(7, 1);
m(6, 2);
d(6, 3);
m(8, 2);
d(8, 3);
m(5, 4);
d(5, 5);
m(9, 4);
d(9, 5);
m(4, 6);
d(4, 8);
m(10, 6);
d(10, 8);
m(5, 9);
d(5, 14);
m(9, 9);
d(9, 14);
m(7, 4);
d(7, 6);
m(7, 8);
d(7, 8);
m(4, 11);
d(10, 11);
g.fillRect(x + 6, y + 12, 3, 3);
break;
case ParticleAction.MOVE_CIRCLE:
xOffset = x;
yOffset = y;
m(1, 1);
d(1, 10);
m(2, 2);
d(2, 9);
m(3, 3);
d(3, 8);
m(4, 4);
d(4, 7);
m(5, 5);
d(5, 7);
m(6, 6);
d(6, 7);
m(7, 7);
d(7, 7);
m(11, 5);
d(11, 6);
m(10, 7);
d(10, 8);
m(12, 7);
d(12, 8);
m(9, 9);
d(9, 11);
m(13, 9);
d(13, 11);
m(10, 12);
d(10, 15);
m(12, 12);
d(12, 15);
m(11, 9);
d(11, 10);
m(11, 13);
d(11, 15);
m(9, 13);
d(13, 13);
break;
case ParticleAction.FILE:
xOffset = x;
yOffset = y;
m(3, 1);
d(9, 1);
d(9, 4);
d(12, 4);
d(12, 14);
d(3, 14);
d(3, 1);
m(10, 2);
d(11, 3);
m(5, 4);
d(7, 4);
m(5, 6);
d(10, 6);
m(5, 8);
d(10, 8);
m(5, 10);
d(10, 10);
m(5, 12);
d(10, 12);
break;
case ParticleAction.TERMINATE:
xOffset = x;
yOffset = y;
m(5, 0);
d(5, 8);
m(4, 5);
d(4, 7);
m(3, 6);
d(3, 7);
m(2, 7);
d(2, 9);
m(1, 8);
d(1, 9);
m(2, 10);
d(6, 10);
m(3, 11);
d(3, 13);
m(1, 14);
d(6, 14);
m(0, 15);
d(7, 15);
m(2, 13);
d(2, 13);
m(5, 13);
d(5, 13);
m(7, 8);
d(14, 8);
m(8, 7);
d(15, 7);
m(8, 9);
d(13, 9);
m(9, 6);
d(9, 10);
m(15, 4);
d(15, 6);
d(14, 6);
break;
case ParticleAction.MAGNIFIER:
xOffset = x + 2;
yOffset = y + 2;
m(3, 0);
d(3, 0);
d(5, 0);
d(8, 3);
d(8, 5);
d(7, 6);
d(7, 7);
d(6, 7);
d(5, 8);
d(3, 8);
d(0, 5);
d(0, 3);
d(3, 0);
m(8, 8);
d(9, 8);
d(13, 12);
d(13, 13);
d(12, 13);
d(8, 9);
d(8, 8);
break;
case ParticleAction.FINDER:
xOffset = x + 4;
yOffset = y + 4;
m(3, 0);
d(3, 0);
d(5, 0);
d(8, 3);
d(8, 5);
d(7, 6);
d(7, 7);
d(6, 7);
d(5, 8);
d(3, 8);
d(0, 5);
d(0, 3);
d(3, 0);
break;
case ParticleAction.CLUSTER:
xOffset = x;
yOffset = y;
m(3, 0);
d(4, 0);
d(4,2);
d(3, 2);
d(3, 1);
m(8, 3);
d(9, 3);
d(9, 5);
d(8, 5);
d(8, 4);
m(5, 10);
d(6, 10);
d(6, 12);
d(5, 12);
d(5, 11);
m(12, 10);
d(13, 10);
d(13, 12);
d(12, 12);
d(12, 11);
break;
case ParticleAction.HAND:
xOffset = x+1; yOffset = y+1;
m(5,14); d(2,11); d(2,10); d(0,8); d(0,7); d(1,6); d(2,6); d(4,8);
d(4,6); d(3,5); d(3,4); d(2,3); d(2,2); d(3,1); d(4,1); d(5,2); d(5,3);
m(6,5); d(6,1); d(7,0); d(8,0); d(9,1); d(9,5);
m(9,1); d(11,1); d(12,2); d(12,6);
m(13,4); d(14,3); d(15,4); d(15,7); d(14,8);
d(14,10); d(13,11); d(13,12); d(12,13); d(12,14);
break;
}
} /* end drawButton */
/*------------------------------------------------------------------*/
private void fill3DRect (
final Graphics g,
final int x,
final int y,
final int width,
final int height,
final boolean raised
) {
if (raised) {
g.setColor(gray);
}
else {
g.setColor(darker);
}
g.fillRect(x + 1, y + 1, width - 2, height - 2);
g.setColor((raised) ? (brighter) : (evenDarker));
g.drawLine(x, y, x, y + height - 1);
g.drawLine(x + 1, y, x + width - 2, y);
g.setColor((raised) ? (evenDarker) : (brighter));
g.drawLine(x + 1, y + height - 1, x + width - 1, y + height - 1);
g.drawLine(x + width - 1, y, x + width - 1, y + height - 2);
} /* end fill3DRect */
/*------------------------------------------------------------------*/
private void m (
final int x,
final int y
) {
this.x = xOffset + x;
this.y = yOffset + y;
} /* end m */
/*------------------------------------------------------------------*/
private void resetButtons (
) {
for (int i = 0; (i < NUM_TOOLS); i++) {
down[i] = false;
}
} /* end resetButtons */
/*------------------------------------------------------------------*/
private void restorePreviousToolbar (
) {
final Container container = instance.getParent();
final Component component[] = container.getComponents();
for (int i = 0; (i < component.length); i++) {
if (component[i] == instance) {
container.remove(instance);
container.add(previousInstance, i);
container.validate();
break;
}
}
} /* end restorePreviousToolbar */
/*------------------------------------------------------------------*/
private void showMessage (
final int tool
) {
switch (tool) {
case ParticleAction.ADD_CIRCLE:
IJ.showStatus("Add circles");
return;
case ParticleAction.MOVE_CIRCLE:
IJ.showStatus("Move circles");
return;
case ParticleAction.FILE:
IJ.showStatus("Export/Import list of points");
return;
case ParticleAction.TERMINATE:
IJ.showStatus("Exit PointPicker");
return;
case ParticleAction.MAGNIFIER:
IJ.showStatus("Magnifying glass");
return;
case ParticleAction.FINDER:
IJ.showStatus("Find particles");
return;
case ParticleAction.CLUSTER:
IJ.showStatus("Find Clusters");
return;
default:
IJ.showStatus("Undefined operation");
return;
}
} /* end showMessage */
} /* end class ParticleToolbar */
class Particle {
public int x;
public int y;
public int cnum;
public int nn;
public Vector neighbors = new Vector(0,16);
Particle(int a,int b, int c){
x=a;
y=b;
cnum=c;
nn=0;
}
public void addNeighbor(Particle p){
neighbors.addElement(p);
nn++;
}
public void print(){
IJ.write("X= "+x+", Y= "+y+"Cluster #:"+cnum+"\n");
}
}
class ParticleCluster {
private Vector particles = new Vector(0,16);
private Vector PCNeighbors = new Vector(0,16);
private int num_p =0;
private int neigb= 0;
public int max_x = 0;
public int max_y = 0;
public int min_x = 0;
public int min_y = 0;
private int cluster_id = 0;
public void addParticle(Particle p){
if(num_p==0) {
max_x=p.x;
min_x=p.x;
max_y=p.y;
min_y=p.y;
}
p.cnum=cluster_id;
particles.addElement(p);
addNeighbor(p);
num_p++;
if(p.x>max_x) max_x=p.x;
if(p.y>max_y) max_y=p.y;
if(p.x0){
next=CloseNeighbor();
p=(Particle) PCNeighbors.elementAt(next);
PCNeighbors.removeElementAt(next);
neigb--;
if(!InCluster(p)) addParticle(p);
//limit++;
}
}
public boolean InCluster(Particle p){
boolean result=false;
Particle p1;
for(int i=0;i second.y) {
Particle temp = first;
listPoints.setElementAt(second, i);
listPoints.setElementAt(temp, i+1);
sorted = false;
}
}
}
}
public void cal_cluster(){
Particle p1,p2;
int clust_id=1;
ParticleCluster pc;
double dd,d;
int limit;
for(int i=0;imax_size) max_size=pn;
//IJ.write(pn+"\n");
for(int i=1;i<=20;i++){
if(pn==i) num1[i-1]+=pn;
}
if(pn>=21) num1[20]+=pn;
}
for(int k=1;k<=21;k++){
IJ.write("**Numb of Particles in Clusters size "+k+" : "+num1[k-1]+"\n");
}
int [] num2;
num2 = new int[max_size+1];
for(int j=0;j