imageJ.BinaryOrbit Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of orbit-image-analysis Show documentation
Show all versions of orbit-image-analysis Show documentation
Orbit, a versatile image analysis software for biological image-based quantification
package imageJ;
import ij.IJ;
import ij.ImagePlus;
import ij.Prefs;
import ij.gui.DialogListener;
import ij.gui.GenericDialog;
import ij.plugin.filter.EDM;
import ij.plugin.filter.ExtendedPlugInFilter;
import ij.plugin.filter.PlugInFilterRunner;
import ij.plugin.frame.ThresholdAdjuster;
import ij.process.ByteProcessor;
import ij.process.FloodFiller;
import ij.process.ImageProcessor;
import java.awt.*;
/** Implements the Erode, Dilate, Open, Close, Outline, Skeletonize
and Fill Holes commands in the Process/Binary submenu.
Gabriel Landini contributed the clever binary fill algorithm
that fills holes in objects by filling the background.
Version 2009-06-23 preview added, interations can be aborted by escape (Michael Schmid)
*/
public class BinaryOrbit implements ExtendedPlugInFilter, DialogListener {
static final int MAX_ITERATIONS = 100;
static final String NO_OPERATION = "Nothing";
static final String[] outputTypes = {"Overwrite", "8-bit", "16-bit", "32-bit"};
static final String[] operations = {NO_OPERATION, "Erode", "Dilate", "Open", "Close", "Outline", "Fill Holes", "Skeletonize"};
//parameters / options
static int iterations = 1; //iterations for erode, dilate, open, close
static int count = 1; //nearest neighbor count for erode, dilate, open, close
String operation = NO_OPERATION; //for dialog; will be copied to 'arg' for actual previewing
String arg;
ImagePlus imp; //null if only setting options with no preview possibility
PlugInFilterRunner pfr;
boolean doOptions; //whether options dialog is required
boolean previewing;
boolean escapePressed;
int foreground, background;
int flags = DOES_8G | DOES_8C | SUPPORTS_MASKING | PARALLELIZE_STACKS | KEEP_PREVIEW | KEEP_THRESHOLD;
int nPasses;
public int setup(String arg, ImagePlus imp) {
this.arg = arg;
IJ.register(BinaryOrbit.class);
doOptions = arg.equals("options");
if (doOptions) {
if (imp == null) return NO_IMAGE_REQUIRED; //options dialog does not need a (suitable) image
ImageProcessor ip = imp.getProcessor();
if (!(ip instanceof ByteProcessor)) return NO_IMAGE_REQUIRED;
if (!ip.isBinary()) return NO_IMAGE_REQUIRED;
}
return flags;
}
public int showDialog (ImagePlus imp, String command, PlugInFilterRunner pfr) {
if (doOptions) {
this.imp = imp;
this.pfr = pfr;
GenericDialog gd = new GenericDialog("Binary Options");
gd.addNumericField("Iterations (1-"+MAX_ITERATIONS+"):", iterations, 0, 3, "");
gd.addNumericField("Count (1-8):", count, 0, 3, "");
gd.addCheckbox("Black background", Prefs.blackBackground);
gd.addCheckbox("Pad edges when eroding", Prefs.padEdges);
gd.addChoice("EDM output:", outputTypes, outputTypes[EDM.getOutputType()]);
if (imp != null) {
gd.addChoice("Do:", operations, operation);
gd.addPreviewCheckbox(pfr);
gd.addDialogListener(this);
previewing = true;
}
gd.addHelp(IJ.URL+"/docs/menus/process.html#options");
gd.showDialog();
previewing = false;
if (gd.wasCanceled()) return DONE;
if (imp==null) { //options dialog only, no do/preview
dialogItemChanged(gd, null); //read dialog result
return DONE;
}
return operation.equals(NO_OPERATION) ? DONE : IJ.setupDialog(imp, flags);
} else { //no dialog, 'arg' is operation type
if (!imp.getProcessor().isBinary()) {
IJ.error("8-bit binary (black and white only) image required.");
return DONE;
}
return IJ.setupDialog(imp, flags);
}
}
public boolean dialogItemChanged (GenericDialog gd, AWTEvent e) {
iterations = (int)gd.getNextNumber();
count = (int)gd.getNextNumber();
boolean bb = Prefs.blackBackground;
Prefs.blackBackground = gd.getNextBoolean();
if ( Prefs.blackBackground!=bb)
ThresholdAdjuster.update();
Prefs.padEdges = gd.getNextBoolean();
EDM.setOutputType(gd.getNextChoiceIndex());
boolean isInvalid = gd.invalidNumber();
if (iterations<1) {iterations = 1; isInvalid = true;}
if (iterations>MAX_ITERATIONS) {iterations = MAX_ITERATIONS; isInvalid = true;}
if (count < 1) {count = 1; isInvalid = true;}
if (count > 8) {count = 8; isInvalid = true;}
if (isInvalid) return false;
if (imp != null) {
operation = gd.getNextChoice();
arg = operation.toLowerCase();
}
return true;
}
public void setNPasses (int nPasses) {
this.nPasses = nPasses;
}
public void run (ImageProcessor ip) {
int fg = Prefs.blackBackground ? 255 : 0;
foreground = ip.isInvertedLut() ? 255-fg : fg;
background = 255 - foreground;
ip.setSnapshotCopyMode(true);
if (arg.equals("outline"))
outline(ip);
else if (arg.startsWith("fill"))
fill(ip, foreground, background);
else if (arg.startsWith("skel")) {
ip.resetRoi(); skeletonize(ip);
} else if (arg.equals("erode") || arg.equals("dilate"))
doIterations(ip, arg);
else if (arg.equals("open")) {
doIterations(ip, "erode");
doIterations(ip, "dilate");
} else if (arg.equals("close")) {
doIterations(ip, "dilate");
doIterations(ip, "erode");
}
ip.setSnapshotCopyMode(false);
ip.setBinaryThreshold();
}
void doIterations (ImageProcessor ip, String mode) {
if (escapePressed) return;
if (!previewing && iterations>1)
IJ.showStatus(arg+"... press ESC to cancel");
for (int i=0; i