// // Slicer.java // /* LOCI Plugins for ImageJ: a collection of ImageJ plugins including the Bio-Formats Importer, Bio-Formats Exporter, Bio-Formats Macro Extensions, Data Browser and Stack Slicer. Copyright (C) 2005-@year@ Melissa Linkert, Curtis Rueden and Christopher Peterson. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package loci.plugins; import ij.CompositeImage; import ij.IJ; import ij.ImagePlus; import ij.ImageStack; import ij.Macro; import ij.gui.GenericDialog; import ij.measure.Calibration; import ij.plugin.filter.PlugInFilter; import ij.process.ImageProcessor; import ij.process.LUT; import java.io.IOException; import loci.formats.FormatException; import loci.formats.FormatTools; import loci.plugins.util.BFVirtualStack; import loci.plugins.util.ImageProcessorReader; import loci.plugins.util.LibraryChecker; import loci.plugins.util.VirtualImagePlus; import loci.plugins.util.WindowTools; /** * A plugin for splitting an image stack into separate * channels, focal planes and/or time points. * * <dl><dt><b>Source code:</b></dt> * <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/loci-plugins/src/loci/plugins/Slicer.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/loci-plugins/src/loci/plugins/Slicer.java;hb=HEAD">Gitweb</a></dd></dl> * * @author Melissa Linkert melissa at glencoesoftware.com */ public class Slicer implements PlugInFilter { // -- Fields -- /** Flag indicating whether last operation was canceled. */ public boolean canceled; /** Plugin options. */ private String arg; /** Current image stack. */ private ImagePlus imp; // -- Slicer methods -- public ImagePlus[] reslice(ImagePlus imp, boolean sliceC, boolean sliceZ, boolean sliceT, String stackOrder) { ImageStack stack = imp.getImageStack(); boolean hyperstack = imp.isHyperStack(); Calibration calibration = imp.getCalibration(); int sizeZ = imp.getNSlices(); int sizeC = imp.getNChannels(); int sizeT = imp.getNFrames(); int slicesPerStack = stack.getSize(); if (sliceZ) slicesPerStack /= sizeZ; if (sliceC) slicesPerStack /= sizeC; if (sliceT) slicesPerStack /= sizeT; int realSizeZ = sliceZ ? 1 : sizeZ; int realSizeC = sliceC ? 1 : sizeC; int realSizeT = sliceT ? 1 : sizeT; BFVirtualStack virtualStack = null; if (stack instanceof BFVirtualStack) { virtualStack = (BFVirtualStack) stack; } ImageStack[] newStacks = new ImageStack[stack.getSize() / slicesPerStack]; for (int i=0; i<newStacks.length; i++) { newStacks[i] = makeStack(stack); if (newStacks[i] == null) return null; } int stackZ = sliceZ ? sizeZ : 1; int stackC = sliceC ? sizeC : 1; int stackT = sliceT ? sizeT : 1; int[][] planeIndexes = new int[newStacks.length][slicesPerStack]; for (int i=0; i<sizeZ*sizeC*sizeT; i++) { int[] zct = FormatTools.getZCTCoords(stackOrder, sizeZ, sizeC, sizeT, stack.getSize(), i); int stackNdx = FormatTools.getIndex(stackOrder, stackZ, stackC, stackT, newStacks.length, sliceZ ? zct[0] : 0, sliceC ? zct[1] : 0, sliceT ? zct[2] : 0); String label = stack.getSliceLabel(i + 1); if (virtualStack != null) { ((BFVirtualStack) newStacks[stackNdx]).addSlice(label); int sliceNdx = FormatTools.getIndex(stackOrder, realSizeZ, realSizeC, realSizeT, slicesPerStack, sliceZ ? 0 : zct[0], sliceC ? 0 : zct[1], sliceT ? 0 : zct[2]); planeIndexes[stackNdx][sliceNdx] = i; } else { newStacks[stackNdx].addSlice(label, stack.getProcessor(i + 1)); } } ImagePlus[] newImps = new ImagePlus[newStacks.length]; double maxValue = Math.pow(2, imp.getBytesPerPixel() * 8) - 1; for (int i=0; i<newStacks.length; i++) { if (virtualStack != null) { ((BFVirtualStack) newStacks[i]).setPlaneIndexes(planeIndexes[i]); } int[] zct = FormatTools.getZCTCoords(stackOrder, stackZ, stackC, stackT, newStacks.length, i); if (imp.isComposite()) { CompositeImage composite = (CompositeImage) imp; if (composite.getMode() == CompositeImage.COLOR) { LUT lut = composite.getChannelLut(zct[1] + 1); newStacks[i].setColorModel(lut); } } String title = imp.getTitle(); title += " -"; if (sliceZ) title += " Z=" + zct[0]; if (sliceT) title += " T=" + zct[2]; if (sliceC) title += " C=" + zct[1]; ImagePlus p = null; if (virtualStack != null) { p = new VirtualImagePlus(title, newStacks[i]); ((VirtualImagePlus) p).setReader(virtualStack.getReader()); } else { p = new ImagePlus(title, newStacks[i]); } p.setProperty("Info", imp.getProperty("Info")); p.setDimensions(realSizeC, realSizeZ, realSizeT); p.setCalibration(calibration); p.setFileInfo(imp.getOriginalFileInfo()); if (!p.isComposite()) { p.setOpenAsHyperStack(hyperstack); } if (imp.isComposite() && !sliceC) { p = reorder(p, stackOrder, "XYCZT"); int mode = ((CompositeImage) imp).getMode(); newImps[i] = new CompositeImage(p, mode); } else newImps[i] = p; double max = imp.getDisplayRangeMax(); double min = imp.getDisplayRangeMin(); if (min > 0d || max < maxValue) { newImps[i].resetDisplayRange(); } else { newImps[i].setDisplayRange(min, max); } } return newImps; } /** Reorder the given ImagePlus's stack. */ public static ImagePlus reorder(ImagePlus imp, String origOrder, String newOrder) { ImageStack s = imp.getStack(); ImageStack newStack = new ImageStack(s.getWidth(), s.getHeight()); int z = imp.getNSlices(); int c = imp.getNChannels(); int t = imp.getNFrames(); int stackSize = s.getSize(); for (int i=0; i<stackSize; i++) { int ndx = FormatTools.getReorderedIndex( origOrder, newOrder, z, c, t, stackSize, i); newStack.addSlice(s.getSliceLabel(ndx + 1), s.getProcessor(ndx + 1)); } ImagePlus p = new ImagePlus(imp.getTitle(), newStack); p.setDimensions(c, z, t); p.setCalibration(imp.getCalibration()); p.setFileInfo(imp.getOriginalFileInfo()); return p; } // -- PlugInFilter methods -- public int setup(String arg, ImagePlus imp) { this.arg = arg; this.imp = imp; return DOES_ALL + NO_CHANGES; } public void run(ImageProcessor ip) { if (!LibraryChecker.checkJava() || !LibraryChecker.checkImageJ()) return; boolean sliceC = false; boolean sliceZ = false; boolean sliceT = false; String stackOrder = null; boolean keepOriginal = false; if (arg == null || arg.trim().equals("")) { // prompt for slicing options GenericDialog gd = new GenericDialog("Slicing options..."); gd.addCheckbox("Split_channels", false); gd.addCheckbox("Split_Z slices", false); gd.addCheckbox("Split_timepoints", false); gd.addCheckbox("Keep_original stack", false); gd.addChoice("Stack_order", new String[] {"XYCZT", "XYCTZ", "XYZCT", "XYZTC", "XYTCZ", "XYTZC"}, "XYCZT"); gd.showDialog(); if (gd.wasCanceled()) { canceled = true; return; } sliceC = gd.getNextBoolean(); sliceZ = gd.getNextBoolean(); sliceT = gd.getNextBoolean(); keepOriginal = gd.getNextBoolean(); stackOrder = gd.getNextChoice(); } else { sliceC = getBooleanValue("split_channels"); sliceZ = getBooleanValue("split_z"); sliceT = getBooleanValue("split_timepoints"); keepOriginal = getBooleanValue("keep_original"); stackOrder = Macro.getValue(arg, "stack_order", "XYCZT"); } if (imp.getImageStack().isVirtual()) { IJ.error("Slicer plugin cannot be used with virtual stacks.\n" + "Please convert the virtual stack using Image>Duplicate."); return; } ImagePlus[] newImps = reslice(imp, sliceC, sliceZ, sliceT, stackOrder); if (!keepOriginal) imp.close(); for (ImagePlus imp : newImps) imp.show(); } // -- Helper methods -- /** Gets the value of the given macro key as a boolean. */ private boolean getBooleanValue(String key) { return Boolean.valueOf(Macro.getValue(arg, key, "false")); } /** Returns a new ImageStack using the given ImageStack as a template. */ private ImageStack makeStack(ImageStack stack) { if (!(stack instanceof BFVirtualStack)) { return new ImageStack(stack.getWidth(), stack.getHeight()); } BFVirtualStack virtualStack = (BFVirtualStack) stack; String path = virtualStack.getPath(); ImageProcessorReader reader = virtualStack.getReader(); try { return new BFVirtualStack(path, reader, false, false, false); } catch (FormatException e) { WindowTools.reportException(e); } catch (IOException e) { WindowTools.reportException(e); } return null; } }