RoiSaver.java
package com.github.celldynamics.quimp.utils.test;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import org.scijava.vecmath.Point2d;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.celldynamics.quimp.QColor;
import com.github.celldynamics.quimp.geom.SegmentedShapeRoi;
import com.github.celldynamics.quimp.plugin.utils.QuimpDataConverter;
import ij.IJ;
import ij.ImagePlus;
import ij.gui.PolygonRoi;
import ij.gui.Roi;
import ij.gui.ShapeRoi;
import ij.process.FloatPolygon;
import ij.process.ImageConverter;
import ij.process.ImageProcessor;
/**
* Helper class to export shapes as *.tif images
*
* @author p.baniukiewicz
*
*/
public class RoiSaver {
/**
* The Constant LOGGER.
*/
static final Logger LOGGER = LoggerFactory.getLogger(RoiSaver.class.getName());
/**
* Dummy constructor.
*/
public RoiSaver() {
}
/**
* Save ROI as image
*
* <p>Get ListArray with vertices and create fileName.tif image with ROI For non-valid input list
* it creates red image of size 100 x 100
*
* @param fileName file to save image with path
* @param vert list of vertices
*/
public static void saveRoi(String fileName, List<Point2d> vert) {
try {
double[] bb;
float[] x = new float[vert.size()];
float[] y = new float[vert.size()];
int l = 0;
// copy to arrays
for (Point2d el : vert) {
x[l] = (float) el.getX();
y[l] = (float) el.getY();
l++;
}
bb = getBoundingBox(vert); // get size of output image
PolygonRoi pp = new PolygonRoi(x, y, Roi.POLYGON); // create polygon object
LOGGER.debug("Creating image of size [" + (int) Math.round(bb[0]) + ","
+ (int) Math.round(bb[1]) + "]");
ImagePlus outputImage = IJ.createImage("", (int) Math.round(bb[0] + 0.2 * bb[0]),
(int) Math.round(bb[1] + 0.2 * bb[1]), 1, 8); // output // margins
ImageProcessor ip = outputImage.getProcessor(); // get processor required later
ip.setColor(Color.WHITE); // set pen
pp.setLocation(0.1 * bb[0], 0.1 * bb[1]); // move slightly ROI to center
pp.drawPixels(ip); // draw roi
IJ.saveAsTiff(outputImage, fileName); // save image
LOGGER.debug("Saved as: " + fileName);
} catch (Exception e) {
ImagePlus outputImage = IJ.createImage("", 100, 100, 1, 24);
ImageProcessor ip = outputImage.getProcessor();
ip.setColor(Color.RED);
ip.fill();
IJ.saveAsTiff(outputImage, fileName); // save image
LOGGER.error(e.getMessage());
}
}
/**
* Save ROI as image.
*
* @param fileName fileName
* @param roi roi
* @see com.github.celldynamics.quimp.utils.test.RoiSaver#saveRois(ImagePlus, String, ArrayList)
*/
public static void saveRoi(String fileName, Roi roi) {
if (roi == null) {
saveRoi(fileName, (List<Point2d>) null);
return;
}
FloatPolygon fp;
fp = roi.getFloatPolygon(); // save common part
saveRoi(fileName, new QuimpDataConverter(fp.xpoints, fp.ypoints).getList());
}
/**
* Save ROIs as image
*
* <p>Get ListArray with vertices and create fileName.tif image with ROI For non-valid input list
* it creates red image of size 100 x 100. Allows to add up to three ROIS in different colors.
*
* @param fileName file to save image with path
* @param xres resolution of output image, must include ROI
* @param yres resolution of output image, must include ROI
* @param vert1 list 1
* @param c1 color of list 1
* @param vert2 list 2
* @param c2 color of list 2
* @param vert3 list 3
* @param c3 color of list 3
*/
public static void saveRois(String fileName, int xres, int yres, List<Point2d> vert1, Color c1,
List<Point2d> vert2, Color c2, List<Point2d> vert3, Color c3) {
ImagePlus outputImage = IJ.createImage("", xres, yres, 1, 24);
ImageProcessor ip = outputImage.getProcessor(); // get processor required later
if (vert1 != null && !vert1.isEmpty()) {
ip = plotOnRoi(ip, vert1, c1);
}
if (vert2 != null && !vert2.isEmpty()) {
ip = plotOnRoi(ip, vert2, c2);
}
if (vert3 != null && !vert3.isEmpty()) {
ip = plotOnRoi(ip, vert3, c3);
}
IJ.saveAsTiff(outputImage, fileName); // save image
}
/**
* Create stack from List of Rois.
*
* @param image Image where rois will be plotted. Number of slices must be equal to rois.size();
* @param fileName File to save
* @param ret List of Lists of Rois. First level of rois is plotted on slices, second contains
* rois to plot. Rois along second level are plotted with the same color across slices
* e.g. First roi in second level in red, second roi in second level ble etc
*/
public static void saveRois(ImagePlus image, String fileName,
ArrayList<ArrayList<SegmentedShapeRoi>> ret) {
ImagePlus cp = image.duplicate();
new ImageConverter(cp).convertToRGB();
for (ArrayList<? extends ShapeRoi> al : ret) {
QColor qcolor = QColor.lightColor();
Color color = new Color(qcolor.getColorInt());
for (int i = 0; i < al.size(); i++) {
ImageProcessor currentP = cp.getImageStack().getProcessor(i + 1);
currentP.setColor(color);
currentP.setLineWidth(2);
al.get(i).drawPixels(currentP); // TODO catch OutOfBounds exception to skip missing slices
}
}
IJ.saveAsTiff(cp, fileName); // save image
}
/**
* Plot ROI on image.
*
* <p>Get ListArray with vertices and create image image with ROI For non-valid input list
* it creates red image of size 100 x 100.
*
* @param ip image to plot in.
* @param vert list of points to plot
* @param c color
* @return image with plotted point
*/
public static ImageProcessor plotOnRoi(ImageProcessor ip, List<Point2d> vert, Color c) {
try {
float[] x;
float[] y;
x = new float[vert.size()];
y = new float[vert.size()];
int l = 0;
// copy to arrays
for (Point2d el : vert) {
x[l] = (float) el.getX();
y[l] = (float) el.getY();
l++;
}
PolygonRoi pp = new PolygonRoi(x, y, Roi.FREELINE); // create polygon object
ip.setColor(c); // set pen
pp.drawPixels(ip); // draw roi
} catch (Exception e) {
ImagePlus outputImage = IJ.createImage("", 100, 100, 1, 24);
ip = outputImage.getProcessor();
ip.setColor(Color.RED);
ip.fill();
LOGGER.error(e.getMessage());
}
return ip;
}
/**
* Calculates width and height of bounding box for shape defined as List of Vector2d
* elements.
*
* @param vert List of vertexes of shape
* @return two elements array where [width height]
*/
private static double[] getBoundingBox(List<Point2d> vert) {
double minx = vert.get(0).getX();
double maxx = minx;
double miny = vert.get(0).getY();
double maxy = miny;
double[] out = new double[2];
for (Point2d el : vert) {
if (el.getX() > maxx) {
maxx = el.getX();
}
if (el.getX() < minx) {
minx = el.getX();
}
if (el.getY() > maxy) {
maxy = el.getY();
}
if (el.getY() < miny) {
miny = el.getY();
}
}
out[0] = Math.abs(maxx - minx);
out[1] = Math.abs(maxy - miny);
return out;
}
}