ij.plugin.Slicer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ij Show documentation
Show all versions of ij Show documentation
ImageJ is an open source Java image processing program inspired by NIH Image for the Macintosh.
package ij.plugin;
import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.measure.*;
import ij.util.Tools;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** Implements the Image/Stacks/Reslice command. Known shortcomings:
for FREELINE or POLYLINE ROI, spatial calibration is ignored:
the image is sampled at constant _pixel_ increments (distance 1), so
(if y/x aspect ratio != 1 in source image) one dimension in the output is not
homogeneous (i.e. pixelWidth not the same everywhere).
*/
public class Slicer implements PlugIn, TextListener, ItemListener {
private static final String[] starts = {"Top", "Left", "Bottom", "Right"};
private static String startAtS = starts[0];
private static boolean rotateS;
private static boolean flipS;
private static int sliceCountS = 1;
private String startAt = starts[0];
private boolean rotate;
private boolean flip;
private int sliceCount = 1;
private boolean nointerpolate = Prefs.avoidResliceInterpolation;
private double inputZSpacing = 1.0;
private double outputZSpacing = 1.0;
private int outputSlices = 1;
private boolean noRoi;
private boolean rgb, notFloat;
private Vector fields, checkboxes;
private Label message;
private ImagePlus imp;
private double gx1, gy1, gx2, gy2, gLength;
// Variables used by getIrregularProfile and doIrregularSetup
private int n;
private double[] x;
private double[] y;
private int xbase;
private int ybase;
private double length;
private double[] segmentLengths;
private double[] dx;
private double[] dy;
public void run(String arg) {
imp = WindowManager.getCurrentImage();
if (imp==null) {
IJ.noImage();
return;
}
int stackSize = imp.getStackSize();
Roi roi = imp.getRoi();
int roiType = roi!=null?roi.getType():0;
// stack required except for ROI = none or RECT
if (stackSize<2 && roi!=null && roiType!=Roi.RECTANGLE) {
IJ.error("Reslice...", "Stack required");
return;
}
// permissible ROI types: none,RECT,*LINE
if (roi!=null && roiType!=Roi.RECTANGLE && roiType!=Roi.LINE && roiType!=Roi.POLYLINE && roiType!=Roi.FREELINE) {
IJ.error("Reslice...", "Line or rectangular selection required");
return;
}
if (!showDialog(imp))
return;
long startTime = System.currentTimeMillis();
ImagePlus imp2 = null;
rgb = imp.getType()==ImagePlus.COLOR_RGB;
notFloat = !rgb && imp.getType()!=ImagePlus.GRAY32;
if (imp.isHyperStack())
imp2 = resliceHyperstack(imp);
else
imp2 = reslice(imp);
if (imp2==null)
return;
ImageProcessor ip = imp.getProcessor();
double min = ip.getMin();
double max = ip.getMax();
if (!rgb) imp2.getProcessor().setMinAndMax(min, max);
imp2.show();
if (noRoi)
imp.deleteRoi();
else
imp.draw();
IJ.showStatus(IJ.d2s(((System.currentTimeMillis()-startTime)/1000.0),2)+" seconds");
}
public ImagePlus reslice(ImagePlus imp) {
ImagePlus imp2;
Roi roi = imp.getRoi();
int roiType = roi!=null?roi.getType():0;
Calibration origCal = imp.getCalibration();
boolean globalCalibration = false;
if (nointerpolate) {// temporarily clear spatial calibration
globalCalibration = imp.getGlobalCalibration()!=null;
imp.setGlobalCalibration(null);
Calibration tmpCal = origCal.copy();
tmpCal.pixelWidth = 1.0;
tmpCal.pixelHeight = 1.0;
tmpCal.pixelDepth = 1.0;
imp.setCalibration(tmpCal);
inputZSpacing = 1.0;
if (roiType!=Roi.LINE)
outputZSpacing = 1.0;
}
double zSpacing = inputZSpacing/imp.getCalibration().pixelWidth;
if (roi==null || roiType==Roi.RECTANGLE || roiType==Roi.LINE) {
imp2 = resliceRectOrLine(imp);
} else {// we assert roiType==Roi.POLYLINE || roiType==Roi.FREELINE
String status = imp.getStack().isVirtual()?"":null;
IJ.showStatus("Reslice...");
ImageProcessor ip2 = getSlice(imp, 0.0, 0.0, 0.0, 0.0, status);
imp2 = new ImagePlus("Reslice of "+imp.getShortTitle(), ip2);
}
if (nointerpolate) { // restore calibration
if (globalCalibration)
imp.setGlobalCalibration(origCal);
imp.setCalibration(origCal);
}
// create Calibration for new stack
// start from previous cal and swap appropriate fields
boolean horizontal = false;
boolean vertical = false;
if (roi==null || roiType==Roi.RECTANGLE) {
if (startAt.equals(starts[0]) || startAt.equals(starts[2]))
horizontal = true;
else
vertical = true;
}
if (roi!=null && roiType==Roi.LINE) {
Line l = (Line)roi;
horizontal = (l.y2-l.y1)==0;
vertical = (l.x2-l.x1)==0;
}
if (imp2==null) return null;
imp2.setCalibration(imp.getCalibration());
Calibration cal = imp2.getCalibration();
if (horizontal) {
cal.pixelWidth = origCal.pixelWidth;
cal.pixelHeight = origCal.pixelDepth/zSpacing;
cal.pixelDepth = origCal.pixelHeight*outputZSpacing;
} else if (vertical) {
cal.pixelWidth = origCal.pixelHeight;
cal.pixelHeight = origCal.pixelDepth/zSpacing;
//cal.pixelWidth = origCal.pixelDepth/zSpacing;
//cal.pixelHeight = origCal.pixelHeight;
cal.pixelDepth = origCal.pixelWidth*outputZSpacing;;
} else { // oblique line, polyLine or freeline
if (origCal.pixelHeight==origCal.pixelWidth) {
cal.pixelWidth = origCal.pixelWidth;
cal.pixelHeight=origCal.pixelDepth/zSpacing;
cal.pixelDepth = origCal.pixelWidth*outputZSpacing;
} else {
cal.pixelWidth = cal.pixelHeight=cal.pixelDepth=1.0;
cal.setUnit("pixel");
}
}
double tmp;
if (rotate) {// if rotated flip X and Y
tmp = cal.pixelWidth;
cal.pixelWidth = cal.pixelHeight;
cal.pixelHeight = tmp;
}
return imp2;
}
ImagePlus resliceHyperstack(ImagePlus imp) {
int channels = imp.getNChannels();
int slices = imp.getNSlices();
int frames = imp.getNFrames();
if (slices==1)
return resliceTimeLapseHyperstack(imp);
int c1 = imp.getChannel();
int z1 = imp.getSlice();
int t1 = imp.getFrame();
int width = imp.getWidth();
int height = imp.getHeight();
ImagePlus imp2 = null;
ImageStack stack2 = null;
Roi roi = imp.getRoi();
for (int t=1; t<=frames; t++) {
for (int c=1; c<=channels; c++) {
ImageStack tmp1Stack = new ImageStack(width, height);
for (int z=1; z<=slices; z++) {
imp.setPositionWithoutUpdate(c, z, t);
tmp1Stack.addSlice(null, imp.getProcessor());
}
ImagePlus tmp1 = new ImagePlus("tmp", tmp1Stack);
tmp1.setCalibration(imp.getCalibration());
tmp1.setRoi(roi);
ImagePlus tmp2 = reslice(tmp1);
int slices2 = tmp2.getStackSize();
if (imp2==null) {
imp2 = tmp2.createHyperStack("Reslice of "+imp.getTitle(), channels, slices2, frames, tmp2.getBitDepth());
stack2 = imp2.getStack();
}
ImageStack tmp2Stack = tmp2.getStack();
for (int z=1; z<=slices2; z++) {
imp.setPositionWithoutUpdate(c, z, t);
int n2 = imp2.getStackIndex(c, z, t);
stack2.setPixels(tmp2Stack.getPixels(z), n2);
}
}
}
imp.setPosition(c1, z1, t1);
if (channels>1 && imp.isComposite()) {
imp2 = new CompositeImage(imp2, ((CompositeImage)imp).getMode());
((CompositeImage)imp2).copyLuts(imp);
}
return imp2;
}
ImagePlus resliceTimeLapseHyperstack(ImagePlus imp) {
int channels = imp.getNChannels();
int frames = imp.getNFrames();
int c1 = imp.getChannel();
int t1 = imp.getFrame();
int width = imp.getWidth();
int height = imp.getHeight();
ImagePlus imp2 = null;
ImageStack stack2 = null;
Roi roi = imp.getRoi();
int z = 1;
for (int c=1; c<=channels; c++) {
ImageStack tmp1Stack = new ImageStack(width, height);
for (int t=1; t<=frames; t++) {
imp.setPositionWithoutUpdate(c, z, t);
tmp1Stack.addSlice(null, imp.getProcessor());
}
ImagePlus tmp1 = new ImagePlus("tmp", tmp1Stack);
tmp1.setCalibration(imp.getCalibration());
tmp1.setRoi(roi);
ImagePlus tmp2 = reslice(tmp1);
int frames2 = tmp2.getStackSize();
if (imp2==null) {
imp2 = tmp2.createHyperStack("Reslice of "+imp.getTitle(), channels, 1, frames2, tmp2.getBitDepth());
stack2 = imp2.getStack();
}
ImageStack tmp2Stack = tmp2.getStack();
for (int t=1; t<=frames2; t++) {
imp.setPositionWithoutUpdate(c, z, t);
int n2 = imp2.getStackIndex(c, z, t);
stack2.setPixels(tmp2Stack.getPixels(z), n2);
}
}
imp.setPosition(c1, 1, t1);
if (channels>1 && imp.isComposite()) {
imp2 = new CompositeImage(imp2, ((CompositeImage)imp).getMode());
((CompositeImage)imp2).copyLuts(imp);
}
return imp2;
}
boolean showDialog(ImagePlus imp) {
Calibration cal = imp.getCalibration();
if (cal.pixelDepth<0.0)
cal.pixelDepth = -cal.pixelDepth;
String units = cal.getUnits();
if (cal.pixelWidth==0.0)
cal.pixelWidth = 1.0;
inputZSpacing = cal.pixelDepth;
double outputSpacing = cal.pixelDepth;
Roi roi = imp.getRoi();
boolean line = roi!=null && roi.getType()==Roi.LINE;
if (line) saveLineInfo(roi);
String macroOptions = Macro.getOptions();
boolean macroRunning = macroOptions!=null;
if (macroRunning) {
if (macroOptions.indexOf("input=")!=-1)
macroOptions = macroOptions.replaceAll("slice=", "slice_count=");
macroOptions = macroOptions.replaceAll("slice=", "output=");
Macro.setOptions(macroOptions);
nointerpolate = false;
} else {
startAt = startAtS;
rotate = rotateS;
flip = flipS;
sliceCount = sliceCountS;
}
GenericDialog gd = new GenericDialog("Reslice");
gd.addNumericField("Output spacing ("+units+"):", outputSpacing, 3);
if (line) {
if (!IJ.isMacro()) outputSlices=sliceCount;
gd.addNumericField("Slice_count:", outputSlices, 0);
} else
gd.addChoice("Start at:", starts, startAt);
gd.addCheckbox("Flip vertically", flip);
gd.addCheckbox("Rotate 90 degrees", rotate);
gd.addCheckbox("Avoid interpolation", nointerpolate);
gd.setInsets(0, 32, 0);
gd.addMessage("(use 1 pixel spacing)");
gd.setInsets(15, 0, 0);
gd.addMessage("Voxel size: "+d2s(cal.pixelWidth)+"x"+d2s(cal.pixelHeight)
+"x"+d2s(cal.pixelDepth)+" "+cal.getUnit());
gd.setInsets(5, 0, 0);
gd.addMessage("Output size: "+getSize(cal.pixelDepth,outputSpacing,outputSlices)+" ");
fields = gd.getNumericFields();
if (!macroRunning) {
for (int i=0; iProperties correct?.");
return null;
}
boolean virtualStack = imp.getStack().isVirtual();
String status = null;
ImagePlus imp2 = null;
ImageStack stack2 = null;
boolean isStack = imp.getStackSize()>1;
IJ.resetEscape();
for (int i=0; i1?(i+1)+"/"+outputSlices+", ":"";
ImageProcessor ip = getSlice(imp, x1, y1, x2, y2, status);
//IJ.log(i+" "+x1+" "+y1+" "+x2+" "+y2+" "+ip);
if (isStack) drawLine(x1, y1, x2, y2, imp);
if (stack2==null) {
stack2 = createOutputStack(imp, ip);
if (stack2==null || stack2.getSize()0) makePolygon(count, outSpacing);
}
String size = getSize(inputZSpacing, outSpacing, count);
message.setText("Output Size: "+size);
}
String getSize(double inSpacing, double outSpacing, int count) {
int size = getOutputStackSize(inSpacing, outSpacing, count);
int mem = getAvailableMemory();
String available = mem!=-1?" ("+mem+"MB free)":"";
if (message!=null)
message.setForeground(mem!=-1&&size>mem?Color.red:Color.black);
if (size>0)
return size+"MB"+available;
else
return "<1MB"+available;
}
void makePolygon(int count, double outSpacing) {
int[] x = new int[4];
int[] y = new int[4];
Calibration cal = imp.getCalibration();
double cx = cal.pixelWidth; //corrects preview for x calibration
double cy = cal.pixelHeight; //corrects preview for y calibration
x[0] = (int)gx1;
y[0] = (int)gy1;
x[1] = (int)gx2;
y[1] = (int)gy2;
double dx = gx2 - gx1;
double dy = gy2 - gy1;
double nrm = Math.sqrt(dx*dx + dy*dy)/outSpacing;
double xInc = -(dy/(cx*nrm)); //cx scales the x increment
double yInc = (dx/(cy*nrm)); //cy scales the y increment
x[2] = x[1] + (int)(xInc*count);
y[2] = y[1] + (int)(yInc*count);
x[3] = x[0] + (int)(xInc*count);
y[3] = y[0] + (int)(yInc*count);
imp.setRoi(new PolygonRoi(x, y, 4, PolygonRoi.FREEROI));
}
int getOutputStackSize(double inSpacing, double outSpacing, int count) {
Roi roi = imp.getRoi();
int width = imp.getWidth();
int height = imp.getHeight();
if (roi!=null) {
Rectangle r = roi.getBounds();
width = r.width;
width = r.height;
}
int type = roi!=null?roi.getType():0;
int stackSize = imp.getStackSize();
double size = 0.0;
if (type==Roi.RECTANGLE) {
size = width*height*stackSize;
if (outSpacing>0&&!nointerpolate) size *= inSpacing/outSpacing;
} else
size = gLength*count*stackSize;
int bits = imp.getBitDepth();
switch (bits) {
case 16: size*=2; break;
case 24: case 32: size*=4; break;
}
return (int)Math.round(size/1048576.0);
}
int getAvailableMemory() {
long max = IJ.maxMemory();
if (max==0) return -1;
long inUse = IJ.currentMemory();
long available = max - inUse;
return (int)((available+524288L)/1048576L);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy