All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ij.plugin.Duplicator Maven / Gradle / Ivy

Go to download

ImageJ is an open source Java image processing program inspired by NIH Image for the Macintosh.

There is a newer version: 1.54m
Show newest version
package ij.plugin;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.util.Tools;
import ij.plugin.frame.Recorder;
import ij.measure.Calibration;

/** This plugin implements the Image/Duplicate command.
   // test script
   img1 = IJ.getImage();
   img2 = new Duplicator().run(img1);
   //img2 = new Duplicator().run(img1,1,10);
   img2.show();
*/ public class Duplicator implements PlugIn, TextListener, ItemListener { private static boolean staticDuplicateStack; private static boolean staticIgnoreSelection; private static boolean ignoreNextSelection; private boolean duplicateStack; private boolean ignoreSelection; private int first, last; private Checkbox stackCheckbox; private TextField titleField, rangeField; private TextField[] rangeFields; private int firstC, lastC, firstZ, lastZ, firstT, lastT; private String defaultTitle; private String sliceLabel; private ImagePlus imp; private boolean legacyMacro; private boolean titleChanged; private GenericDialog gd; public void run(String arg) { imp = IJ.getImage(); Roi roiA = imp.getRoi(); ImagePlus impA = imp; boolean isRotatedRect = (roiA!=null && roiA instanceof RotatedRectRoi); if (isRotatedRect) { Rectangle bounds = imp.getRoi().getBounds(); imp.setRoi(bounds); } if (roiA!=null) { Rectangle r = roiA.getBounds(); if (r.x>=imp.getWidth() || r.y>=imp.getHeight() || r.x+r.width<=0 || r.y+r.height<=0) { IJ.error("Roi is outside image"); return; } } int stackSize = imp.getStackSize(); String title = imp.getTitle(); String newTitle = WindowManager.getUniqueName(imp, title); defaultTitle = newTitle; duplicateStack = staticDuplicateStack && !IJ.isMacro(); ignoreSelection = (staticIgnoreSelection||ignoreNextSelection) && Macro.getOptions()==null; if (!IJ.altKeyDown()||stackSize>1) { if (imp.isHyperStack() || imp.isComposite()) { duplicateHyperstack(imp, newTitle); if (isRotatedRect) { straightenRotatedRect(impA, roiA, IJ.getImage()); } return; } else newTitle = showDialog(imp, "Duplicate...", "Title: "); } if (newTitle==null) { if (isRotatedRect) imp.setRoi(roiA); return; } ImagePlus imp2; Roi roi = imp.getRoi(); if (ignoreSelection && roi!=null) imp.deleteRoi(); if (duplicateStack && (first>1||last1 && imp2.getStackSize()==stackSize) imp2.setSlice(imp.getCurrentSlice()); if (isRotatedRect) straightenRotatedRect(impA, roiA, imp2); } private void recordCrop(ImagePlus imp) { if (!Recorder.record) return; if (imp.getStackSize()==1) { if (imp.getRoi()==null || ignoreSelection) Recorder.recordCall("imp = imp.duplicate();"); else Recorder.recordCall("imp = imp.crop();"); } else if (imp.getRoi()==null || ignoreSelection) { if (duplicateStack) Recorder.recordCall("imp = imp.duplicate();"); else Recorder.recordCall("imp = imp.crop(\"whole-slice\");"); } else { if (duplicateStack) Recorder.recordCall("imp = imp.crop();"); else Recorder.recordCall("imp = imp.crop(\"slice\");"); } } /** Rotates duplicated part of image - impA is original image, - roiA is orig rotatedRect - impB contains duplicated overlapping bounding rectangle processing steps: - increase canvas of impB before rotation - rotate impB - calculate excentricity - translate to compensate excentricity - create orthogonal rectangle in center - crop to impC Author: N. Vischer */ private void straightenRotatedRect(ImagePlus impA, Roi roiA, ImagePlus impB) { impB.deleteRoi(); //we have it in roiA Color colorBack = Toolbar.getBackgroundColor(); IJ.setBackgroundColor(0,0,0); String title = impB.getTitle(); if(impB.getOverlay() != null) impB.getOverlay().clear(); int boundLeft = roiA.getBounds().x; int boundTop = roiA.getBounds().y; int boundWidth = roiA.getBounds().width; int boundHeight = roiA.getBounds().height; float[] xx = roiA.getFloatPolygon().xpoints; float[] yy = roiA.getFloatPolygon().ypoints; double dx1 = xx[1] - xx[0];//calc sides and angle double dy1 = yy[1] - yy[0]; double dx2 = xx[2] - xx[1]; double dy2 = yy[2] - yy[1]; double rrWidth = Math.sqrt(dx1 * dx1 + dy1 * dy1);//width of rot rect double rrHeight = Math.sqrt(dx2 * dx2 + dy2 * dy2); double rrDia = Math.sqrt(rrWidth * rrWidth + rrHeight * rrHeight); double phi1 = -Math.atan2(dy1, dx1); double phi0 = phi1 * 180 / Math.PI; double usedL = Math.max(boundLeft, 0); //usedrect is orthogonal rect to be rotated double usedR = Math.min(boundLeft + boundWidth, impA.getWidth()); double usedT = Math.max(boundTop, 0); double usedB = Math.min(boundTop + boundHeight, impA.getHeight()); double usedCX = (usedL + usedR) / 2; double usedCY = (usedT + usedB) / 2; //Center of UsedRect double boundsCX = boundLeft + boundWidth / 2;//Center of Bound = center of RotRect double boundsCY = boundTop + boundHeight / 2; double dx3 = boundsCX - usedCX;//calculate excentricity double dy3 = boundsCY - usedCY; double rad3 = Math.sqrt(dx3 * dx3 + dy3 * dy3); double phi3 = Math.atan2(dy3, dx3); double phi4 = phi3 + phi1; double dx4 = -rad3 * Math.cos(phi4); double dy4 = -rad3 * Math.sin(phi4); //Increase canvas to a square large enough for rotation ImageStack stackOld = impB.getStack(); int currentSlice = impB.getCurrentSlice(); double xOff = (rrDia - (usedR - usedL)) / 2;//put img in center double yOff = (rrDia - (usedB - usedT)) / 2; ImageStack stackNew = (new CanvasResizer()).expandStack(stackOld, (int) rrDia, (int) rrDia, (int) xOff, (int) yOff); impB.setStack(stackNew); ImageProcessor ip = impB.getProcessor(); ip.setInterpolationMethod(ImageProcessor.BILINEAR); ip.setBackgroundValue(0); for (int slc = 0; slc < stackNew.size(); slc++) { impB.setSlice(slc+1); ip.rotate(phi0); //Rotate ip.translate(dx4, dy4); //Translate } int x = (impB.getWidth() - (int) rrWidth) / 2; int y = (impB.getHeight() - (int) rrHeight) / 2; impB.setStack(impB.getStack().crop(x, y, 0, (int) rrWidth, (int) rrHeight, impB.getStack().getSize()));//Crop impB.setSlice(currentSlice); impB.setTitle(title); impB.show(); impB.updateAndDraw(); impA.setRoi(roiA); //restore rotated rect in source image Toolbar.setBackgroundColor(colorBack); } /** Returns a copy of the image, stack or hyperstack contained in the specified ImagePlus. * @see ij.ImagePlus#duplicate */ public ImagePlus run(ImagePlus imp) { if (imp.getStackSize()==1) return crop(imp); Rectangle rect = null; Roi roi = imp.getRoi(); Roi roi2 = cropRoi(imp, roi); if (roi2!=null && roi2.isArea()) rect = roi2.getBounds(); ImageStack stack = imp.getStack(); boolean virtualStack = stack.isVirtual(); double min = imp.getDisplayRangeMin(); double max = imp.getDisplayRangeMax(); ImageStack stack2 = null; int n = stack.size(); boolean showProgress = virtualStack || ((double)n*stack.getWidth()*stack.getHeight()>=209715200.0); for (int i=1; i<=n; i++) { if (showProgress) { IJ.showStatus("Duplicating: "+i+"/"+n); IJ.showProgress(i,n); } ImageProcessor ip2 = stack.getProcessor(i); ip2.setRoi(rect); ip2 = ip2.crop(); if (stack2==null) stack2 = new ImageStack(ip2.getWidth(), ip2.getHeight(), imp.getProcessor().getColorModel()); stack2.addSlice(stack.getSliceLabel(i), ip2); } IJ.showProgress(1.0); ImagePlus imp2 = imp.createImagePlus(); imp2.setStack("DUP_"+imp.getTitle(), stack2); String info = (String)imp.getProperty("Info"); if (info!=null) imp2.setProperty("Info", info); imp2.setProperties(imp.getPropertiesAsArray()); imp2.setCalibration(imp.getCalibration()); int[] dim = imp.getDimensions(); imp2.setDimensions(dim[2], dim[3], dim[4]); if (imp.isComposite()) { imp2 = new CompositeImage(imp2, 0); ((CompositeImage)imp2).copyLuts(imp); } if (virtualStack) imp2.setDisplayRange(min, max); if (imp.isHyperStack()) imp2.setOpenAsHyperStack(true); Overlay overlay = imp.getOverlay(); if (overlay!=null && !imp.getHideOverlay()) imp2.setOverlay(overlay.crop(rect)); if (Recorder.record) { if (imp.getRoi()==null || ignoreSelection) Recorder.recordCall("imp = imp.duplicate();"); else Recorder.recordCall("imp = imp.crop(\"stack\");"); } return imp2; } /** Returns a copy the current image or stack slice, cropped if there is a selection. * @see ij.ImagePlus#crop * @see ij.ImagePlus#crop(String) */ public ImagePlus crop(ImagePlus imp) { //if (imp!=null) throw new IllegalArgumentException(); if (imp.getNChannels()>1 && imp.getCompositeMode()==IJ.COMPOSITE) { int z = imp.getSlice(); int t = imp.getFrame(); return run(imp, 1, imp.getNChannels(), z, z, t, t); } boolean hyperstack = imp.isHyperStack(); int displayMode = imp.isComposite()?imp.getDisplayMode():0; ImageProcessor ip = imp.getProcessor(); ImageProcessor ip2 = ip.crop(); ImagePlus imp2 = imp.createImagePlus(); imp2.setProcessor("DUP_"+imp.getTitle(), ip2); String info = (String)imp.getProperty("Info"); if (info!=null) imp2.setProperty("Info", info); imp2.setProperties(imp.getPropertiesAsArray()); if (imp.isStack()) { ImageStack stack = imp.getStack(); String label = stack.getSliceLabel(imp.getCurrentSlice()); if (label!=null) { if (label.length()>250 && label.indexOf('\n')>0 && label.contains("0002,")) imp2.setProperty("Info", label); // DICOM metadata else imp2.setProperty("Label", label); } if (imp.isComposite()) { LUT lut = ((CompositeImage)imp).getChannelLut(); if (displayMode==IJ.GRAYSCALE) imp2.getProcessor().setColorModel(null); else imp2.getProcessor().setColorModel(lut); } } else { String label = (String)imp.getProperty("Label"); if (label!=null) imp2.setProperty("Label", label); } Overlay overlay = imp.getOverlay(); if (overlay!=null && !imp.getHideOverlay()) { Overlay overlay2 = overlay.crop(ip.getRoi()); if (imp.getStackSize()>1) { if (hyperstack) { int c = imp.getC(); int z = imp.getZ(); int t = imp.getT(); overlay2.crop(c,c,z,z,t,t); } else overlay2.crop(imp.getCurrentSlice(), imp.getCurrentSlice()); } imp2.setOverlay(overlay2); } return imp2; } /** Returns a new stack containing a subrange of the specified stack. */ public ImagePlus run(ImagePlus imp, int firstSlice, int lastSlice) { Rectangle rect = null; Roi roi = imp.getRoi(); if (roi!=null && roi.isArea()) rect = roi.getBounds(); ImageStack stack = imp.getStack(); boolean virtualStack = stack.isVirtual(); double min = imp.getDisplayRangeMin(); double max = imp.getDisplayRangeMax(); ImageStack stack2 = null; int n = lastSlice-firstSlice+1; boolean showProgress = virtualStack || ((double)n*stack.getWidth()*stack.getHeight()>=209715200.0); for (int i=firstSlice; i<=lastSlice; i++) { if (showProgress) { IJ.showStatus("Duplicating: "+i+"/"+lastSlice); IJ.showProgress(i-firstSlice,n); } ImageProcessor ip2 = stack.getProcessor(i); ip2.setRoi(rect); ip2 = ip2.crop(); if (stack2==null) stack2 = new ImageStack(ip2.getWidth(), ip2.getHeight(), imp.getProcessor().getColorModel()); stack2.addSlice(stack.getSliceLabel(i), ip2); } IJ.showProgress(1.0); ImagePlus imp2 = imp.createImagePlus(); imp2.setStack("DUP_"+imp.getTitle(), stack2); String info = (String)imp.getProperty("Info"); if (info!=null) imp2.setProperty("Info", info); imp2.setProperties(imp.getPropertiesAsArray()); int size = stack2.getSize(); boolean tseries = imp.getNFrames()==imp.getStackSize(); if (tseries) imp2.setDimensions(1, 1, size); else imp2.setDimensions(1, size, 1); if (virtualStack) imp2.setDisplayRange(min, max); Overlay overlay = imp.getOverlay(); if (overlay!=null && !imp.getHideOverlay()) { Overlay overlay2 = overlay.crop(rect); overlay2.crop(firstSlice, lastSlice); imp2.setOverlay(overlay2); } if (Recorder.record) Recorder.recordCall("imp = imp.crop(\""+firstSlice+"-"+lastSlice+"\");"); return imp2; } /** Returns a new hyperstack containing a possibly reduced version of the input image. */ public ImagePlus run(ImagePlus imp, int firstC, int lastC, int firstZ, int lastZ, int firstT, int lastT) { Rectangle rect = null; Roi roi = imp.getRoi(); Roi roi2 = cropRoi(imp, roi); if (roi2!=null && roi2.isArea()) rect = roi2.getBounds(); ImageStack stack = imp.getStack(); ImageStack stack2 = null; for (int t=firstT; t<=lastT; t++) { for (int z=firstZ; z<=lastZ; z++) { for (int c=firstC; c<=lastC; c++) { int n1 = imp.getStackIndex(c, z, t); ImageProcessor ip = stack.getProcessor(n1); String label = stack.getSliceLabel(n1); ip.setRoi(rect); ip = ip.crop(); if (stack2==null) stack2 = new ImageStack(ip.getWidth(), ip.getHeight(), null); stack2.addSlice(label, ip); } } } ImagePlus imp2 = imp.createImagePlus(); imp2.setStack("DUP_"+imp.getTitle(), stack2); imp2.setDimensions(lastC-firstC+1, lastZ-firstZ+1, lastT-firstT+1); if (imp.isComposite()) { int mode =imp.getDisplayMode(); if (lastC>firstC) { imp2 = new CompositeImage(imp2, mode); int i2 = 1; for (int i=firstC; i<=lastC; i++) { LUT lut = ((CompositeImage)imp).getChannelLut(i); ((CompositeImage)imp2).setChannelLut(lut, i2++); } if (imp.getNChannels()==imp2.getNChannels()) { boolean[] active = ((CompositeImage)imp).getActiveChannels(); boolean[] active2 = ((CompositeImage)imp2).getActiveChannels(); if (active!=null && active2!=null && active.length==active2.length) { for (int i=0; i1 && duplicateStack && !isMacro; legacyMacro = options!=null && (options.contains("duplicate")||!options.contains("use")); String title = getNewTitle(); if (title==null) title=defaultTitle; GenericDialog gd = new GenericDialog(dialogTitle); this.gd = gd; gd.addStringField(prompt, title, 15); if (isRoi) gd.addCheckbox("Ignore selection", ignoreSelection); if (stackSize>1) { gd.addCheckbox("Duplicate stack", duplicateStack); gd.setInsets(2, 30, 3); gd.addStringField("Range:", "1-"+stackSize); if (!isMacro) { stackCheckbox = (Checkbox)(gd.getCheckboxes().elementAt(gd.getCheckboxes().size()-1)); stackCheckbox.addItemListener(this); Vector v = gd.getStringFields(); titleField = (TextField)v.elementAt(0); rangeField = (TextField)v.elementAt(1); titleField.addTextListener(this); rangeField.addTextListener(this); } } gd.setSmartRecording(true); gd.showDialog(); if (gd.wasCanceled()) return null; title = gd.getNextString(); if (isRoi) ignoreSelection = gd.getNextBoolean(); if (stackSize>1) { duplicateStack = gd.getNextBoolean(); if (duplicateStack) { String[] range = Tools.split(gd.getNextString(), " -"); double d1 = gd.parseDouble(range[0]); double d2 = range.length==2?gd.parseDouble(range[1]):Double.NaN; first = Double.isNaN(d1)?1:(int)d1; last = Double.isNaN(d2)?stackSize:(int)d2; if (first<1) first = 1; if (last>stackSize) last = stackSize; if (first>last) {first=1; last=stackSize;} } else { first = 1; last = stackSize; } } if (!isMacro) { staticDuplicateStack = duplicateStack; if (!ignoreNextSelection) staticIgnoreSelection=ignoreSelection; } ignoreNextSelection = false; if (Recorder.record && titleField!=null && titleField.getText().equals(sliceLabel)) Recorder.recordOption("use"); return title; } private String getNewTitle() { if (titleChanged) return null; String title = defaultTitle; if (imp.getStackSize()>1 && !duplicateStack && !legacyMacro && (stackCheckbox==null||!stackCheckbox.getState())) { ImageStack stack = imp.getStack(); String label = stack.getShortSliceLabel(imp.getCurrentSlice()); if (label!=null && label.length()==0) label = null; if (label!=null) { title = label; sliceLabel = label; } } return title; } void duplicateHyperstack(ImagePlus imp, String newTitle) { newTitle = showHSDialog(imp, newTitle); if (newTitle==null) return; ImagePlus imp2 = null; Roi roi = imp.getRoi(); if (!duplicateStack) { int nChannels = imp.getNChannels(); boolean singleComposite = imp.isComposite() && nChannels==imp.getStackSize(); if (!singleComposite && nChannels>1 && imp.isComposite() && ((CompositeImage)imp).getMode()==IJ.COMPOSITE) { firstC = 1; lastC = nChannels; } else firstC = lastC = imp.getChannel(); firstZ = lastZ = imp.getSlice(); firstT = lastT = imp.getFrame(); } imp2 = run(imp, firstC, lastC, firstZ, lastZ, firstT, lastT); if (imp2==null) return; imp2.setTitle(newTitle); if (imp2.getWidth()==0 || imp2.getHeight()==0) { IJ.error("Duplicator", "Selection is outside the image"); return; } if (roi!=null && roi.isArea() && roi.getType()!=Roi.RECTANGLE) { Roi roi2 = (Roi)cropRoi(imp, roi).clone(); roi2.setLocation(0, 0); imp2.setRoi(roi2); } imp2.show(); imp2.setPosition(imp.getC(), imp.getZ(), imp.getT()); if (IJ.isMacro()&&imp2.getWindow()!=null) IJ.wait(50); } String showHSDialog(ImagePlus imp, String newTitle) { int nChannels = imp.getNChannels(); int nSlices = imp.getNSlices(); int nFrames = imp.getNFrames(); boolean composite = imp.isComposite() && nChannels==imp.getStackSize(); String options = Macro.getOptions(); boolean isMacro = options!=null; GenericDialog gd = new GenericDialog("Duplicate"); gd.addStringField("Title:", newTitle, 15); gd.setInsets(12, 20, 8); gd.addCheckbox("Duplicate hyperstack", (duplicateStack&&!isMacro)||composite); int nRangeFields = 0; if (nChannels>1) { gd.setInsets(2, 30, 3); gd.addStringField("Channels (c):", "1-"+nChannels); nRangeFields++; } if (nSlices>1) { gd.setInsets(2, 30, 3); gd.addStringField("Slices (z):", "1-"+nSlices); nRangeFields++; } if (nFrames>1) { gd.setInsets(2, 30, 3); gd.addStringField("Frames (t):", "1-"+nFrames); nRangeFields++; } if (!isMacro) { stackCheckbox = (Checkbox)(gd.getCheckboxes().elementAt(gd.getCheckboxes().size()-1)); stackCheckbox.addItemListener(this); Vector v = gd.getStringFields(); rangeFields = new TextField[3]; for (int i=0; i1) { String[] range = Tools.split(gd.getNextString(), " -"); double c1 = gd.parseDouble(range[0]); double c2 = range.length==2?gd.parseDouble(range[1]):Double.NaN; firstC = Double.isNaN(c1)?1:(int)c1; lastC = Double.isNaN(c2)?firstC:(int)c2; if (firstC<1) firstC = 1; if (lastC>nChannels) lastC = nChannels; if (firstC>lastC) {firstC=1; lastC=nChannels;} } else firstC = lastC = 1; if (nSlices>1) { String[] range = Tools.split(gd.getNextString(), " -"); double z1 = gd.parseDouble(range[0]); double z2 = range.length==2?gd.parseDouble(range[1]):Double.NaN; firstZ = Double.isNaN(z1)?1:(int)z1; lastZ = Double.isNaN(z2)?firstZ:(int)z2; if (firstZ<1) firstZ = 1; if (lastZ>nSlices) lastZ = nSlices; if (firstZ>lastZ) {firstZ=1; lastZ=nSlices;} } else firstZ = lastZ = 1; if (nFrames>1) { String[] range = Tools.split(gd.getNextString(), " -"); double t1 = gd.parseDouble(range[0]); double t2 = range.length==2?gd.parseDouble(range[1]):Double.NaN; firstT= Double.isNaN(t1)?1:(int)t1; lastT = Double.isNaN(t2)?firstT:(int)t2; if (firstT<1) firstT = 1; if (lastT>nFrames) lastT = nFrames; if (firstT>lastT) {firstT=1; lastT=nFrames;} } else firstT = lastT = 1; if (!isMacro) staticDuplicateStack = duplicateStack; return newTitle; } /* * Returns the part of 'roi' overlaping 'imp' * Author Marcel Boeglin 2013.12.15 */ Roi cropRoi(ImagePlus imp, Roi roi) { if (roi==null) return null; if (imp==null) return roi; Rectangle b = roi.getBounds(); int w = imp.getWidth(); int h = imp.getHeight(); if (b.x<0 || b.y<0 || b.x+b.width>w || b.y+b.height>h) { ShapeRoi shape1 = new ShapeRoi(roi); ShapeRoi shape2 = new ShapeRoi(new Roi(0, 0, w, h)); roi = shape2.and(shape1); } if (roi.getBounds().width==0 || roi.getBounds().height==0) throw new IllegalArgumentException("Selection is outside the image"); return roi; } public static Overlay cropOverlay(Overlay overlay, Rectangle bounds) { return overlay.crop(bounds); } public void textValueChanged(TextEvent e) { if (IJ.debugMode) IJ.log("Duplicator.textValueChanged: "+e); if (e.getSource()==titleField) { if (!titleField.getText().equals(getNewTitle())) titleChanged = true; } else stackCheckbox.setState(true); } public void itemStateChanged(ItemEvent e) { duplicateStack = stackCheckbox.getState(); if (titleField!=null) { String title = getNewTitle(); if (title!=null && !title.equals(titleField.getText())) { titleField.setText(title); if (gd!=null) gd.setDefaultString(0, title); } } } public static void ignoreNextSelection() { ignoreNextSelection = true; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy