package ij.process;
import java.awt.*;
import java.awt.image.*;
import ij.*;
import ij.gui.*;
import ij.measure.*;
/** This class does stack type conversions. */
public class StackConverter {
ImagePlus imp;
int type, nSlices, width, height;
public StackConverter(ImagePlus imp) {
this.imp = imp;
type = imp.getType();
nSlices = imp.getStackSize();
if (nSlices<2)
throw new IllegalArgumentException("Stack required");
width = imp.getWidth();
height = imp.getHeight();
}
/** Converts this Stack to 8-bit grayscale. */
public void convertToGray8() {
ImageStack stack1 = imp.getStack();
int currentSlice = imp.getCurrentSlice();
ImageProcessor ip = imp.getProcessor();
boolean colorLut = ip.isColorLut();
boolean pseudoColorLut = colorLut && ip.isPseudoColorLut();
if (type==ImagePlus.GRAY8 && pseudoColorLut) {
boolean invertedLut = ip.isInvertedLut();
ip.setColorModel(LookUpTable.createGrayscaleColorModel(invertedLut));
stack1.setColorModel(ip.getColorModel());
imp.updateAndDraw();
return;
}
if (type==ImagePlus.COLOR_RGB || type==ImagePlus.COLOR_256 || colorLut) {
convertRGBToGray8();
imp.setSlice(currentSlice);
return;
}
ImageStack stack2 = new ImageStack(width, height);
Image img;
String label;
double min = ip.getMin();
double max = ip.getMax();
int inc = nSlices/20;
if (inc<1) inc = 1;
LUT[] luts = imp.isComposite()?((CompositeImage)imp).getLuts():null;
for(int i=1; i<=nSlices; i++) {
label = stack1.getSliceLabel(1);
ip = stack1.getProcessor(1);
stack1.deleteSlice(1);
if (luts!=null) {
int index = (i-1)%luts.length;
min = luts[index].min;
max = luts[index].max;
}
ip.setMinAndMax(min, max);
boolean scale = ImageConverter.getDoScaling();
stack2.addSlice(label, ip.convertToByte(scale));
if ((i%inc)==0) {
IJ.showProgress((double)i/nSlices);
IJ.showStatus("Converting to 8-bits: "+i+"/"+nSlices);
}
}
imp.setStack(null, stack2);
imp.setCalibration(imp.getCalibration()); //update calibration
if (imp.isComposite()) {
((CompositeImage)imp).resetDisplayRanges();
((CompositeImage)imp).updateAllChannelsAndDraw();
}
imp.setSlice(currentSlice);
IJ.showProgress(1.0);
}
/** Converts an RGB or 8-bit color stack to 8-bit grayscale. */
void convertRGBToGray8() {
ImageStack stack1 = imp.getStack();
ImageStack stack2 = new ImageStack(width, height);
ImageProcessor ip;
Image img;
String label;
int inc = nSlices/20;
if (inc<1) inc = 1;
for(int i=1; i<=nSlices; i++) {
label = stack1.getSliceLabel(1);
ip = stack1.getProcessor(1);
stack1.deleteSlice(1);
if (ip instanceof ByteProcessor)
ip = new ColorProcessor(ip.createImage());
boolean scale = ImageConverter.getDoScaling();
stack2.addSlice(label, ip.convertToByte(scale));
if ((i%inc)==0) {
IJ.showProgress((double)i/nSlices);
IJ.showStatus("Converting to 8-bits: "+i+"/"+nSlices);
}
}
imp.setStack(null, stack2);
IJ.showProgress(1.0);
}
/** Converts this Stack to 16-bit grayscale. */
public void convertToGray16() {
if (type==ImagePlus.GRAY16)
return;
if (!(type==ImagePlus.GRAY8 || type==ImagePlus.GRAY32))
throw new IllegalArgumentException("Unsupported conversion");
ImageStack stack1 = imp.getStack();
ImageStack stack2 = new ImageStack(width, height);
String label;
int inc = nSlices/20;
if (inc<1) inc = 1;
boolean scale = type==ImagePlus.GRAY32 && ImageConverter.getDoScaling();
ImageProcessor ip1, ip2;
for(int i=1; i<=nSlices; i++) {
label = stack1.getSliceLabel(1);
ip1 = stack1.getProcessor(1);
ip2 = ip1.convertToShort(scale);
stack1.deleteSlice(1);
stack2.addSlice(label, ip2);
if ((i%inc)==0) {
IJ.showProgress((double)i/nSlices);
IJ.showStatus("Converting to 16-bits: "+i+"/"+nSlices);
}
}
IJ.showProgress(1.0);
imp.setStack(null, stack2);
}
/** Converts this Stack to 32-bit (float) grayscale. */
public void convertToGray32() {
if (type==ImagePlus.GRAY32)
return;
if (!(type==ImagePlus.GRAY8||type==ImagePlus.GRAY16))
throw new IllegalArgumentException("Unsupported conversion");
ImageStack stack1 = imp.getStack();
ImageStack stack2 = new ImageStack(width, height);
String label;
int inc = nSlices/20;
if (inc<1) inc = 1;
ImageProcessor ip1, ip2;
Calibration cal = imp.getCalibration();
for(int i=1; i<=nSlices; i++) {
label = stack1.getSliceLabel(1);
ip1 = stack1.getProcessor(1);
ip1.setCalibrationTable(cal.getCTable());
ip2 = ip1.convertToFloat();
stack1.deleteSlice(1);
stack2.addSlice(label, ip2);
if ((i%inc)==0) {
IJ.showProgress((double)i/nSlices);
IJ.showStatus("Converting to 32-bits: "+i+"/"+nSlices);
}
}
IJ.showProgress(1.0);
imp.setStack(null, stack2);
imp.setCalibration(imp.getCalibration()); //update calibration
}
/** Converts the Stack to RGB. */
public void convertToRGB() {
if (imp.isComposite())
throw new IllegalArgumentException("Use Image>Color>Stack to RGB");
ImageStack stack1 = imp.getStack();
ImageStack stack2 = new ImageStack(width, height);
String label;
int inc = nSlices/20;
if (inc<1) inc = 1;
ImageProcessor ip1, ip2;
Calibration cal = imp.getCalibration();
for(int i=1; i<=nSlices; i++) {
label = stack1.getSliceLabel(i);
ip1 = stack1.getProcessor(i);
ip2 = ip1.convertToRGB();
stack2.addSlice(label, ip2);
if ((i%inc)==0) {
IJ.showProgress((double)i/nSlices);
IJ.showStatus("Converting to RGB: "+i+"/"+nSlices);
}
}
IJ.showProgress(1.0);
imp.setStack(null, stack2);
imp.setCalibration(imp.getCalibration()); //update calibration
}
/** Converts the stack (which must be RGB) to a
3 channel (red, green and blue) hyperstack. */
public void convertToRGBHyperstack() {
if (type!=ImagePlus.COLOR_RGB)
throw new IllegalArgumentException("RGB stack required");
new ij.plugin.CompositeConverter().run("composite");
}
/** Converts the stack (which must be RGB) to a 3 channel
(hue, saturation and brightness) hyperstack. */
public void convertToHSBHyperstack() {
if (type!=ImagePlus.COLOR_RGB)
throw new IllegalArgumentException("RGB stack required");
ImageStack stack1 = imp.getStack();
ImageStack stack2 = new ImageStack(width,height);
int nSlices = stack1.getSize();
Calibration cal = imp.getCalibration();
int inc = nSlices/20;
if (inc<1) inc = 1;
for(int i=1; i<=nSlices; i++) {
String label = stack1.getSliceLabel(i);
ColorProcessor cp = (ColorProcessor)stack1.getProcessor(i);
ImageStack stackHSB = cp.getHSBStack();
stack2.addSlice(label,stackHSB.getProcessor(1));
stack2.addSlice(label,stackHSB.getProcessor(2));
stack2.addSlice(label,stackHSB.getProcessor(3));
if ((i%inc)==0) {
IJ.showProgress((double)i/nSlices);
IJ.showStatus("Converting to HSB: "+i+"/"+nSlices);
}
}
IJ.showProgress(1.0);
imp.setStack(null,stack2);
imp.setCalibration(cal);
imp.setDimensions(3, nSlices, 1);
CompositeImage ci = new CompositeImage(imp, CompositeImage.GRAYSCALE);
ci.show();
imp.hide();
}
/** Converts the stack to 8-bits indexed color. 'nColors' must
be greater than 1 and less than or equal to 256. */
public void convertToIndexedColor(int nColors) {
if (type!=ImagePlus.COLOR_RGB)
throw new IllegalArgumentException("RGB stack required");
ImageStack stack = imp.getStack();
int size = stack.getSize();
ImageProcessor montage = new ColorProcessor(width*size, height);
for (int i=0; i<size; i++)
montage.insert(stack.getProcessor(i+1), i*width, 0);
MedianCut mc = new MedianCut((ColorProcessor)montage);
montage = mc.convertToByte(nColors);
ImageStack stack2 = new ImageStack(width, height);
for (int i=0; i<size; i++) {
montage.setRoi(i*width, 0, width, height);
stack2.addSlice(null, montage.crop());
}
imp.setStack(null, stack2);
}
}