package edu.stanford.rsl.conrad.utils; import java.awt.Color; import edu.stanford.rsl.conrad.data.numeric.Grid2D; import edu.stanford.rsl.conrad.data.numeric.Grid3D; import edu.stanford.rsl.conrad.data.numeric.MultiChannelGrid2D; import edu.stanford.rsl.conrad.fitting.Function; import edu.stanford.rsl.conrad.fitting.LinearFunction; import edu.stanford.rsl.conrad.geometry.shapes.simple.PointND; import edu.stanford.rsl.conrad.geometry.splines.BSpline; import ij.ImageJ; import ij.ImagePlus; import ij.ImageStack; import ij.gui.Line; import ij.gui.Overlay; import ij.gui.Plot; import ij.process.FloatProcessor; import ij.process.ImageProcessor; public abstract class VisualizationUtil { public static synchronized Plot createPlot(String title, double [] yValues){ return createPlot(yValues, title, "Column", "Power"); } public static synchronized Plot createPlot(String title, float [] yValues){ double[] tmp = new double[yValues.length]; for(int i=0; i<yValues.length; ++i) tmp[i] = yValues[i]; return createPlot(tmp, title, "Column", "Power"); } public static synchronized Plot createPlot(float [] yValues){ double[] tmp = new double[yValues.length]; for(int i=0; i<yValues.length; ++i) tmp[i] = yValues[i]; return createPlot(tmp, "Current Plot", "Column", "Power"); } public static synchronized Plot createPlot(double [] yValues){ return createPlot(yValues, "Average Row Weighting", "Column", "Power"); } public static Plot createSplinePlot(BSpline spline){ int length = 100; double [] x = new double[length]; double [] y = new double[length]; for (int i = 0; i< length; i++){ PointND p = spline.evaluate(((double) i) / (length)); x[i] = p.get(0); y[i] = p.get(1); } return new Plot("Spline Plot", "x", "y", x, y); } public static Plot createPlot(double [] yValues, String title, String xLabel, String yLabel){ double [] xValues = new double [yValues.length]; double min = Double.MAX_VALUE; double max = -Double.MAX_VALUE; for (int i = 0; i < xValues.length; i ++){ min = (yValues[i] < min) ? yValues[i] : min; max = (yValues[i] > max) ? yValues[i] : max; xValues[i] = i + 1; } if (min == max){ max++; } Plot plot = new Plot(title, xLabel, yLabel, xValues, yValues, Plot.DEFAULT_FLAGS); plot.setLimits(1, xValues.length, min, max); return plot; } public static Plot createPlot(double [] xValues, double [] yValues, String title, String xLabel, String yLabel){ double miny = Double.MAX_VALUE; double maxy = -Double.MAX_VALUE; double minx = Double.MAX_VALUE; double maxx = -Double.MAX_VALUE; for (int i = 0; i < xValues.length; i ++){ miny = (yValues[i] < miny) ? yValues[i] : miny; maxy = (yValues[i] > maxy) ? yValues[i] : maxy; minx = (xValues[i] < minx) ? xValues[i] : minx; maxx = (xValues[i] > maxx) ? xValues[i] : maxx; } if (miny == maxy){ maxy++; } if (minx == maxx){ maxx++; } Plot plot = new Plot(title, xLabel, yLabel, xValues, yValues, Plot.DEFAULT_FLAGS); plot.setLimits(minx, maxx, miny, maxy); return plot; } public static Plot createComplexPowerPlot(double [] yValues, String title){ double [] absValues = new double [yValues.length / 2]; for (int i = 0; i < absValues.length; i ++){ absValues[i] = FFTUtil.abs(i, yValues); } return createPlot(absValues, title, "Frequency (Center = +/- Nyquist)", "Power"); } public static Plot createHalfComplexPowerPlot(double [] yValues, String title){ double [] absValues = new double [yValues.length / 4]; for (int i = 0; i < absValues.length; i ++){ absValues[i] = FFTUtil.abs(i, yValues); } return createPlot(absValues, title, "Frequency", "Power"); } public static Plot createHalfComplexPowerPlot(double [] yValues, double [] xValues, String title){ double [] absValues = new double [yValues.length / 4]; for (int i = 0; i < absValues.length; i ++){ absValues[i] = FFTUtil.abs(i, yValues); } return createPlot(xValues, absValues, title, "Frequency", "Power"); } public static Plot createComplexPowerPlot(double [] yValues){ return createComplexPowerPlot(yValues, "Complex Power Plot"); } public static ImagePlus showGrid2D(Grid2D grid, String title){ if (grid instanceof MultiChannelGrid2D){ MultiChannelGrid2D multiChannelGrid2D = (MultiChannelGrid2D) grid; ImagePlus imp = new ImagePlus(); ImageStack stack = new ImageStack(grid.getWidth(),grid.getHeight()); for (int c = 0; c < multiChannelGrid2D.getNumberOfChannels(); c++){ if (multiChannelGrid2D.getChannelNames() == null) { stack.addSlice("Channel " + c,ImageUtil.wrapGrid2D(multiChannelGrid2D.getChannel(c))); } else { stack.addSlice(multiChannelGrid2D.getChannelNames()[c],ImageUtil.wrapGrid2D(multiChannelGrid2D.getChannel(c))); } } imp.setStack(title, stack); imp.show(); return imp; } return showImageProcessor(ImageUtil.wrapGrid2D(grid), title); } public static ImagePlus showImageProcessor(ImageProcessor image, String title){ ImagePlus imp = new ImagePlus(); ImageStack stack = new ImageStack(image.getWidth(),image.getHeight()); stack.addSlice(title, image); imp.setStack(title, stack); imp.show(); return imp; } public static ImagePlus showImageProcessor(ImageProcessor image){ return showImageProcessor(image, "Untitled Image"); } public static ImagePlus showGrid3DX( Grid3D image, String title){ int[] size = image.getSize(); int nSlices = size[0]; int width = size[1]; int height = size[2]; System.out.print("Grid size: " + width + " X " + height + " X " + nSlices + ".\n" ); //this is more memory efficient to use grid3D directly new ImageJ(); ImagePlus imp = ImageUtil.wrapGrid3D(image, ""); imp.show(); imp.setTitle( title ); /* ImagePlus imp = new ImagePlus(); ImageStack stack = new ImageStack( width, height); for( int n = 0 ; n < nSlices; n++){ //System.out.print("Slice " + n + " \n" ); FloatProcessor slice = new FloatProcessor( width, height); for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { slice.setf(x, y, image.getAtIndex(n, x, y)); } } stack.addSlice( " " + n, slice ); } imp.setStack(title, stack); imp.show(); */ return imp; } public static ImagePlus showGrid3DX( Grid3D image){ return showGrid3DX( image, "Untitled Image"); } public static ImagePlus showGrid3DZ( Grid3D image, String title){ int[] size = image.getSize(); int width = size[0]; int height = size[1]; int nSlices = size[2]; System.out.print("Grid size: " + width + " X " + height + " X " + nSlices + ".\n" ); //not sure if imageJ could rotate the grid3D data, so i copy and rearrange the 3D image to show cornal view new ImageJ(); ImagePlus imp = new ImagePlus(); ImageStack stack = new ImageStack( width, height); for( int n = 0 ; n < nSlices; n++){ //System.out.print("Slice " + n + " \n" ); FloatProcessor slice = new FloatProcessor( width, height); for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { slice.setf(x, y, image.getAtIndex(x, y, n)); } } stack.addSlice( " " + n, slice ); } imp.setStack(title, stack); imp.show(); return imp; } public static ImagePlus showGrid3DZ( Grid3D image){ return showGrid3DZ( image, "Untitled Image"); } /** * Takes an image overlay for Image Plus images and draws a cross at the 2D position defined by pos. * @param ov the overlay to draw on * @param pos the position where the cross is to be drawn * @param slice the slice number where the point should be drawn * @param crossSize half the width of the cross' bounding box * @param col the color of the cross */ public static void printCrossAtPoint(Overlay ov, PointND pos, int slice, double crossSize, Color col){ double pos0 = pos.get(0)+0.5; double pos1 = pos.get(1)+0.5; Line line = new Line(pos0, pos1-crossSize, pos0, pos1+crossSize); line.setStrokeWidth(1); line.setStrokeColor(col); line.setPosition(slice+1); line.setStrokeWidth(0.5); ov.add(line); line = new Line(pos0-crossSize, pos1, pos0+crossSize, pos1); line.setStrokeWidth(1); line.setStrokeColor(col); line.setPosition(slice+1); line.setStrokeWidth(0.5); ov.add(line); } public static Plot plotCompareGrayValues(ImageProcessor before, ImageProcessor after, Function func){ double [] xp = new double[before.getWidth()*before.getHeight()]; double [] yp = new double[before.getWidth()*before.getHeight()]; for (int i=0;i<before.getWidth();i++){ for (int j=0;j<before.getHeight();j++){ xp[before.getHeight()*i+j] = before.getPixelValue(i, j); yp[before.getHeight()*i+j] = after.getPixelValue(i, j); } } return createScatterPlot(xp, yp, func); } public static Plot createScatterPlot(double [] xCoords, double [] yCoords, Function func){ return createScatterPlot("Plot", xCoords, yCoords, func); } public static Plot createScatterPlot(String title, double [] xCoords, double [] yCoords, Function func){ double margin = 0.15; int scale = 200; func.fitToPoints(xCoords, yCoords); float [] xVals = new float[scale]; float [] yVals = new float[scale]; double [] stats = DoubleArrayUtil.minAndMaxOfArray(xCoords); double range = (stats[1] - stats[0]) * (1+(2*margin)); for (int i=0;i<scale;i++){ double x = stats[0] - (range * margin) + ((i + 0.0) / scale) * range; xVals[i] = (float) x; yVals[i] = (float) func.evaluate(x); } double avg = 0; for (int i=0;i<xCoords.length;i++){ double other = func.evaluate(xCoords[i]); avg += Math.pow(other - yCoords[i],2); } avg /= xCoords.length; avg = Math.sqrt(avg); Plot plot = new Plot(title + " (r = "+DoubleArrayUtil.correlateDoubleArrays(xCoords, yCoords)+" SSIM: " + DoubleArrayUtil.computeSSIMDoubleArrays(xCoords, yCoords) + ") Model: " + func.toString() + " standard deviation along model: " + avg, "X", "Y", xVals, yVals, Plot.DEFAULT_FLAGS); plot.addPoints(xCoords, yCoords, Plot.CIRCLE); return plot; } /** * Creates a scatter plot for two given double arrays with the given title. * @param title The Title * @param xCoords the array for the x-coordinates * @param yCoords the array for the y-coordinates * @return the resulting plot. */ public static Plot createScatterPlot(String title, double [] xCoords, double [] yCoords){ Function func = new LinearFunction(); func.fitToPoints(xCoords, yCoords); double margin = 0.15; int scale = 200; float [] xVals = new float[scale]; float [] yVals = new float[scale]; double [] stats = DoubleArrayUtil.minAndMaxOfArray(xCoords); double range = (stats[1] - stats[0]) * (1+(2*margin)); for (int i=0;i<scale;i++){ double x = stats[0] - (range * margin) + ((i + 0.0) / scale) * range; xVals[i] = (float) x; yVals[i] = (float) func.evaluate(x); } Plot plot = new Plot(title + "Plot (r = "+DoubleArrayUtil.correlateDoubleArrays(xCoords, yCoords)+")", "X", "Y", xVals, yVals, Plot.DEFAULT_FLAGS); plot.addPoints(xCoords, yCoords, Plot.CROSS); return plot; } } /* * Copyright (C) 2010-2014 Andreas Maier * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */