1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
package ij.plugin;
import ij.*;
import ij.gui.*;
import ij.measure.Calibration;
import ij.plugin.frame.Recorder;
import java.awt.AWTEvent;
import java.awt.geom.Rectangle2D;
/**
* The plugin implements the Image/Adjust/Coordinates command. It allows
* the user to set the corner coordinates of the selection bounds or the full image.
* This modifies the image scale (pixelWidth, pixelHeight) and the xOrigin, yOrigin.
* If a single point is selected, the coordinates of the point can be specified, which only
* sets the xOrigin and yOrigin.
* Units for x and y can be also selected (2016-08-30, Michael Schmid).
* Z unit of stacks can be selected (2019-09-30, Stein Rorvik).
*/
public class Coordinates implements PlugIn, DialogListener {
private static final String help = "<html>"
+"<h1>Image>Adjust>Coordinates</h1>"
+"<font size=+1>"
+"This command allows the user to set the corner coordinates of<br>the selection bounds "
+"or the full image. This modifies the image<br>scale (<i>pixelWidth</i>, <i>pixelHeight</i>) and <i>xOrigin</i> and <i>yOrigin</i>. "
+"If a<br>single point is selected, the coordinates of the point can be<br>specified, which only "
+"sets <i>xOrigin</i> and <i>yOrigin</i>. The units for X<br>and Y can be also selected.<br> "
+"</font>";
private final static String SAME_AS_X = "<same as x unit>";
private final static int IMAGE = 0, ROI_BOUNDS = 1, POINT = 2; //mode: coordinates of what to specify
private int mode = IMAGE;
private boolean isStack;
public void run(String arg) {
ImagePlus imp = IJ.getImage();
int imageHeight = imp.getHeight();
Calibration cal = imp.getCalibration();
Roi roi = imp.getRoi();
Rectangle2D.Double bounds = null;
int numSlices = imp.getNSlices();
int currSlice = imp.getCurrentSlice();
isStack = numSlices>1;
if (roi != null) {
bounds = roi.getFloatBounds();
if (bounds.width==0 && bounds.height==0)
mode = POINT;
else
mode = ROI_BOUNDS;
} else { //no Roi, use image bounds
bounds = new Rectangle2D.Double(0, 0, imp.getWidth(), imp.getHeight());
}
String title = (mode==IMAGE ? "Image" : "Selection") +" Coordinates";
if (mode == POINT)
title = "Point Coordinates";
GenericDialog gd = new GenericDialog(title);
if (mode == POINT) {
gd.addNumericField("X:", cal.getX(bounds.x), 2, 8, "");
gd.addNumericField("Y:", cal.getY(bounds.y, imageHeight), 2, 8, "");
if (isStack)
gd.addNumericField("Z:", cal.getZ(currSlice-1), 2, 8, "");
} else {
gd.addNumericField("Left:", cal.getX(bounds.x), 2, 8, "");
gd.addNumericField("Right:", cal.getX(bounds.x+bounds.width), 2, 8, "");
gd.addNumericField("Top:", cal.getY(bounds.y, imageHeight), 2, 8, "");
gd.addNumericField("Bottom:", cal.getY(bounds.y+bounds.height, imageHeight), 2, 8, "");
if (isStack) {
gd.addNumericField("Front:", cal.getZ(0), 2, 8, "");
gd.addNumericField("Back:", cal.getZ(numSlices), 2, 8, "");
}
}
String xUnit = cal.getUnit();
String yUnit = cal.getYUnit();
String zUnit = cal.getZUnit();
boolean xUnitChanged=false,yUnitChanged=false,zUnitChanged=false;
gd.addStringField("X_unit:", xUnit, 18);
gd.addStringField("Y_unit:", yUnit.equals(xUnit) ? SAME_AS_X : yUnit, 18);
if (isStack)
gd.addStringField("Z_unit:", zUnit.equals(xUnit) ? SAME_AS_X : zUnit, 18);
gd.addHelp(help);
gd.addDialogListener(this);
gd.showDialog();
if (gd.wasCanceled())
return;
if (mode == POINT) {
double x = gd.getNextNumber();
double y = gd.getNextNumber();
if (gd.invalidNumber()) {
IJ.error("Invalid number");
return;
}
cal.xOrigin = coordinate2offset(x, bounds.x, cal.pixelWidth);
cal.yOrigin = coordinate2offset(y, bounds.y, cal.getInvertY() ? -cal.pixelHeight : cal.pixelHeight);
if (isStack) {
double z = gd.getNextNumber();
if (gd.invalidNumber()) {
IJ.error("Invalid number");
return;
}
cal.zOrigin = coordinate2offset(z, currSlice-1, cal.pixelDepth);
}
} else {
double xl = gd.getNextNumber();
double xr = gd.getNextNumber();
double yt = gd.getNextNumber();
double yb = gd.getNextNumber();
if (gd.invalidNumber()) {
IJ.error("Invalid number");
return;
}
cal.pixelWidth = (xr-xl)/bounds.width;
cal.pixelHeight = (yb-yt)/bounds.height;
cal.xOrigin = coordinate2offset(xl, bounds.x, cal.pixelWidth);
cal.yOrigin = coordinate2offset(yt, bounds.y, cal.pixelHeight);
cal.setInvertY(cal.pixelHeight < 0);
if (isStack) {
double zf = gd.getNextNumber();
double zl = gd.getNextNumber();
cal.pixelDepth = (zl-zf)/numSlices;
cal.zOrigin = coordinate2offset(zf, 0, cal.pixelDepth);
}
if (cal.pixelHeight < 0)
cal.pixelHeight = -cal.pixelHeight;
}
String xUnit2 = gd.getNextString();
xUnitChanged = !xUnit2.equals(xUnit);
if (xUnitChanged)
cal.setXUnit(xUnit2);
String yUnit2 = gd.getNextString();
yUnitChanged = !yUnit2.equals(yUnit) && !yUnit2.equals(SAME_AS_X);
if (yUnitChanged)
cal.setYUnit(yUnit2);
String zUnit2 = null;
if (isStack) {
zUnit2 = gd.getNextString();
zUnitChanged = !zUnit2.equals(zUnit) && !zUnit2.equals(SAME_AS_X);
if (zUnitChanged)
cal.setZUnit(zUnit2);
}
ImageWindow win = imp.getWindow();
imp.repaintWindow();
if (Recorder.record) {
if (Recorder.scriptMode()) {
if (xUnitChanged)
Recorder.recordCall("imp.getCalibration().setXUnit(\""+xUnit2+"\");", true);
if (yUnitChanged)
Recorder.recordCall("imp.getCalibration().setYUnit(\""+yUnit2+"\");", true);
if (zUnitChanged)
Recorder.recordCall("imp.getCalibration().setZUnit(\""+zUnit2+"\");", true);
} else {
if (xUnitChanged)
Recorder.record("Stack.setXUnit", xUnit2);
if (yUnitChanged)
Recorder.record("Stack.setYUnit", yUnit2);
if (zUnitChanged)
Recorder.record("Stack.setZUnit", zUnit2);
}
}
}
public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
if (mode == POINT) {
gd.getNextNumber();
gd.getNextNumber();
if (isStack)
gd.getNextNumber();
return (!gd.invalidNumber());
} else {
double xl = gd.getNextNumber();
double xr = gd.getNextNumber();
double yt = gd.getNextNumber();
double yb = gd.getNextNumber();
if (isStack) {
double zf = gd.getNextNumber();
double zl = gd.getNextNumber();
return (!gd.invalidNumber() && (xr>xl) && (yt!=yb) && (zl>zf));
} else
return (!gd.invalidNumber() && xr>xl && yt!=yb);
}
}
// Calculates pixel offset from scaled coordinates of a point with given pixel position
private double coordinate2offset(double coordinate, double pixelPos, double pixelSize) {
return pixelPos - coordinate/pixelSize;
}
}
|