All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.mianalysis.mia.module.visualise.overlays.AddContourLines Maven / Gradle / Ivy

Go to download

ModularImageAnalysis (MIA) is an ImageJ plugin which provides a modular framework for assembling image and object analysis workflows. Detected objects can be transformed, filtered, measured and related. Analysis workflows are batch-enabled by default, allowing easy processing of high-content datasets.

There is a newer version: 1.6.12
Show newest version
package io.github.mianalysis.mia.module.visualise.overlays;

import java.awt.Color;
import java.awt.Font;
import java.awt.image.IndexColorModel;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;

import org.scijava.Priority;
import org.scijava.plugin.Plugin;
import org.scijava.vecmath.Point2d;

import com.drew.lang.annotations.Nullable;

import ij.ImagePlus;
import ij.gui.PolygonRoi;
import ij.gui.Roi;
import ij.gui.ShapeRoi;
import ij.gui.TextRoi;
import ij.plugin.Duplicator;
import ij.plugin.HyperStackConverter;
import ij.plugin.filter.ThresholdToSelection;
import ij.process.FloatPolygon;
import ij.process.ImageProcessor;
import io.github.mianalysis.mia.module.Categories;
import io.github.mianalysis.mia.module.Category;
import io.github.mianalysis.mia.module.Module;
import io.github.mianalysis.mia.module.Modules;
import io.github.mianalysis.mia.object.Workspace;
import io.github.mianalysis.mia.object.image.Image;
import io.github.mianalysis.mia.object.image.ImageFactory;
import io.github.mianalysis.mia.object.imagej.LUTs;
import io.github.mianalysis.mia.object.parameters.BooleanP;
import io.github.mianalysis.mia.object.parameters.ChoiceP;
import io.github.mianalysis.mia.object.parameters.InputImageP;
import io.github.mianalysis.mia.object.parameters.OutputImageP;
import io.github.mianalysis.mia.object.parameters.Parameters;
import io.github.mianalysis.mia.object.parameters.SeparatorP;
import io.github.mianalysis.mia.object.parameters.text.DoubleP;
import io.github.mianalysis.mia.object.parameters.text.IntegerP;
import io.github.mianalysis.mia.object.refs.collections.ImageMeasurementRefs;
import io.github.mianalysis.mia.object.refs.collections.MetadataRefs;
import io.github.mianalysis.mia.object.refs.collections.ObjMeasurementRefs;
import io.github.mianalysis.mia.object.refs.collections.ObjMetadataRefs;
import io.github.mianalysis.mia.object.refs.collections.ParentChildRefs;
import io.github.mianalysis.mia.object.refs.collections.PartnerRefs;
import io.github.mianalysis.mia.object.system.Status;
import io.github.mianalysis.mia.process.ColourFactory;
import io.github.mianalysis.mia.process.LabelFactory;
import io.github.mianalysis.mia.process.math.CumStat;


/**
* Adds overlay contour lines (and optional labels) to an image.  Lines correspond to contours of constant intensity in the input image.
*/
@Plugin(type = Module.class, priority=Priority.LOW, visible=true)
public class AddContourLines extends Module {

	/**
	* 
	*/
    public static final String INPUT_SEPARATOR = "Image input/output";

	/**
	* Image onto which overlay will be rendered.  Input image will only be updated if "Apply to input image" is enabled, otherwise the image containing the overlay will be stored as a new image with name specified by "Output image".
	*/
    public static final String INPUT_IMAGE = "Input image";

	/**
	* Determines if the modifications made to the input image (added overlay elements) will be applied to that image or directed to a new image.  When selected, the input image will be updated.
	*/
    public static final String APPLY_TO_INPUT = "Apply to input image";

	/**
	* If the modifications (overlay) aren't being applied directly to the input image, this control will determine if a separate image containing the overlay should be saved to the workspace.
	*/
    public static final String ADD_OUTPUT_TO_WORKSPACE = "Add output image to workspace";

	/**
	* The name of the new image to be saved to the workspace (if not applying the changes directly to the input image).
	*/
    public static final String OUTPUT_IMAGE = "Output image";


	/**
	* 
	*/
    public static final String COLOUR_SEPARATOR = "Contour colours";

	/**
	* Minimum contour magnitude to display.
	*/
    public static final String MINIMUM_INTENSITY = "Minimum intensity";

	/**
	* Maximum contour magnitude to display.
	*/
    public static final String MAXIMUM_INTENSITY = "Maximum intensity";

	/**
	* Number of different contour magnitudes to display.  Contour lines are equally spaced in magnitude between "Minimum intensity" and "Maximum intensity".
	*/
    public static final String NUMBER_OF_CONTOURS = "Number of contours";

