|
MontageMaker |
|
package ij.plugin;
import ij.*;
import ij.gui.*;
import ij.process.*;
import ij.measure.Calibration;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
/** Implements the Image/Stacks/Make Montage command. */
public class MontageMaker implements PlugIn {
private static int columns, rows, first, last, inc, borderWidth;
private static double scale;
private static boolean label;
private static boolean useForegroundColor;
private static int saveID;
public void run(String arg) {
ImagePlus imp = WindowManager.getCurrentImage();
if (imp==null || imp.getStackSize()==1)
{IJ.error("Stack required"); return;}
makeMontage(imp);
saveID = imp.getID();
IJ.register(MontageMaker.class);
}
public void makeMontage(ImagePlus imp) {
int nSlices = imp.getStackSize();
if (columns==0 || imp.getID()!=saveID) {
columns = (int)Math.sqrt(nSlices);
rows = columns;
int n = nSlices - columns*rows;
if (n>0) columns += (int)Math.ceil((double)n/rows);
scale = 1.0;
if (imp.getWidth()*columns>800)
scale = 0.5;
if (imp.getWidth()*columns>1600)
scale = 0.25;
inc = 1;
first = 1;
last = nSlices;
}
GenericDialog gd = new GenericDialog("Make Montage", IJ.getInstance());
gd.addNumericField("Columns:", columns, 0);
gd.addNumericField("Rows:", rows, 0);
gd.addNumericField("Scale Factor:", scale, 2);
gd.addNumericField("First Slice:", first, 0);
gd.addNumericField("Last Slice:", last, 0);
gd.addNumericField("Increment:", inc, 0);
gd.addNumericField("Border Width:", borderWidth, 0);
gd.addCheckbox("Label Slices", label);
gd.addCheckbox("Use Foreground Color", useForegroundColor);
gd.showDialog();
if (gd.wasCanceled())
return;
columns = (int)gd.getNextNumber();
rows = (int)gd.getNextNumber();
scale = gd.getNextNumber();
first = (int)gd.getNextNumber();
last = (int)gd.getNextNumber();
inc = (int)gd.getNextNumber();
borderWidth = (int)gd.getNextNumber();
if (borderWidth<0) borderWidth = 0;
if (first<1) first = 1;
if (last>nSlices) last = nSlices;
if (first>last)
{first=1; last=nSlices;}
if (inc<1) inc = 1;
if (gd.invalidNumber()) {
IJ.error("Invalid number");
return;
}
label = gd.getNextBoolean();
useForegroundColor = gd.getNextBoolean();
makeMontage(imp, columns, rows, scale, first, last, inc, borderWidth, label);
}
public void makeMontage(ImagePlus imp, int columns, int rows, double scale, int first, int last, int inc, int borderWidth, boolean labels) {
int stackWidth = imp.getWidth();
int stackHeight = imp.getHeight();
int nSlices = imp.getStackSize();
int width = (int)(stackWidth*scale);
int height = (int)(stackHeight*scale);
int montageWidth = width*columns;
int montageHeight = height*rows;
ImageProcessor ip = imp.getProcessor();
ImageProcessor montage = ip.createProcessor(montageWidth+borderWidth/2, montageHeight+borderWidth/2);
Color fgColor=Color.white;
Color bgColor = Color.black;
if (useForegroundColor) {
fgColor = Toolbar.getForegroundColor();
bgColor = Toolbar.getBackgroundColor();
} else {
boolean whiteBackground = false;
if ((ip instanceof ByteProcessor) || (ip instanceof ColorProcessor)) {
ImageStatistics is = imp.getStatistics();
whiteBackground = is.mode>=200;
if (imp.isInvertedLut())
whiteBackground = !whiteBackground;
}
if (whiteBackground) {
fgColor=Color.black;
bgColor = Color.white;
}
}
montage.setColor(bgColor);
montage.fill();
montage.setColor(fgColor);
ImageStack stack = imp.getStack();
int x = 0;
int y = 0;
ImageProcessor aSlice;
int slice = first;
while (slice<=last) {
aSlice = stack.getProcessor(slice);
if (scale!=1.0)
aSlice = aSlice.resize(width, height);
montage.insert(aSlice, x, y);
String label = stack.getShortSliceLabel(slice);
if (borderWidth>0) drawBorder(montage, x, y, width, height, borderWidth);
if (labels) drawLabel(montage, slice, label, x, y, width, height);
x += width;
if (x>=montageWidth) {
x = 0;
y += height;
if (y>=montageHeight)
break;
}
IJ.showProgress((double)(slice-first)/(last-first));
slice += inc;
}
if (borderWidth>0) {
int w2 = borderWidth/2;
drawBorder(montage, w2, w2, montageWidth-w2, montageHeight-w2, borderWidth);
}
IJ.showProgress(1.0);
ImagePlus imp2 = new ImagePlus("Montage", montage);
imp2.setCalibration(imp.getCalibration());
Calibration cal = imp2.getCalibration();
if (cal.scaled()) {
cal.pixelWidth /= scale;
cal.pixelHeight /= scale;
}
imp2.setProperty("Info", "xMontage="+columns+"\nyMontage="+rows+"\n");
imp2.show();
}
void drawBorder(ImageProcessor montage, int x, int y, int width, int height, int borderWidth) {
montage.setLineWidth(borderWidth);
montage.moveTo(x, y);
montage.lineTo(x+width, y);
montage.lineTo(x+width, y+height);
montage.lineTo(x, y+height);
montage.lineTo(x, y);
}
void drawLabel(ImageProcessor montage, int slice, String label, int x, int y, int width, int height) {
if (label!=null && !label.equals("") && montage.getStringWidth(label)>=width) {
do {
label = label.substring(0, label.length()-1);
} while (label.length()>1 && montage.getStringWidth(label)>=width);
}
if (label==null || label.equals(""))
label = ""+slice;
int swidth = montage.getStringWidth(label);
x += width/2 - swidth/2;
y += height;
montage.moveTo(x, y);
montage.drawString(label);
}
}
|
MontageMaker |
|