package ij.plugin;
import ij.*;
import ij.gui.*;
import ij.process.*;
import ij.measure.Calibration;
import java.awt.*;
import java.util.Vector;
/** Implements the Image/HyperStacks/Reduce Dimensionality command. */
public class HyperStackReducer implements PlugIn, DialogListener {
ImagePlus imp;
int channels1, slices1, frames1;
int channels2, slices2, frames2;
double imageSize;
static boolean keep = true;
/** Default constructor */
public HyperStackReducer() {
}
/** Constructs a HyperStackReducer using the specified source image. */
public HyperStackReducer(ImagePlus imp) {
this.imp = imp;
}
public void run(String arg) {
//IJ.log("HyperStackReducer-1");
imp = IJ.getImage();
if (!imp.isHyperStack()) {
IJ.error("Reducer", "HyperStack required");
return;
}
int width = imp.getWidth();
int height = imp.getHeight();
imageSize = width*height*imp.getBytesPerPixel()/(1024.0*1024.0);
channels1 = channels2 = imp.getNChannels();
slices1 = slices2 = imp.getNSlices();
frames1 = frames2 = imp.getNFrames();
if (!showDialog())
return;
//IJ.log("HyperStackReducer-2: "+keep+" "+channels2+" "+slices2+" "+frames2);
String title2 = keep?WindowManager.getUniqueName(imp.getTitle()):imp.getTitle();
ImagePlus imp2 = null;
if (keep) {
imp2 = IJ.createImage(title2, imp.getBitDepth()+"-bit", width, height, channels2*slices2*frames2);
if (imp2==null) return;
imp2.setDimensions(channels2, slices2, frames2);
imp2.setCalibration(imp.getCalibration());
imp2.setOpenAsHyperStack(true);
} else
imp2 = imp.createHyperStack(title2, channels2, slices2, frames2, imp.getBitDepth());
reduce(imp2);
if (channels2>1 && channels2==imp.getNChannels() && imp.isComposite()) {
int mode = ((CompositeImage)imp).getMode();
imp2 = new CompositeImage(imp2, mode);
((CompositeImage)imp2).copyLuts(imp);
} else {
imp2.setDisplayRange(imp.getDisplayRangeMin(), imp.getDisplayRangeMax());
if (imp.isComposite() && ((CompositeImage)imp).getMode()==CompositeImage.GRAYSCALE)
IJ.run(imp2, "Grays", "");
}
if (imp.getWindow()==null && !keep) {
imp.setImage(imp2);
return;
}
imp2.show();
//IJ.log("HyperStackReducer-4");
if (!keep) {
imp.changes = false;
imp.close();
}
}
public void reduce(ImagePlus imp2) {
int channels = imp2.getNChannels();
int slices = imp2.getNSlices();
int frames = imp2.getNFrames();
int c1 = imp.getChannel();
int z1 = imp.getSlice();
int t1 = imp.getFrame();
int i = 1;
int n = channels*slices*frames;
ImageStack stack = imp.getStack();
ImageStack stack2 = imp2.getStack();
for (int c=1; c<=channels; c++) {
if (channels==1) c = c1;
LUT lut = imp.isComposite()?((CompositeImage)imp).getChannelLut():null;
imp.setPositionWithoutUpdate(c, 1, 1);
ImageProcessor ip = imp.getProcessor();
double min = ip.getMin();
double max = ip.getMax();
for (int z=1; z<=slices; z++) {
if (slices==1) z = z1;
for (int t=1; t<=frames; t++) {
//IJ.showProgress(i++, n);
if (frames==1) t = t1;
//ip = stack.getProcessor(n1);
imp.setPositionWithoutUpdate(c, z, t);
ip = imp.getProcessor();
int n1 = imp.getStackIndex(c, z, t);
String label = stack.getSliceLabel(n1);
int n2 = imp2.getStackIndex(c, z, t);
if (stack2.getPixels(n2)!=null)
stack2.getProcessor(n2).insert(ip, 0, 0);
else
stack2.setPixels(ip.getPixels(), n2);
stack2.setSliceLabel(label, n2);
}
}
if (lut!=null) {
if (imp2.isComposite())
((CompositeImage)imp2).setChannelLut(lut);
else
imp2.getProcessor().setColorModel(lut);
}
imp2.getProcessor().setMinAndMax(min, max);
}
imp.setPosition(c1, z1, t1);
imp2.resetStack();
imp2.setPosition(1, 1, 1);
}
boolean showDialog() {
GenericDialog gd = new GenericDialog("Reduce");
gd.setInsets(10, 20, 5);
gd.addMessage("Create Image With:");
gd.setInsets(0, 35, 0);
if (channels1!=1) gd.addCheckbox("Channels ("+channels1+")", true);
gd.setInsets(0, 35, 0);
if (slices1!=1) gd.addCheckbox("Slices ("+slices1+")", true);
gd.setInsets(0, 35, 0);
if (frames1!=1) gd.addCheckbox("Frames ("+frames1+")", true);
gd.setInsets(5, 20, 0);
gd.addMessage(getNewDimensions()+" ");
gd.setInsets(15, 20, 0);
gd.addCheckbox("Keep Source", keep);
gd.addDialogListener(this);
gd.showDialog();
if (gd.wasCanceled())
return false;
else
return true;
}
public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
if (IJ.isMacOSX()) IJ.wait(100);
if (channels1!=1) channels2 = gd.getNextBoolean()?channels1:1;
if (slices1!=1) slices2 = gd.getNextBoolean()?slices1:1;
if (frames1!=1) frames2 = gd.getNextBoolean()?frames1:1;
keep = gd.getNextBoolean();
((Label)gd.getMessage()).setText(getNewDimensions());
return true;
}
String getNewDimensions() {
String s = channels2+"x"+slices2+"x"+frames2;
s += " ("+(int)Math.round(imageSize*channels2*slices2*frames2)+"MB)";
return(s);
}
}