/* * Multichannel_ZT-axis_Profile.bsh * IJ BAR: https://github.com/tferr/Scripts#scripts * * BeanShell script that extends Image>Stack>Plot Z-axis Profile to multichannel (composite) images. * It features a "live" option, guesses displayed lookup tables and ignores disabled channels (i.e., * those deselected in the "Channels" widget (Image>Color>Channels Tool). * * N.B.: * - Intensities (mean, min or max) are retrieved from active ROI or entire canvas if no ROI exists * - With hyperstacks, intensities can be averaged across Z-slices at each time point * - Limits of Y-axis are set to include data from all visible channels */ import ij.CompositeImage; import ij.IJ; import ij.ImagePlus; import ij.ImageStack; import ij.WindowManager; import ij.gui.GenericDialog; import ij.gui.Plot; import ij.gui.Roi; import ij.measure.Calibration; import ij.process.ImageProcessor; import ij.process.ImageStatistics; import ij.util.Tools; import java.awt.Color; import java.awt.image.IndexColorModel; import java.util.Arrays; /* Options for Plot's y-axis values */ String[] yOptions = new String[] {"Mean", "Max", "Min"}; /* Default choice for y-axis value */ String yOption = yOptions[0]; /* Default choice for calibrated x-axis */ boolean calibratedX = true; /* Default choice for Z-slice averaging */ boolean averageZ = true; /* Prompts user for settings. Returns false if user aborted prompt otherwise true. */ boolean showOptions() { GenericDialog gd = new GenericDialog("Multichannel Z/T-axis Profile"); gd.addRadioButtonGroup("Vertical y-axis:", super.yOptions, 1, 3, super.yOption); gd.setInsets(5, 20, 0); gd.addCheckbox("Average Z-dimension in time profiles", super.averageZ); gd.setInsets(20, 10, 0); gd.addMessage("Horizontal x-axis:"); gd.addCheckbox("Calibrated units", super.calibratedX);; gd.addHelp("https://github.com/tferr/Scripts/tree/master/Analysis#multichannel-zt-axis-profile"); gd.showDialog(); super.yOption = gd.getNextRadioButton(); super.averageZ = gd.getNextBoolean(); super.calibratedX = gd.getNextBoolean(); return !gd.wasCanceled(); } /* * Returns the multichannel plot: "Intensity vs time" (frames), or "Intensity vs * depth" (slices) if stack contains no time dimension. An "Intensity vs channel" * plot is not considered. */ Plot getPlot() { // Retrieve image properties ImageStack stack = imp.getImageStack(); Roi roi = imp.getRoi(); int channels = imp.getNChannels(); int slices = imp.getNSlices(); int frames = imp.getNFrames(); // Retrieve active channels and respective LUT colors. We could use // CompositeImage.getChannelColor() but as of IJ1.49 it requires each // channel to be activated (by ImagePlus.setPositionWithoutUpdate()) // which causes an annoying glich in the image canvas/c-slider Color[] colors; boolean[] states; if (imp.isComposite()) { CompositeImage ci = (CompositeImage)imp; states = ci.getActiveChannels(); colors = new Color[channels]; for (int c=0; cmax) max = value; } } return new double[] {min, max}; } /* Returns the ImageStatistics measure specified by the user */ double getIntensity(ImageStatistics stats) { if (super.yOption.equals(super.yOptions[0])) return stats.mean; else if (super.yOption.equals(super.yOptions[1])) return stats.max; else return stats.min; } /* * Returns the color associated with the specified LUT. See * ij.CompositeImage.getChannelColor() */ Color getLutColor(IndexColorModel cm) { int index = cm.getMapSize() - 1; int r = cm.getRed(index); int g = cm.getGreen(index); int b = cm.getBlue(index); if (r<100 || g<100 || b<100) return new Color(r, g, b); else return Color.BLACK; } /* Returns an array of colors with the specified size */ Color[] getUniqueColors(int n) { Color[] defaults = {Color.BLACK, Color.DARK_GRAY, Color.RED, Color.GREEN, Color.BLUE, Color.MAGENTA, Color.CYAN, Color.YELLOW}; Color[] newcolors = new Color[n]; for (int i=0; i