/* * #%L * Bio-Formats Plugins for ImageJ: a collection of ImageJ plugins including the * Bio-Formats Importer, Bio-Formats Exporter, Bio-Formats Macro Extensions, * Data Browser and Stack Slicer. * %% * Copyright (C) 2006 - 2015 Open Microscopy Environment: * - Board of Regents of the University of Wisconsin-Madison * - Glencoe Software, Inc. * - University of Dundee * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-2.0.html>. * #L% */ package loci.plugins.util; import ij.IJ; import ij.ImagePlus; import ij.Prefs; import ij.gui.EllipseRoi; import ij.gui.Line; import ij.gui.OvalRoi; import ij.gui.Overlay; import ij.gui.PointRoi; import ij.gui.PolygonRoi; import ij.gui.Roi; import ij.gui.ShapeRoi; import ij.gui.TextRoi; import ij.plugin.frame.RoiManager; import java.awt.Color; import java.awt.Font; import java.awt.Rectangle; import java.util.ArrayList; import java.util.List; import loci.formats.MetadataTools; import loci.formats.meta.IMetadata; import loci.formats.meta.MetadataStore; import loci.formats.ome.OMEXMLMetadata; import ome.units.quantity.Length; import ome.units.UNITS; import ome.xml.model.Ellipse; import ome.xml.model.OME; import ome.xml.model.Point; import ome.xml.model.Polygon; import ome.xml.model.Polyline; import ome.xml.model.Shape; import ome.xml.model.Union; import ome.xml.model.primitives.NonNegativeInteger; // TODO: Stored ROIs are not correctly linked to Image. /** * Utility class for managing regions of interest within ImageJ. * Capable of constructing ROIs within ImageJ's ROI manager matching * those specified in an OME metadata store, and vice versa. * * @author Melissa Linkert melissa at glencoesoftware.com */ public class ROIHandler { // -- ROIHandler API methods -- /** * Look for ROIs in the given OMEXMLMetadata; if any are present, apply * them to the given images and display them in the ROI manager. */ public static void openROIs(IMetadata retrieve, ImagePlus[] images) { openROIs(retrieve,images, false); } /** * Opens the rois and converts them into ImageJ Rois. * * @param retrieve The OMEXML store. * @param images The imageJ object. * @param isOMERO <code>true</code> if data stored in OMERO, * <code>false</code> otherwise. */ public static void openROIs(IMetadata retrieve, ImagePlus[] images, boolean isOMERO) { if (!(retrieve instanceof OMEXMLMetadata)) return; int nextRoi = 0; RoiManager manager = RoiManager.getInstance(); OME root = (OME) retrieve.getRoot(); Roi roi; Float sw; Color sc; Color fc; int imageCount = images.length; for (int imageNum=0; imageNum<imageCount; imageNum++) { int roiCount = root.sizeOfROIList(); if (roiCount > 0 && manager == null) { manager = new RoiManager(); } for (int roiNum=0; roiNum<roiCount; roiNum++) { Union shapeSet = root.getROI(roiNum).getUnion(); int shapeCount = shapeSet.sizeOfShapeList(); for (int shape=0; shape<shapeCount; shape++) { Shape shapeObject = shapeSet.getShape(shape); roi = null; sw = null; sc = null; fc = null; int c= 0; int z= 0; int t= 0; if (shapeObject instanceof Ellipse) { Ellipse ellipse = (Ellipse) shapeObject; int cx = ellipse.getX().intValue(); int cy = ellipse.getY().intValue(); int rx = ellipse.getRadiusX().intValue(); int ry = ellipse.getRadiusY().intValue(); roi = new OvalRoi(cx - rx, cy - ry, rx * 2, ry * 2); if (ellipse.getStrokeColor() != null) { ome.xml.model.primitives.Color StrokeColor = ellipse.getStrokeColor(); sc = new Color(StrokeColor.getRed(), StrokeColor.getGreen(), StrokeColor.getBlue(),StrokeColor.getAlpha()); if (isOMERO) { sc = new Color(StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha(), StrokeColor.getRed()); } } if (ellipse.getFillColor() != null) { ome.xml.model.primitives.Color FillColor = ellipse.getFillColor(); fc = new Color(FillColor.getRed(), FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha()); if (isOMERO) { fc = new Color(FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha(), FillColor.getRed()); } } if (ellipse.getStrokeWidth() != null) { sw = ellipse.getStrokeWidth().value().floatValue(); } } else if (shapeObject instanceof ome.xml.model.Line) { ome.xml.model.Line line = (ome.xml.model.Line) shapeObject; int x1 = line.getX1().intValue(); int x2 = line.getX2().intValue(); int y1 = line.getY1().intValue(); int y2 = line.getY2().intValue(); roi = new Line(x1, y1, x2, y2); if (line.getStrokeColor() != null) { ome.xml.model.primitives.Color StrokeColor = line.getStrokeColor(); sc = new Color(StrokeColor.getRed(), StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha()); if (isOMERO) { sc = new Color(StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha(), StrokeColor.getRed()); } } if (line.getFillColor() != null) { ome.xml.model.primitives.Color FillColor = line.getFillColor(); fc = new Color(FillColor.getRed(), FillColor.getGreen(), FillColor.getBlue(),FillColor.getAlpha()); if (isOMERO) { fc = new Color(FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha(), FillColor.getRed()); } } if (line.getStrokeWidth() != null) { sw = line.getStrokeWidth().value().floatValue(); } } else if (shapeObject instanceof Point) { Point point = (Point) shapeObject; int x = point.getX().intValue(); int y = point.getY().intValue(); roi = new PointRoi(x, y); if (point.getStrokeColor() != null){ ome.xml.model.primitives.Color StrokeColor = point.getStrokeColor(); sc = new Color(StrokeColor.getRed(), StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha()); if (isOMERO) { sc = new Color(StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha(), StrokeColor.getRed()); } } if (point.getFillColor() != null){ ome.xml.model.primitives.Color FillColor = point.getFillColor(); fc = new Color(FillColor.getRed(), FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha()); if (isOMERO) { fc = new Color(FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha(), FillColor.getRed()); } } if (point.getStrokeWidth() != null){ sw = point.getStrokeWidth().value().floatValue(); } } else if (shapeObject instanceof Polyline) { Polyline polyline = (Polyline) shapeObject; String points = polyline.getPoints(); int[][] coordinates = parsePoints(points); roi = new PolygonRoi(coordinates[0], coordinates[1], coordinates[0].length, Roi.POLYLINE); if (polyline.getStrokeColor() != null){ ome.xml.model.primitives.Color StrokeColor = polyline.getStrokeColor(); sc = new Color(StrokeColor.getRed(), StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha()); if (isOMERO) { sc = new Color(StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha(), StrokeColor.getRed()); } } if (polyline.getFillColor() != null){ ome.xml.model.primitives.Color FillColor = polyline.getFillColor(); fc = new Color(FillColor.getRed(), FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha()); if (isOMERO) { fc = new Color(FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha(), FillColor.getRed()); } } if (polyline.getStrokeWidth() != null){ sw = polyline.getStrokeWidth().value().floatValue(); } } else if (shapeObject instanceof Polygon) { Polygon polygon = (Polygon) shapeObject; String points = polygon.getPoints(); int[][] coordinates = parsePoints(points); roi = new PolygonRoi(coordinates[0], coordinates[1], coordinates[0].length, Roi.POLYGON); if (polygon.getStrokeColor() != null){ ome.xml.model.primitives.Color StrokeColor = polygon.getStrokeColor(); sc = new Color(StrokeColor.getRed(), StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha()); if (isOMERO) { sc = new Color(StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha(), StrokeColor.getRed()); } } if (polygon.getFillColor() != null){ ome.xml.model.primitives.Color FillColor = polygon.getFillColor(); fc = new Color(FillColor.getRed(), FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha()); if (isOMERO) { fc = new Color(FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha(), FillColor.getRed()); } } if (polygon.getStrokeWidth() != null){ sw = polygon.getStrokeWidth().value().floatValue(); } } else if (shapeObject instanceof ome.xml.model.Label){ //add support for TextROI's ome.xml.model.Label label = (ome.xml.model.Label) shapeObject; double x = label.getX().doubleValue(); double y = label.getY().doubleValue(); String labelText = label.getText(); int size = label.getFontSize().value().intValue(); Font font = new Font(labelText, Font.PLAIN, size); roi = new TextRoi((int) x,(int) y, labelText,font); if (label.getStrokeColor() != null) { ome.xml.model.primitives.Color StrokeColor = label.getStrokeColor(); sc = new Color(StrokeColor.getRed(), StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha()); if (isOMERO) { sc = new Color(StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha(), StrokeColor.getRed()); } } if (label.getFillColor() != null) { ome.xml.model.primitives.Color FillColor = label.getFillColor(); fc = new Color(FillColor.getRed(), FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha()); if (isOMERO) { fc = new Color(FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha(), FillColor.getRed()); } } if (label.getStrokeWidth() != null) { sw = label.getStrokeWidth().value().floatValue(); } } else if (shapeObject instanceof ome.xml.model.Rectangle) { ome.xml.model.Rectangle rectangle = (ome.xml.model.Rectangle) shapeObject; int x = rectangle.getX().intValue(); int y = rectangle.getY().intValue(); int w = rectangle.getWidth().intValue(); int h = rectangle.getHeight().intValue(); roi = new Roi(x, y, w, h); if (rectangle.getStrokeColor() != null){ ome.xml.model.primitives.Color StrokeColor = rectangle.getStrokeColor(); sc = new Color(StrokeColor.getRed(), StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha()); if (isOMERO) { sc = new Color(StrokeColor.getGreen(), StrokeColor.getBlue(), StrokeColor.getAlpha(), StrokeColor.getRed()); } } if (rectangle.getFillColor() != null){ ome.xml.model.primitives.Color FillColor = rectangle.getFillColor(); fc = new Color(FillColor.getRed(), FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha()); if (isOMERO) { fc = new Color(FillColor.getGreen(), FillColor.getBlue(), FillColor.getAlpha(), FillColor.getRed()); } } if (rectangle.getStrokeWidth() != null){ sw = rectangle.getStrokeWidth().value().floatValue(); } } if (roi != null) { String roiLabel = shapeObject.getText(); if (roiLabel == null) { roiLabel = shapeObject.getID(); } roi.setName(roiLabel); if (Prefs.showAllSliceOnly) { if (shapeObject.getTheC() != null) { c = shapeObject.getTheC().getValue(); } if (shapeObject.getTheZ() != null) { z = shapeObject.getTheZ().getValue(); } if (shapeObject.getTheT() != null) { t = shapeObject.getTheT().getValue(); } // ImageJ expects 1-based indexing, opposed to // 0-based indexing in OME // Roi positions differ between hyperstacks and normal stacks ImagePlus imp = images[imageNum]; if (imp.getNChannels() > 1) { c++; } if (imp.getNSlices() > 1) { z++; } if (imp.getNFrames() > 1) { t++; } if (c == 0) c = 1; if (t == 0) t = 1; if (z == 0) z = 1; if (imp.getNChannels() == 1 && imp.getNSlices() == 1) { roi.setPosition(t); } else if (imp.getNChannels() == 1 && imp.getNFrames() == 1) { roi.setPosition(z); } else if (imp.getNSlices() == 1 && imp.getNFrames() == 1) { roi.setPosition(c); } else if (imp.isHyperStack()) { roi.setPosition(c, z, t); } } if (sw == null) { roi.setStrokeWidth((float) 1); } if (sw != null) { if (sw == 0) { sw= (float) 1; } roi.setStrokeWidth(sw); } if (sc != null) { roi.setStrokeColor(sc); } manager.add(images[imageNum], roi, nextRoi++); } } } if (roiCount > 0 && manager != null) { manager.setAlwaysOnTop(true); manager.runCommand("show all with labels"); } } } /** * Returns the rois if any stored in the ROI manager. * @return See above. */ public static Roi[] readFromRoiManager() { RoiManager manager = RoiManager.getInstance(); if (manager == null) return null; return manager.getRoisAsArray(); } /** * Returns rois if any from the overlay. * @return See above */ public static Roi[] readFromOverlays() { ImagePlus image = IJ.getImage(); Overlay overlay = image.getOverlay(); if (overlay == null) return null; return overlay.toArray(); } /** * Save ROIs in the ROI manager to the given MetadataStore. * * @param store Where to store the rois. */ public static void saveROIs(MetadataStore store) { Roi[] rois = readFromOverlays(); if (rois == null || rois.length == 0) { rois = readFromRoiManager(); } if (rois == null || rois.length == 0) return; List<String> discardList = new ArrayList<String>(); String roiID = null; OME root = (OME) store.getRoot(); int roicount = root.sizeOfROIList(); int cntr = roicount; for (int i=0; i<rois.length; i++) { String polylineID = MetadataTools.createLSID("Shape", cntr, 0); roiID = MetadataTools.createLSID("ROI", cntr, 0); Roi ijRoi = rois[i]; int c = ijRoi.getCPosition()-1; int z = ijRoi.getZPosition()-1; int t = ijRoi.getTPosition()-1; if (ijRoi.isDrawingTool()){//Checks if the given roi is a Text box/Arrow/Rounded Rectangle if (ijRoi.getTypeAsString().matches("Text")) { if (ijRoi instanceof TextRoi){ store.setLabelID(polylineID, cntr, 0); storeText((TextRoi) ijRoi, store, cntr, 0, c, z, t); } } else if (ijRoi.getTypeAsString().matches("Rectangle")) { if (ijRoi instanceof Roi) { store.setRectangleID(polylineID, cntr, 0); storeRectangle(ijRoi, store, cntr, 0, c, z, t); } } else { roiID = null; String type = ijRoi.getName(); IJ.log("ROI ID : " + type + " ROI type : " + "Arrow (Drawing Tool) is not supported"); } } else if (ijRoi instanceof OvalRoi) {//Check if its an oval or ellipse ROI store.setEllipseID(polylineID, cntr, 0); storeOval((OvalRoi) ijRoi, store, cntr, 0, c, z, t); } else if (ijRoi instanceof Line) { //Check if its a Line or Arrow ROI boolean checkpoint = ijRoi.isDrawingTool(); if (!checkpoint) { store.setLineID(polylineID, cntr, 0); storeLine((Line) ijRoi, store, cntr, 0, c, z, t); } else { roiID = null; String type = ijRoi.getName(); IJ.log("ROI ID : " + type + " ROI type : " + "Arrow (Drawing Tool) is not supported"); } } else if (ijRoi instanceof PolygonRoi || ijRoi instanceof EllipseRoi) { if (ijRoi.getTypeAsString().matches("Polyline") || ijRoi.getTypeAsString().matches("Freeline") || ijRoi.getTypeAsString().matches("Angle")) { store.setPolylineID(polylineID, cntr, 0); storePolygon((PolygonRoi) ijRoi, store, cntr, 0, c, z, t); } else if (ijRoi.getTypeAsString().matches("Point")) { store.setPointID(polylineID, cntr, 0); storePoint((PointRoi) ijRoi, store, cntr, 0, c, z, t); } else if (ijRoi.getTypeAsString().matches("Polygon") || ijRoi.getTypeAsString().matches("Freehand") || ijRoi.getTypeAsString().matches("Traced") || ijRoi.getTypeAsString().matches("Oval")) { store.setPolygonID(polylineID, cntr, 0); storePolygon((PolygonRoi) ijRoi, store, cntr, 0, c, z, t); } } else if (ijRoi instanceof ShapeRoi) { Roi[] subRois = ((ShapeRoi) ijRoi).getRois(); for (int q = 0; q < subRois.length; q++) { polylineID = MetadataTools.createLSID("Shape", cntr, q); roiID = MetadataTools.createLSID("ROI", cntr, q); Roi ijShape = subRois[q]; if (ijShape.isDrawingTool()) {//Checks if the given roi is a Text box/Arrow/Rounded Rectangle if (ijShape.getTypeAsString().matches("Text")) { if (ijShape instanceof TextRoi) { store.setLabelID(polylineID, cntr, q); storeText((TextRoi) ijShape, store, cntr, q, c, z, t); } } else if (ijShape.getTypeAsString().matches("Rectangle")) { if (ijShape instanceof Roi) { store.setRectangleID(polylineID, cntr, q); storeRectangle(ijShape, store, cntr, q, c, z, t); } } else { roiID = null; String type = ijShape.getName(); IJ.log("ROI ID : " + type + " ROI type : " + "Arrow (Drawing Tool) is not supported"); } } else if (ijShape instanceof Line) { boolean checkpoint = ijShape.isDrawingTool(); if (!checkpoint) { store.setLineID(polylineID, cntr, 0); storeLine((Line) ijShape, store, cntr, 0, c, z, t); } else { roiID = null; String type1 = ijShape.getName(); discardList.add(type1); IJ.log("ROI ID : " + type1 + " ROI type : " + "Arrow (DrawingTool) is not supported"); } } else if (ijShape instanceof OvalRoi) { store.setEllipseID(polylineID, cntr, q); storeOval((OvalRoi) ijShape, store, cntr, q, c, z, t); } else if (ijShape instanceof PolygonRoi || ijShape instanceof EllipseRoi) { if (ijShape.getTypeAsString().matches("Polyline") || ijShape.getTypeAsString().matches("Freeline") || ijShape.getTypeAsString().matches("Angle")) { store.setPolylineID(polylineID, cntr, q); storePolygon((PolygonRoi) ijShape, store, cntr, q, c, z, t); } else if (ijShape.getTypeAsString().matches("Point")) { store.setPointID(polylineID, cntr, q); storePoint((PointRoi) ijShape, store, cntr, q, c, z, t); } else if (ijShape.getTypeAsString().matches("Polygon") || ijShape.getTypeAsString().matches("Freehand") || ijShape.getTypeAsString().matches("Traced") || ijShape.getTypeAsString().matches("Oval")) { store.setPolygonID(polylineID, cntr, q); storePolygon((PolygonRoi) ijShape, store, cntr, q, c, z, t); } } else if (ijShape.getTypeAsString().matches("Rectangle")) { store.setRectangleID(polylineID, cntr, q); storeRectangle(ijShape, store, cntr, q, c, z, t); } else { roiID = null; String type = ijShape.getName(); IJ.log("ROI ID : " + type + " ROI type : " + ijShape.getTypeAsString() + "is not supported"); } } } else if (ijRoi.getTypeAsString().matches("Rectangle")) {//Check if its a Rectangle or Rounded Rectangle ROI store.setRectangleID(polylineID, cntr, 0); storeRectangle(ijRoi, store, cntr, 0, c, z, t); } else { roiID = null; String type = ijRoi.getName(); IJ.log("ROI ID : " + type + " ROI type : " + rois[cntr].getTypeAsString() + "is not supported"); } //Save Roi's using ROIHandler if (roiID != null) { store.setROIID(roiID, cntr); store.setImageROIRef(roiID, 0, cntr); cntr++; } } } // -- Helper methods -- /** * Wraps the specified integer into a Non negative integer. * * @param r The value to wrap. * @return See above. */ private static NonNegativeInteger unwrap(int r) { return new NonNegativeInteger(r); } /** * Stores the text ROI into the metadata stored. * * @param roi The roi to convert. * @param store The store to handle. * @param roiNum The roi number * @param shape The index of the shape. * @param c The selected channel. * @param z The selected slice. * @param t The selected timepoint. */ private static void storeText(TextRoi roi, MetadataStore store, int roiNum, int shape, int c, int z, int t) { store.setLabelX(roi.getPolygon().getBounds().getX(), roiNum, shape); store.setLabelY(roi.getPolygon().getBounds().getY(), roiNum, shape); store.setLabelText(roi.getText().trim(), roiNum, shape); store.setLabelFontSize(new Length(roi.getCurrentFont().getSize(), UNITS.PIXEL), roiNum, shape); if (c >= 0) { store.setLabelTheC(unwrap(c), roiNum, shape); } if (z >= 0) { store.setLabelTheZ(unwrap(z), roiNum, shape); } if (t >= 0) { store.setLabelTheT(unwrap(t), roiNum, shape); } if (roi.getStrokeWidth() > 0) { store.setLabelStrokeWidth(new Length((roi.getStrokeWidth()), UNITS.PIXEL), roiNum, shape); } if (roi.getStrokeColor() != null) { store.setLabelStrokeColor(toOMExmlColor(roi.getStrokeColor()) , roiNum, shape); } if (roi.getFillColor() != null) { store.setLabelFillColor(toOMExmlColor(roi.getFillColor()) , roiNum, shape); } } /** * Stores the Point ROI into the specified metadata store. * * @param roi The roi to convert. * @param store The store to handle. * @param roiNum The roi number * @param shape The index of the shape. * @param c The selected channel. * @param z The selected slice. * @param t The selected timepoint. */ private static void storePoint(PointRoi roi, MetadataStore store, int roiNum, int shape, int c, int z, int t) { int[] xCoordinates = roi.getPolygon().xpoints; int[] yCoordinates = roi.getPolygon().ypoints; for (int cntr = 0 ; cntr < xCoordinates.length; cntr++) { String polylineID = MetadataTools.createLSID("Shape", roiNum, shape+cntr); store.setPointID(polylineID, roiNum, shape+cntr); store.setPointX((double) xCoordinates[cntr], roiNum, shape+cntr); store.setPointY((double) yCoordinates[cntr], roiNum, shape+cntr); store.setPointText(roi.getName(), roiNum, shape+cntr); if (c >= 0) { store.setPointTheC(unwrap(c), roiNum, shape); } if (z >= 0) { store.setPointTheZ(unwrap(z), roiNum, shape); } if (t >= 0) { store.setPointTheT(unwrap(t), roiNum, shape); } if (roi.getStrokeWidth() > 0) { store.setPointStrokeWidth( new Length((roi.getStrokeWidth()), UNITS.PIXEL), roiNum, shape+cntr); } if (roi.getStrokeColor() != null) { store.setPointStrokeColor(toOMExmlColor(roi.getStrokeColor()), roiNum, shape+cntr); } if (roi.getFillColor() != null){ store.setPointFillColor(toOMExmlColor(roi.getFillColor()), roiNum, shape+cntr); } } } /** * Stores the Line ROI into the specified metadata store. * * @param roi The roi to convert. * @param store The store to handle. * @param roiNum The roi number * @param shape The index of the shape. * @param c The selected channel. * @param z The selected slice. * @param t The selected timepoint. */ private static void storeLine(Line roi, MetadataStore store, int roiNum, int shape, int c, int z, int t) { store.setLineX1(new Double(roi.x1), roiNum, shape); store.setLineX2(new Double(roi.x2), roiNum, shape); store.setLineY1(new Double(roi.y1), roiNum, shape); store.setLineY2(new Double(roi.y2), roiNum, shape); if (c >= 0) { store.setLineTheC(unwrap(c), roiNum, shape); } if (z >= 0) { store.setLineTheZ(unwrap(z), roiNum, shape); } if (t >= 0) { store.setLineTheT(unwrap(t), roiNum, shape); } store.setLineText(roi.getName(), roiNum, shape); if (roi.getStrokeWidth() > 0) { store.setLineStrokeWidth(new Length((roi.getStrokeWidth()), UNITS.PIXEL), roiNum, shape); } if (roi.getStrokeColor() != null) { store.setLineStrokeColor(toOMExmlColor(roi.getStrokeColor()), roiNum, shape); } if (roi.getFillColor() != null) { store.setLineFillColor(toOMExmlColor(roi.getFillColor()), roiNum, shape); } } /** * Stores the Rectangle ROI into the specified metadata store. * * @param roi The roi to convert. * @param store The store to handle. * @param roiNum The roi number * @param shape The index of the shape. * @param c The selected channel. * @param z The selected slice. * @param t The selected timepoint. */ private static void storeRectangle(Roi roi, MetadataStore store, int roiNum, int shape, int c, int z, int t) { Rectangle bounds = roi.getBounds(); store.setRectangleX(new Double(bounds.x), roiNum, shape); store.setRectangleY(new Double(bounds.y), roiNum, shape); store.setRectangleWidth(new Double(bounds.width), roiNum, shape); store.setRectangleHeight(new Double(bounds.height), roiNum, shape); if (c >= 0) { store.setRectangleTheC(unwrap(c), roiNum, shape); } if (z >= 0) { store.setRectangleTheZ(unwrap(z), roiNum, shape); } if (t >= 0) { store.setRectangleTheT(unwrap(t), roiNum, shape); } store.setRectangleText(roi.getName(), roiNum, shape); if (roi.getStrokeWidth() > 0) { store.setRectangleStrokeWidth(new Length((roi.getStrokeWidth()), UNITS.PIXEL), roiNum, shape); } if (roi.getStrokeColor() != null) { store.setRectangleStrokeColor(toOMExmlColor(roi.getStrokeColor()), roiNum, shape); } if (roi.getFillColor() != null){ store.setRectangleFillColor(toOMExmlColor(roi.getFillColor()), roiNum, shape); } } /** * Stores the Polygon ROI into the specified metadata store. * * @param roi The roi to convert. * @param store The store to handle. * @param roiNum The roi number * @param shape The index of the shape. * @param c The selected channel. * @param z The selected slice. * @param t The selected timepoint. */ private static void storePolygon(PolygonRoi roi, MetadataStore store, int roiNum, int shape, int c, int z, int t) { int[] xCoordinates = roi.getPolygon().xpoints; int[] yCoordinates = roi.getPolygon().ypoints; String st1 = roi.getTypeAsString(); String points = "1"; for (int i = 0; i < xCoordinates.length; i++){ if (i == 0) { points = (xCoordinates[i] + "," + yCoordinates[i]); } else { points= (points + " " + xCoordinates[i] + "," + yCoordinates[i]); } } if (st1.matches("Polyline") || st1.matches("Freeline") || st1.matches("Angle")) { store.setPolylinePoints(points.toString(), roiNum, shape); store.setPolylineText(roi.getName(), roiNum, shape); if (c >= 0) { store.setPolylineTheC(unwrap(c), roiNum, shape); } if (z >= 0) { store.setPolylineTheZ(unwrap(z), roiNum, shape); } if (t >= 0) { store.setPolylineTheT(unwrap(t), roiNum, shape); } if (roi.getStrokeWidth() > 0) { store.setPolylineStrokeWidth(new Length((roi.getStrokeWidth()), UNITS.PIXEL), roiNum, shape); } if (roi.getStrokeColor() != null) { store.setPolylineStrokeColor(toOMExmlColor(roi.getStrokeColor()), roiNum, shape); } if (roi.getFillColor() != null) { store.setPolylineFillColor(toOMExmlColor(roi.getFillColor()) , roiNum, shape); } } else if (st1.matches("Polygon") || st1.matches("Freehand") || st1.matches("Traced")){ store.setPolygonPoints(points.toString(), roiNum, shape); store.setPolygonText(roi.getName(), roiNum, shape); if (c >= 0) { store.setPolygonTheC(unwrap(c), roiNum, shape); } if (z >= 0) { store.setPolygonTheZ(unwrap(z), roiNum, shape); } if (t >= 0) { store.setPolygonTheT(unwrap(t), roiNum, shape); } if (roi.getStrokeWidth() > 0) { store.setPolygonStrokeWidth(new Length((roi.getStrokeWidth()), UNITS.PIXEL), roiNum, shape); } if (roi.getStrokeColor() != null) { store.setPolygonStrokeColor(toOMExmlColor(roi.getStrokeColor()) , roiNum, shape); } if (roi.getFillColor() != null){ store.setPolygonFillColor(toOMExmlColor(roi.getFillColor()), roiNum, shape); } } } /** * Stores the Oval ROI into the specified metadata store. * * @param roi The roi to convert. * @param store The store to handle. * @param roiNum The roi number * @param shape The index of the shape. * @param c The selected channel. * @param z The selected slice. * @param t The selected timepoint. */ private static void storeOval(OvalRoi roi, MetadataStore store, int roiNum, int shape, int c, int z, int t) { Rectangle vnRectBounds = roi.getPolygon().getBounds(); int x = vnRectBounds.x; int y = vnRectBounds.y; double rx = vnRectBounds.getWidth(); double ry = vnRectBounds.getHeight(); store.setEllipseX(((double) x + rx/2), roiNum, shape); store.setEllipseY(((double) y + ry/2), roiNum, shape); store.setEllipseRadiusX((double) rx/2, roiNum, shape); store.setEllipseRadiusY((double) ry/2, roiNum, shape); store.setEllipseText(roi.getName(), roiNum, shape); if (c >= 0) { store.setEllipseTheC(unwrap(c), roiNum, shape); } if (z >= 0) { store.setEllipseTheZ(unwrap(z), roiNum, shape); } if (t >= 0) { store.setEllipseTheT(unwrap(t), roiNum, shape); } if (roi.getStrokeWidth() > 0) { store.setEllipseStrokeWidth(new Length((roi.getStrokeWidth()), UNITS.PIXEL), roiNum, shape); } if (roi.getStrokeColor() != null) { store.setEllipseStrokeColor(toOMExmlColor(roi.getStrokeColor()), roiNum, shape); } if (roi.getFillColor() != null){ store.setEllipseFillColor(toOMExmlColor(roi.getFillColor()) , roiNum, shape); } } /** * Parse (x, y) coordinates from a String returned by * MetadataRetrieve.getPolygonpoints(...) or * MetadataRetrieve.getPolylinepoints(...) */ private static int[][] parsePoints(String points) { // assuming points are stored like this: // x0,y0 x1,y1 x2,y2 ... String[] pointList = points.split(" "); int[][] coordinates = new int[2][pointList.length]; for (int q=0; q<pointList.length; q++) { pointList[q] = pointList[q].trim(); int delim = pointList[q].indexOf(","); coordinates[0][q] = (int) Double.parseDouble(pointList[q].substring(0, delim)); coordinates[1][q] = (int) Double.parseDouble(pointList[q].substring(delim + 1)); } return coordinates; } /** * Converts the Java Color into an OME-XML Color. * * @param color The color to convert * @return See above */ private static ome.xml.model.primitives.Color toOMExmlColor(Color color) { return new ome.xml.model.primitives.Color(color.getRed(), color.getGreen(), color.getBlue(),color.getAlpha()); } }