	/**
	* Determines the colour look-up table to use when rendering the contours.  Colour corresponds to the magnitude of that contour line:

- "Black fire" Standard ImageJ "Fire" look-up table. Values taken from "https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java".

- "Ice" Standard ImageJ "Ice" look-up table. Values taken from "https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java".

- "Jet" Look-up table with colour progression blue, cyan, green, yellow, orange, red.

- "Physics" Standard Fiji "Physics" look-up table. Values taken from "https://github.com/fiji/fiji/tree/master/luts/physics.lut".

- "Random" Random sequence of colours.

- "Single colour" All contour lines have the same colour, determined by the "Contour colour" parameter.

- "Single colour gradient" Single colour gradient from the colour determined by the "Contour colour" parameter (lowest magnitude contour line) and white (highest magnitude contour line).

- "Spectrum" Standard ImageJ "Spectrum" look-up table. Values taken from "https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java".

- "Thermal" Standard Fiji "Thermal" look-up table. Values taken from "https://github.com/fiji/fiji/tree/master/luts/Thermal.lut".
*/ public static final String CONTOUR_COLOUR_MODE = "Contour colour mode"; /** * Contour colour used when "Contour colour mode" is set to either "Single colour" or "Single colour gradient". Choices are: White, Black, Red, Orange, Yellow, Green, Cyan, Blue, Violet, Magenta. */ public static final String CONTOUR_COLOUR = "Contour colour"; /** * */ public static final String RENDERING_SEPARATOR = "Contour rendering"; /** * Width of the rendered lines. Specified in pixel units. */ public static final String LINE_WIDTH = "Line width"; /** * Specifies the interval between plotted points on the contour line. This is useful when there are a lot of contour lines in an image and where a reduction in line precision isn't problematic. Plotting fewer points will reduce the memory required to store/display overlays. */ public static final String DRAW_EVERY_N_POINTS = "Draw every N points"; /** * */ public static final String LABEL_SEPARATOR = "Label rendering"; /** * Display magnitude values as text on each contour line. Labels are placed randomly on each contour and are oriented in line with the local contour line. */ public static final String SHOW_LABELS = "Show labels"; /** * Number of decimal places to use when displaying numeric values. */ public static final String DECIMAL_PLACES = "Decimal places"; /** * When enabled, numeric values will be displayed in the format 1.23E-3. Otherwise, the same value would appear as 0.00123. */ public static final String USE_SCIENTIFIC = "Use scientific notation"; /** * Determines the colour look-up table to use when rendering the contour labels. Colour corresponds to the magnitude of that contour line:

- "Black fire" Standard ImageJ "Fire" look-up table. Values taken from "https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java".

- "Ice" Standard ImageJ "Ice" look-up table. Values taken from "https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java".

- "Jet" Look-up table with colour progression blue, cyan, green, yellow, orange, red.

- "Physics" Standard Fiji "Physics" look-up table. Values taken from "https://github.com/fiji/fiji/tree/master/luts/physics.lut".

- "Random" Random sequence of colours.

- "Single colour" All contour line labels have the same colour, determined by the "Contour colour" parameter.

- "Single colour gradient" Single colour gradient from the colour determined by the "Contour colour" parameter (lowest magnitude contour line label) and white (highest magnitude contour line label).

- "Spectrum" Standard ImageJ "Spectrum" look-up table. Values taken from "https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java".

- "Thermal" Standard Fiji "Thermal" look-up table. Values taken from "https://github.com/fiji/fiji/tree/master/luts/Thermal.lut".
*/ public static final String LABEL_COLOUR_MODE = "Label colour mode"; /** * Contour line label colour used when "Contour colour mode" is set to either "Single colour" or "Single colour gradient". Choices are: White, Black, Red, Orange, Yellow, Green, Cyan, Blue, Violet, Magenta. */ public static final String LABEL_COLOUR = "Label colour"; /** * Font size of the text label. */ public static final String LABEL_SIZE = "Label size"; public interface ColourModes { String BLACK_FIRE = "Black fire"; String ICE = "Ice"; String JET = "Jet"; String PHYSICS = "Physics"; String RANDOM = "Random"; String SINGLE_COLOUR_GRADIENT = "Single colour gradient"; String SINGLE_COLOUR = "Single colour"; String SPECTRUM = "Spectrum"; String THERMAL = "Thermal"; String[] ALL = new String[] { BLACK_FIRE, ICE, JET, PHYSICS, RANDOM, SINGLE_COLOUR_GRADIENT, SINGLE_COLOUR, SPECTRUM, THERMAL }; } public interface SingleColours extends ColourFactory.SingleColours { } public AddContourLines(Modules modules) { super("Add contour lines", modules); } public static double[] getContourLevels(double minIntensity, double maxIntensity, int nContours) { double[] levels = new double[nContours]; double intensityWidth = (maxIntensity - minIntensity) / (nContours - 1); for (int i = 0; i < nContours; i++) levels[i] = minIntensity + i * intensityWidth; return levels; } public static HashMap getColours(double[] levels, String colourMode, @Nullable String singleColour) { HashMap colours = new HashMap<>(); double minIntensity = levels[0]; double maxIntensity = levels[levels.length - 1]; double range = maxIntensity - minIntensity; IndexColorModel cm = null; switch (colourMode) { case ColourModes.BLACK_FIRE: cm = LUTs.BlackFire().getColorModel(); break; case ColourModes.ICE: cm = LUTs.Ice().getColorModel(); break; case ColourModes.PHYSICS: cm = LUTs.Physics().getColorModel(); break; case ColourModes.RANDOM: cm = LUTs.Random(false).getColorModel(); break; case ColourModes.JET: cm = LUTs.Jet().getColorModel(); break; case ColourModes.SPECTRUM: cm = LUTs.Spectrum().getColorModel(); break; case ColourModes.THERMAL: cm = LUTs.Thermal().getColorModel(); break; } for (double level : levels) { // Finding normalised position within range float norm = ((float) (level - minIntensity)) / ((float) range); int idx = (int) Math.round(norm * 255); switch (colourMode) { case ColourModes.BLACK_FIRE: case ColourModes.ICE: case ColourModes.PHYSICS: case ColourModes.RANDOM: case ColourModes.JET: case ColourModes.SPECTRUM: case ColourModes.THERMAL: colours.put(level, new Color(cm.getRed(idx), cm.getGreen(idx), cm.getBlue(idx))); break; case ColourModes.SINGLE_COLOUR: colours.put(level, ColourFactory.getColour(singleColour)); break; case ColourModes.SINGLE_COLOUR_GRADIENT: float hue = ColourFactory.getHue(singleColour); colours.put(level, Color.getHSBColor(hue, 1 - norm, 1f)); break; } } return colours; } public static HashMap getLabels(double[] levels, int decimalPlaces, boolean useScientific) { HashMap labels = new HashMap<>(); DecimalFormat df = LabelFactory.getDecimalFormat(decimalPlaces, useScientific); for (double level : levels) { String label = df.format(level); labels.put(level, label); } return labels; } public static Roi getContour(ImageProcessor ipr, double level) { // We will be thresholding the ImageProcessor, so duplicating it first ipr = ipr.duplicate(); // Binarising image at specified level ipr.setThreshold(level, Double.MAX_VALUE, ImageProcessor.NO_LUT_UPDATE); // Getting ROI corresponding to binarised region return new ThresholdToSelection().convert(ipr); } public static void addOverlay(ImagePlus ipl, double[] levels, HashMap contourColours, double lineWidth, int drawEveryNPoints) { addOverlay(ipl, levels, contourColours, lineWidth, drawEveryNPoints, null, null, 0); } public static void addOverlay(ImagePlus ipl, double[] levels, HashMap contourColours, double lineWidth, int drawEveryNPoints, @Nullable HashMap labels, @Nullable HashMap labelColours, int labelSize) { if (ipl.getOverlay() == null) ipl.setOverlay(new ij.gui.Overlay()); for (int c = 0; c < ipl.getNChannels(); c++) { for (int z = 0; z < ipl.getNSlices(); z++) { for (int t = 0; t < ipl.getNFrames(); t++) { int[] pos = null; if (ipl.isHyperStack()) { pos = new int[] { c + 1, z + 1, t + 1 }; ipl.setPosition(pos[0], pos[1], pos[2]); } else { pos = new int[] { Math.max(Math.max(c, z), t) + 1 }; ipl.setPosition(pos[0]); } if (labelColours == null) { addOverlay(ipl.getProcessor(), ipl.getOverlay(), pos, levels, contourColours, lineWidth, drawEveryNPoints); } else { addOverlay(ipl.getProcessor(), ipl.getOverlay(), pos, levels, contourColours, lineWidth, drawEveryNPoints, labels, labelColours, labelSize); } } } } } public static void addOverlay(ImageProcessor ipr, ij.gui.Overlay overlay, int[] pos, double[] levels, HashMap contourColours, double lineWidth, int drawEveryNPoints) { for (double level : levels) { Roi contour = getContour(ipr, level); Color contourColour = contourColours.get(level); if (contour == null) continue; if (contour.getType() == Roi.COMPOSITE) { ShapeRoi shapeRoi = new ShapeRoi(contour); for (Roi roi : shapeRoi.getRois()) { addSingleLevelContour(ipr, roi, overlay, pos, level, contourColour, lineWidth, drawEveryNPoints, new ArrayList<>()); } } else { addSingleLevelContour(ipr, contour, overlay, pos, level, contourColour, lineWidth, drawEveryNPoints, new ArrayList<>()); } } } public static void addOverlay(ImageProcessor ipr, ij.gui.Overlay overlay, int[] pos, double[] levels, HashMap contourColours, double lineWidth, int drawEveryNPoints, HashMap labels, HashMap labelColours, int labelSize) { for (double level : levels) { Roi contour = getContour(ipr, level); Color contourColour = contourColours.get(level); String label = labels.get(level); Color labelColour = labelColours.get(level); if (contour == null) continue; if (contour.getType() == Roi.COMPOSITE) { ShapeRoi shapeRoi = new ShapeRoi(contour); for (Roi roi : shapeRoi.getRois()) { ArrayList labelRegion = getLabelPosition(ipr, roi, pos, label, labelSize); addSingleLevelContour(ipr, roi, overlay, pos, level, contourColour, lineWidth, drawEveryNPoints, labelRegion); addSingleLevelLabel(ipr, roi, overlay, pos, label, labelColour, labelSize, labelRegion); } } else { ArrayList labelRegion = getLabelPosition(ipr, contour, pos, label, labelSize); addSingleLevelContour(ipr, contour, overlay, pos, level, contourColour, lineWidth, drawEveryNPoints, labelRegion); addSingleLevelLabel(ipr, contour, overlay, pos, label, labelColour, labelSize, labelRegion); } } } public static ArrayList getLabelPosition(ImageProcessor ipr, Roi roi, int[] pos, String label, int labelSize) { Font font = new Font(Font.SANS_SERIF, Font.PLAIN, labelSize); int imWidth = ipr.getWidth(); int imHeight = ipr.getHeight(); // Creating label, so we know the width TextRoi textRoi = new TextRoi(0, 0, label, font); double width = textRoi.getFloatWidth(); // Ensuring there are enough points to draw the label FloatPolygon fp = roi.getInterpolatedPolygon(); if (fp.npoints < width * 4) return new ArrayList<>(); // Ensuring there are enough consecutive non-boundary points to draw the label ArrayList longestPath = getLongestNonBoundaryPath(fp, imWidth, imHeight); if (longestPath.size() < width * 4) return new ArrayList<>(); // Finding a location on the longest continuous part of the contour, // sufficiently far from one end ArrayList labelRegion = new ArrayList<>(); int startIdx = (int) Math.floor(0.25 * (longestPath.size() - 2 * width)); // int startIdx = (int) Math.floor(Math.random() * (longestPath.size() - 2.5 * // width)); int endIdx = startIdx + (int) Math.round(2 * width); for (int idx = startIdx; idx < endIdx; idx++) labelRegion.add(longestPath.get(idx)); return labelRegion; } static ArrayList getLongestNonBoundaryPath(FloatPolygon fp, int imWidth, int imHeight) { ArrayList nbp = new ArrayList<>(); ArrayList nbpMax = new ArrayList<>(); for (int i = 0; i < fp.npoints; i++) { float x = fp.xpoints[i]; float y = fp.ypoints[i]; if (x >= 1 && x < (imWidth - 1) && y >= 1 && y < (imHeight - 1)) { nbp.add(i); } else { if (nbp.size() > nbpMax.size()) nbpMax = new ArrayList<>(nbp); nbp = new ArrayList<>(); } } if (nbp.size() > nbpMax.size()) { nbpMax = new ArrayList<>(nbp); } return nbpMax; } public static void addSingleLevelContour(ImageProcessor ipr, Roi roi, ij.gui.Overlay overlay, int[] pos, double level, Color colour, double lineWidth, int drawEveryNPoints, ArrayList labelRegion) { int imWidth = ipr.getWidth(); int imHeight = ipr.getHeight(); FloatPolygon fp = roi.getInterpolatedPolygon(); FloatPolygon fpPlot = new FloatPolygon(); for (int i = 0; i < fp.npoints - drawEveryNPoints; i = i + drawEveryNPoints) { // Skip any points on the label region if (labelRegion.contains(i)) { addContourFragment(fpPlot, overlay, pos, colour, lineWidth); fpPlot = new FloatPolygon(); continue; } float x1 = fp.xpoints[i]; float y1 = fp.ypoints[i]; float x2 = fp.xpoints[i + drawEveryNPoints]; float y2 = fp.ypoints[i + drawEveryNPoints]; if (i >= fp.npoints - 2 * drawEveryNPoints) { x2 = fp.xpoints[0]; y2 = fp.ypoints[0]; } if ((x1 >= 1 && x1 < (imWidth - 1) && y1 >= 1 && y1 < (imHeight - 1)) || (x2 >= 1 && x2 < (imWidth - 1) && y2 >= 1 && y2 < (imHeight - 1))) { fpPlot.addPoint(x1, y1); if (i >= fp.npoints - 2 * drawEveryNPoints) fpPlot.addPoint(x2, y2); } else { addContourFragment(fpPlot, overlay, pos, colour, lineWidth); fpPlot = new FloatPolygon(); } } addContourFragment(fpPlot, overlay, pos, colour, lineWidth); } // new array, x=no~rows of array list items, y = no columns of array list // items#generate good public static void addContourFragment(FloatPolygon fp, ij.gui.Overlay overlay, int[] pos, Color colour, double lineWidth) { if (fp.npoints == 0) return; PolygonRoi line = new PolygonRoi(fp, PolygonRoi.FREELINE); line.setStrokeWidth(lineWidth); line.setStrokeColor(colour); if (pos.length > 1) { line.setPosition(pos[0], pos[1], pos[2]); } else { line.setPosition(pos[0]); } overlay.addElement(line); } public static void addSingleLevelLabel(ImageProcessor ipr, Roi roi, ij.gui.Overlay overlay, int[] pos, String label, Color colour, int labelSize, ArrayList labelRegion) { // If no label region was specified, don't add a label if (labelRegion.size() == 0) return; FloatPolygon fp = roi.getInterpolatedPolygon(); Font font = new Font(Font.SANS_SERIF, Font.PLAIN, labelSize); // Getting label centre CumStat csX = new CumStat(); CumStat csY = new CumStat(); for (int idx : labelRegion) { csX.addMeasure(fp.xpoints[idx]); csY.addMeasure(fp.ypoints[idx]); } double xCent = csX.getMean(); double yCent = csY.getMean(); // Adding text label double angle = getLabelOrientation(fp, labelRegion); TextRoi textRoi = createTextRoi(xCent, yCent, angle, label, font, overlay); textRoi.setStrokeColor(colour); if (pos.length > 1) { textRoi.setPosition(pos[0], pos[1], pos[2]); } else { textRoi.setPosition(pos[0]); } overlay.addElement(textRoi); } public static TextRoi createTextRoi(double xCent, double yCent, double angle, String text, Font font, ij.gui.Overlay overlay) { TextRoi textRoi = new TextRoi(xCent, yCent, text, font); double x0 = textRoi.getXBase(); double y0 = textRoi.getYBase(); double width = textRoi.getFloatWidth(); double height = textRoi.getFloatHeight(); Point2d p1 = new Point2d(x0, y0); Point2d pCent = new Point2d(x0 + width / 2 - 1, y0 + height / 2 - 1); Point2d pCentR = rotatePoint(pCent, p1, angle); double xBaseOffs = 2 * x0 - pCentR.x; double yBaseOffs = 2 * y0 - pCentR.y; textRoi.setLocation(xBaseOffs, yBaseOffs); textRoi.setAngle(angle); return textRoi; } public static Point2d rotatePoint(Point2d pIn, Point2d pRot, double angleD) { double angle = -Math.toRadians(angleD); double x1 = pIn.x - pRot.x; double y1 = pIn.y - pRot.y; double x2 = x1 * Math.cos(angle) - y1 * Math.sin(angle); double y2 = x1 * Math.sin(angle) + y1 * Math.cos(angle); pIn.x = x2 + pRot.x; pIn.y = y2 + pRot.y; return pIn; } public static double getLabelOrientation(FloatPolygon fp, ArrayList labelRegion) { int idx1 = labelRegion.get(0); int idx2 = labelRegion.get(labelRegion.size() - 1); float x1 = fp.xpoints[idx1]; float y1 = fp.ypoints[idx1]; float x2 = fp.xpoints[idx2]; float y2 = fp.ypoints[idx2]; if (x1 > x2) { return -Math.toDegrees(Math.atan2(y1 - y2, x1 - x2)); } else { return -Math.toDegrees(Math.atan2(y2 - y1, x2 - x1)); } } @Override public Category getCategory() { return Categories.VISUALISATION_OVERLAYS; } @Override public String getVersionNumber() { return "1.0.0"; } @Override public String getDescription() { return "Adds overlay contour lines (and optional labels) to an image. Lines correspond to contours of constant intensity in the input image."; } @Override protected Status process(Workspace workspace) { // Getting parameters boolean applyToInput = parameters.getValue(APPLY_TO_INPUT,workspace); boolean addOutputToWorkspace = parameters.getValue(ADD_OUTPUT_TO_WORKSPACE,workspace); String outputImageName = parameters.getValue(OUTPUT_IMAGE,workspace); // Getting input image String inputImageName = parameters.getValue(INPUT_IMAGE,workspace); Image inputImage = workspace.getImages().get(inputImageName); ImagePlus ipl = inputImage.getImagePlus(); double minIntensity = parameters.getValue(MINIMUM_INTENSITY,workspace); double maxIntensity = parameters.getValue(MAXIMUM_INTENSITY,workspace); int nContours = parameters.getValue(NUMBER_OF_CONTOURS,workspace); String contourColourMode = parameters.getValue(CONTOUR_COLOUR_MODE,workspace); String contourColour = parameters.getValue(CONTOUR_COLOUR,workspace); double lineWidth = parameters.getValue(LINE_WIDTH,workspace); int drawEveryNPoints = parameters.getValue(DRAW_EVERY_N_POINTS,workspace); boolean showLabels = parameters.getValue(SHOW_LABELS,workspace); int decimalPlaces = parameters.getValue(DECIMAL_PLACES,workspace); boolean useScientific = parameters.getValue(USE_SCIENTIFIC,workspace); String labelColourMode = parameters.getValue(LABEL_COLOUR_MODE,workspace); String labelColour = parameters.getValue(LABEL_COLOUR,workspace); int labelSize = parameters.getValue(LABEL_SIZE,workspace); // Only add output to workspace if not applying to input if (applyToInput) addOutputToWorkspace = false; // Duplicating the image, so the original isn't altered if (!applyToInput) ipl = new Duplicator().run(ipl); // If necessary, turning the image into a HyperStack (if 2 dimensions=1 it will // be a standard ImagePlus) if (!ipl.isComposite() & (ipl.getNSlices() > 1 | ipl.getNFrames() > 1 | ipl.getNChannels() > 1)) { ipl = HyperStackConverter.toHyperStack(ipl, ipl.getNChannels(), ipl.getNSlices(), ipl.getNFrames()); } // Getting intensity levels for contours double[] levels = getContourLevels(minIntensity, maxIntensity, nContours); HashMap contourColours = getColours(levels, contourColourMode, contourColour); if (showLabels) { HashMap labels = getLabels(levels, decimalPlaces, useScientific); HashMap labelColours = getColours(levels, labelColourMode, labelColour); addOverlay(ipl, levels, contourColours, lineWidth, drawEveryNPoints, labels, labelColours, labelSize); } else { addOverlay(ipl, levels, contourColours, lineWidth, drawEveryNPoints); } // If necessary, adding output image to workspace. This also allows us to show // it. Image outputImage = ImageFactory.createImage(outputImageName, ipl); if (addOutputToWorkspace) workspace.addImage(outputImage); if (showOutput) outputImage.show(); return Status.PASS; } @Override protected void initialiseParameters() { parameters.add(new SeparatorP(INPUT_SEPARATOR, this)); parameters.add(new InputImageP(INPUT_IMAGE, this)); parameters.add(new BooleanP(APPLY_TO_INPUT, this, false)); parameters.add(new BooleanP(ADD_OUTPUT_TO_WORKSPACE, this, false)); parameters.add(new OutputImageP(OUTPUT_IMAGE, this)); parameters.add(new SeparatorP(COLOUR_SEPARATOR, this)); parameters.add(new DoubleP(MINIMUM_INTENSITY, this, 0)); parameters.add(new DoubleP(MAXIMUM_INTENSITY, this, 255)); parameters.add(new IntegerP(NUMBER_OF_CONTOURS, this, 9)); parameters.add(new ChoiceP(CONTOUR_COLOUR_MODE, this, ColourModes.PHYSICS, ColourModes.ALL)); parameters.add(new ChoiceP(CONTOUR_COLOUR, this, SingleColours.WHITE, SingleColours.ALL)); parameters.add(new SeparatorP(RENDERING_SEPARATOR, this)); parameters.add(new DoubleP(LINE_WIDTH, this, 1)); parameters.add(new IntegerP(DRAW_EVERY_N_POINTS, this, 1)); parameters.add(new SeparatorP(LABEL_SEPARATOR, this)); parameters.add(new BooleanP(SHOW_LABELS, this, true)); parameters.add(new IntegerP(DECIMAL_PLACES, this, 0)); parameters.add(new BooleanP(USE_SCIENTIFIC, this, false)); parameters.add(new ChoiceP(LABEL_COLOUR_MODE, this, ColourModes.PHYSICS, ColourModes.ALL)); parameters.add(new ChoiceP(LABEL_COLOUR, this, SingleColours.WHITE, SingleColours.ALL)); parameters.add(new IntegerP(LABEL_SIZE, this, 12)); addParameterDescriptions(); } @Override public Parameters updateAndGetParameters() { Workspace workspace = null; Parameters returnedParameters = new Parameters(); returnedParameters.add(parameters.getParameter(INPUT_SEPARATOR)); returnedParameters.add(parameters.getParameter(INPUT_IMAGE)); returnedParameters.add(parameters.getParameter(APPLY_TO_INPUT)); if (!(boolean) parameters.getValue(APPLY_TO_INPUT,workspace)) { returnedParameters.add(parameters.getParameter(ADD_OUTPUT_TO_WORKSPACE)); if ((boolean) parameters.getValue(ADD_OUTPUT_TO_WORKSPACE,workspace)) { returnedParameters.add(parameters.getParameter(OUTPUT_IMAGE)); } } returnedParameters.add(parameters.getParameter(COLOUR_SEPARATOR)); returnedParameters.add(parameters.getParameter(MINIMUM_INTENSITY)); returnedParameters.add(parameters.getParameter(MAXIMUM_INTENSITY)); returnedParameters.add(parameters.getParameter(NUMBER_OF_CONTOURS)); returnedParameters.add(parameters.getParameter(CONTOUR_COLOUR_MODE)); switch ((String) parameters.getValue(CONTOUR_COLOUR_MODE,workspace)) { case ColourModes.SINGLE_COLOUR: case ColourModes.SINGLE_COLOUR_GRADIENT: returnedParameters.add(parameters.getParameter(CONTOUR_COLOUR)); break; } returnedParameters.add(parameters.getParameter(RENDERING_SEPARATOR)); returnedParameters.add(parameters.getParameter(LINE_WIDTH)); returnedParameters.add(parameters.getParameter(DRAW_EVERY_N_POINTS)); returnedParameters.add(parameters.getParameter(LABEL_SEPARATOR)); returnedParameters.add(parameters.getParameter(SHOW_LABELS)); if ((boolean) parameters.getValue(SHOW_LABELS,workspace)) { returnedParameters.add(parameters.getParameter(DECIMAL_PLACES)); returnedParameters.add(parameters.getParameter(USE_SCIENTIFIC)); returnedParameters.add(parameters.getParameter(LABEL_COLOUR_MODE)); switch ((String) parameters.getValue(LABEL_COLOUR_MODE,workspace)) { case ColourModes.SINGLE_COLOUR: case ColourModes.SINGLE_COLOUR_GRADIENT: returnedParameters.add(parameters.getParameter(LABEL_COLOUR)); break; } returnedParameters.add(parameters.getParameter(LABEL_SIZE)); } return returnedParameters; } @Override public ImageMeasurementRefs updateAndGetImageMeasurementRefs() { return null; } @Override public ObjMeasurementRefs updateAndGetObjectMeasurementRefs() { return null; } @Override public ObjMetadataRefs updateAndGetObjectMetadataRefs() { return null; } @Override public MetadataRefs updateAndGetMetadataReferences() { return null; } @Override public ParentChildRefs updateAndGetParentChildRefs() { return null; } @Override public PartnerRefs updateAndGetPartnerRefs() { return null; } @Override public boolean verify() { return true; } void addParameterDescriptions() { parameters.get(INPUT_IMAGE) .setDescription("Image onto which overlay will be rendered. Input image will only be updated if \"" + APPLY_TO_INPUT + "\" is enabled, otherwise the image containing the overlay will be stored as a new image with name specified by \"" + OUTPUT_IMAGE + "\"."); parameters.get(APPLY_TO_INPUT).setDescription( "Determines if the modifications made to the input image (added overlay elements) will be applied to that image or directed to a new image. When selected, the input image will be updated."); parameters.get(ADD_OUTPUT_TO_WORKSPACE).setDescription( "If the modifications (overlay) aren't being applied directly to the input image, this control will determine if a separate image containing the overlay should be saved to the workspace."); parameters.get(OUTPUT_IMAGE).setDescription( "The name of the new image to be saved to the workspace (if not applying the changes directly to the input image)."); parameters.get(MINIMUM_INTENSITY).setDescription("Minimum contour magnitude to display."); parameters.get(MAXIMUM_INTENSITY).setDescription("Maximum contour magnitude to display."); parameters.get(NUMBER_OF_CONTOURS).setDescription( "Number of different contour magnitudes to display. Contour lines are equally spaced in magnitude between \"" + MINIMUM_INTENSITY + "\" and \"" + MAXIMUM_INTENSITY + "\"."); parameters.get(CONTOUR_COLOUR_MODE).setDescription( "Determines the colour look-up table to use when rendering the contours. Colour corresponds to the magnitude of that contour line:
" + "
- \"" + ColourModes.BLACK_FIRE + "\" Standard ImageJ \"Fire\" look-up table. Values taken from \"https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java\".
" + "
- \"" + ColourModes.ICE + "\" Standard ImageJ \"Ice\" look-up table. Values taken from \"https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java\".
" + "
- \"" + ColourModes.JET + "\" Look-up table with colour progression blue, cyan, green, yellow, orange, red.
" + "
- \"" + ColourModes.PHYSICS + "\" Standard Fiji \"Physics\" look-up table. Values taken from \"https://github.com/fiji/fiji/tree/master/luts/physics.lut\".
" + "
- \"" + ColourModes.RANDOM + "\" Random sequence of colours.
" + "
- \"" + ColourModes.SINGLE_COLOUR + "\" All contour lines have the same colour, determined by the \"" + CONTOUR_COLOUR + "\" parameter.
" + "
- \"" + ColourModes.SINGLE_COLOUR_GRADIENT + "\" Single colour gradient from the colour determined by the \"" + CONTOUR_COLOUR + "\" parameter (lowest magnitude contour line) and white (highest magnitude contour line).
" + "
- \"" + ColourModes.SPECTRUM + "\" Standard ImageJ \"Spectrum\" look-up table. Values taken from \"https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java\".
" + "
- \"" + ColourModes.THERMAL + "\" Standard Fiji \"Thermal\" look-up table. Values taken from \"https://github.com/fiji/fiji/tree/master/luts/Thermal.lut\".
"); parameters.get(CONTOUR_COLOUR) .setDescription("Contour colour used when \"" + CONTOUR_COLOUR_MODE + "\" is set to either \"" + ColourModes.SINGLE_COLOUR + "\" or \"" + ColourModes.SINGLE_COLOUR_GRADIENT + "\". Choices are: " + String.join(", ", SingleColours.ALL) + "."); parameters.get(LINE_WIDTH).setDescription("Width of the rendered lines. Specified in pixel units."); parameters.get(DRAW_EVERY_N_POINTS).setDescription( "Specifies the interval between plotted points on the contour line. This is useful when there are a lot of contour lines in an image and where a reduction in line precision isn't problematic. Plotting fewer points will reduce the memory required to store/display overlays."); parameters.get(SHOW_LABELS).setDescription( "Display magnitude values as text on each contour line. Labels are placed randomly on each contour and are oriented in line with the local contour line."); parameters.get(DECIMAL_PLACES) .setDescription("Number of decimal places to use when displaying numeric values."); parameters.get(USE_SCIENTIFIC).setDescription( "When enabled, numeric values will be displayed in the format 1.23E-3. Otherwise, the same value would appear as 0.00123."); parameters.get(LABEL_COLOUR_MODE).setDescription( "Determines the colour look-up table to use when rendering the contour labels. Colour corresponds to the magnitude of that contour line:
" + "
- \"" + ColourModes.BLACK_FIRE + "\" Standard ImageJ \"Fire\" look-up table. Values taken from \"https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java\".
" + "
- \"" + ColourModes.ICE + "\" Standard ImageJ \"Ice\" look-up table. Values taken from \"https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java\".
" + "
- \"" + ColourModes.JET + "\" Look-up table with colour progression blue, cyan, green, yellow, orange, red.
" + "
- \"" + ColourModes.PHYSICS + "\" Standard Fiji \"Physics\" look-up table. Values taken from \"https://github.com/fiji/fiji/tree/master/luts/physics.lut\".
" + "
- \"" + ColourModes.RANDOM + "\" Random sequence of colours.
" + "
- \"" + ColourModes.SINGLE_COLOUR + "\" All contour line labels have the same colour, determined by the \"" + CONTOUR_COLOUR + "\" parameter.
" + "
- \"" + ColourModes.SINGLE_COLOUR_GRADIENT + "\" Single colour gradient from the colour determined by the \"" + CONTOUR_COLOUR + "\" parameter (lowest magnitude contour line label) and white (highest magnitude contour line label).
" + "
- \"" + ColourModes.SPECTRUM + "\" Standard ImageJ \"Spectrum\" look-up table. Values taken from \"https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/LookUpTable.java\".
" + "
- \"" + ColourModes.THERMAL + "\" Standard Fiji \"Thermal\" look-up table. Values taken from \"https://github.com/fiji/fiji/tree/master/luts/Thermal.lut\".
"); parameters.get(LABEL_COLOUR).setDescription("Contour line label colour used when \"" + CONTOUR_COLOUR_MODE + "\" is set to either \"" + ColourModes.SINGLE_COLOUR + "\" or \"" + ColourModes.SINGLE_COLOUR_GRADIENT + "\". Choices are: " + String.join(", ", SingleColours.ALL) + "."); parameters.get(LABEL_SIZE).setDescription("Font size of the text label."); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy