use of qupath.lib.roi.PointsROI in project qupath by qupath.
the class PointIO method writePoints.
/**
* Write a list of point annotations to a stream.
* @param stream
* @param pathObjects
* @throws IOException
*/
public static void writePoints(OutputStream stream, Collection<? extends PathObject> pathObjects) throws IOException {
// Check that all PathObjects contain only point annotations
int unfilteredSize = pathObjects.size();
pathObjects = pathObjects.stream().filter(p -> p.getROI() instanceof PointsROI).collect(Collectors.toList());
int filteredSize = pathObjects.size();
if (unfilteredSize != filteredSize)
logger.warn(unfilteredSize - filteredSize + " of the " + filteredSize + " elements in list is/are not point annotations. These will be skipped.");
try (Writer writer = new BufferedWriter(new OutputStreamWriter(stream, StandardCharsets.UTF_8))) {
List<String> cols = new ArrayList<>();
cols.addAll(Arrays.asList("x", "y"));
String sep = "\t";
ImagePlane defaultPlane = ImagePlane.getDefaultPlane();
boolean hasClass = pathObjects.stream().anyMatch(p -> p.getPathClass() != null);
boolean hasName = pathObjects.stream().anyMatch(p -> p.getName() != null);
boolean hasColor = pathObjects.stream().anyMatch(p -> p.getColorRGB() != null);
boolean hasC = pathObjects.stream().anyMatch(p -> p.getROI().getC() > defaultPlane.getC());
boolean hasZ = pathObjects.stream().anyMatch(p -> p.getROI().getZ() > defaultPlane.getZ());
boolean hasT = pathObjects.stream().anyMatch(p -> p.getROI().getT() > defaultPlane.getT());
if (hasC)
cols.add("c");
if (hasZ)
cols.add("z");
if (hasT)
cols.add("t");
if (hasClass)
cols.add("class");
if (hasName)
cols.add("name");
if (hasColor)
cols.add("color");
for (String col : cols) writer.write(col + sep);
writer.write(System.lineSeparator());
for (PathObject pathObject : pathObjects) {
if (!PathObjectTools.hasPointROI(pathObject))
continue;
PointsROI points = (PointsROI) pathObject.getROI();
for (Point2 point : points.getAllPoints()) {
String[] row = new String[cols.size()];
row[cols.indexOf("x")] = point.getX() + "";
row[cols.indexOf("y")] = sep + point.getY();
if (hasC)
row[cols.indexOf("c")] = sep + points.getC();
if (hasZ)
row[cols.indexOf("z")] = sep + points.getZ();
if (hasT)
row[cols.indexOf("t")] = sep + points.getT();
if (hasClass)
row[cols.indexOf("class")] = pathObject.getPathClass() != null ? sep + pathObject.getPathClass() : sep;
if (hasName)
row[cols.indexOf("name")] = pathObject.getName() != null ? sep + pathObject.getName() : sep;
if (hasColor)
row[cols.indexOf("color")] = pathObject.getColorRGB() != null ? sep + pathObject.getColorRGB() : sep;
for (String val : row) writer.write(val);
writer.write(System.lineSeparator());
}
}
}
}
use of qupath.lib.roi.PointsROI in project qupath by qupath.
the class IJTools method convertToIJRoi.
/**
* Convert a QuPath ROI to an ImageJ Roi.
* @param <T>
* @param pathROI
* @param xOrigin x-origin indicating relationship of ImagePlus to the original image, as stored in ImageJ Calibration object
* @param yOrigin y-origin indicating relationship of ImagePlus to the original image, as stored in ImageJ Calibration object
* @param downsampleFactor downsample factor at which the ImagePlus was extracted from the full-resolution image
* @return
*/
public static <T extends PathImage<ImagePlus>> Roi convertToIJRoi(ROI pathROI, double xOrigin, double yOrigin, double downsampleFactor) {
if (pathROI instanceof PolygonROI)
return ROIConverterIJ.convertToPolygonROI((PolygonROI) pathROI, xOrigin, yOrigin, downsampleFactor);
if (pathROI instanceof RectangleROI)
return ROIConverterIJ.getRectangleROI((RectangleROI) pathROI, xOrigin, yOrigin, downsampleFactor);
if (pathROI instanceof EllipseROI)
return ROIConverterIJ.convertToOvalROI((EllipseROI) pathROI, xOrigin, yOrigin, downsampleFactor);
if (pathROI instanceof LineROI)
return ROIConverterIJ.convertToLineROI((LineROI) pathROI, xOrigin, yOrigin, downsampleFactor);
if (pathROI instanceof PolylineROI)
return ROIConverterIJ.convertToPolygonROI((PolylineROI) pathROI, xOrigin, yOrigin, downsampleFactor);
if (pathROI instanceof PointsROI)
return ROIConverterIJ.convertToPointROI((PointsROI) pathROI, xOrigin, yOrigin, downsampleFactor);
// If we have any other kind of shape, create a general shape roi
if (pathROI != null && pathROI.isArea()) {
// TODO: Deal with non-AWT area ROIs!
Shape shape = RoiTools.getArea(pathROI);
// "scaleX", "shearY", "shearX", "scaleY", "translateX", "translateY"
shape = new AffineTransform(1.0 / downsampleFactor, 0, 0, 1.0 / downsampleFactor, xOrigin, yOrigin).createTransformedShape(shape);
return ROIConverterIJ.setIJRoiProperties(new ShapeRoi(shape), pathROI);
}
// TODO: Integrate ROI not supported exception...?
return null;
}
use of qupath.lib.roi.PointsROI in project qupath by qupath.
the class PointsTool method mouseReleased.
@Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
if (e.getButton() != MouseButton.PRIMARY || e.isConsumed()) {
return;
}
PointsROI points = getCurrentPoints();
if (points == null)
return;
var viewer = getViewer();
RoiEditor editor = viewer.getROIEditor();
editor.resetActiveHandle();
var currentObject = viewer.getSelectedObject();
viewer.getHierarchy().updateObject(currentObject, false);
// viewer.getHierarchy().fireHierarchyChangedEvent(this, vcurrentObject);
// // Find out the coordinates in the image domain & update the adjustment
// Point2D p = viewer.componentPointToImagePoint(e.getX(), e.getY(), null, false);
// points.finishAdjusting(p.getX(), p.getY(), e.isShiftDown());
// points.resetMeasurements();
}
use of qupath.lib.roi.PointsROI in project qupath by qupath.
the class PathClassificationLabellingHelper method getClassificationMap.
/**
* Get a map of training data, based on the child objects of some classified annotations.
*
* @param hierarchy the hierarchy containing all the objects and annotations.
* @param pointsOnly if true, only Point annotations will be used for training.
*
* @return
*/
public static Map<PathClass, List<PathObject>> getClassificationMap(final PathObjectHierarchy hierarchy, final boolean pointsOnly) {
Map<PathClass, List<PathObject>> classifications = new TreeMap<>();
// Get the annotations & filter out those that are useful
List<PathObject> annotations = new ArrayList<>(getAnnotations(hierarchy));
Iterator<PathObject> iter = annotations.iterator();
while (iter.hasNext()) {
PathObject pathObject = iter.next();
// We need a PathClass, and may need to only include points
if (pathObject.getPathClass() == null || pathObject.getPathClass() == PathClassFactory.getPathClass(StandardPathClasses.REGION) || (pointsOnly && !PathObjectTools.hasPointROI(pathObject)))
iter.remove();
else
classifications.put(pathObject.getPathClass(), new ArrayList<>());
}
// from the hierarchy
if (annotations.size() > 1) {
annotations.sort(new Comparator<PathObject>() {
@Override
public int compare(PathObject o1, PathObject o2) {
PathAnnotationObject p1 = (PathAnnotationObject) o1;
PathAnnotationObject p2 = (PathAnnotationObject) o2;
int comp = 0;
if (p1.hasROI()) {
if (p2.hasROI()) {
comp = Double.compare(p1.getROI().getCentroidY(), p2.getROI().getCentroidY());
if (comp == 0)
comp = Double.compare(p1.getROI().getCentroidX(), p2.getROI().getCentroidX());
if (comp == 0)
comp = p1.getROI().toString().compareTo(p2.getROI().toString());
}
}
if (comp == 0)
return Integer.compare(o1.hashCode(), o2.hashCode());
else
return comp;
}
});
}
// StringBuilder sb = new StringBuilder("DETECTIONS:\t");
for (PathObject pathObject : annotations) {
PathClass pathClass = pathObject.getPathClass();
List<PathObject> list = classifications.get(pathClass);
// sb.append(list.size() + ", ");
if (PathObjectTools.hasPointROI(pathObject)) {
for (Point2 p : ((PointsROI) pathObject.getROI()).getAllPoints()) {
// TODO: Pay attention to z & t position!
Collection<PathObject> pathObjectsTemp = PathObjectTools.getObjectsForLocation(hierarchy, p.getX(), p.getY(), 0, 0, -1);
pathObjectsTemp = PathObjectTools.getObjectsOfClass(pathObjectsTemp, PathDetectionObject.class);
// Clumsy way to avoid duplicates...
list.removeAll(pathObjectsTemp);
list.addAll(pathObjectsTemp);
}
} else
list.addAll(hierarchy.getObjectsForROI(PathDetectionObject.class, pathObject.getROI()));
}
for (Entry<PathClass, List<PathObject>> entry : classifications.entrySet()) {
logger.info(entry.getKey() + ": " + entry.getValue().size());
}
return classifications;
}
use of qupath.lib.roi.PointsROI in project qupath by qupath.
the class PathHierarchyPaintingHelper method paintPoints.
private static void paintPoints(ROI pathPoints, Graphics2D g2d, double radius, Color colorStroke, Stroke stroke, Color colorFill, double downsample) {
PointsROI pathPointsROI = pathPoints instanceof PointsROI ? (PointsROI) pathPoints : null;
if (pathPointsROI != null && PathPrefs.showPointHullsProperty().get()) {
ROI convexHull = pathPointsROI.getConvexHull();
if (convexHull != null) {
Color colorHull = colorFill != null ? colorFill : colorStroke;
colorHull = ColorToolsAwt.getColorWithOpacity(colorHull, 0.1);
if (colorHull != null)
paintShape(RoiTools.getShape(convexHull), g2d, null, null, colorHull);
// getConvexHull().draw(g, null, colorHull);
}
}
RectangularShape ellipse;
// double radius = pathPointsROI == null ? PointsROI.defaultPointRadiusProperty().get() : pathPointsROI.getPointRadius();
// Ensure that points are drawn with at least a radius of one, after any transforms have been applied
double scale = Math.max(1, downsample);
radius = (Math.max(1 / scale, radius));
// Get clip bounds
Rectangle2D bounds = g2d.getClipBounds();
if (bounds != null) {
bounds.setRect(bounds.getX() - radius, bounds.getY() - radius, bounds.getWidth() + radius * 2, bounds.getHeight() + radius * 2);
}
// Don't fill if we have a small radius, and use a rectangle instead of an ellipse (as this repaints much faster)
Graphics2D g = g2d;
if (radius / downsample < 0.5) {
if (colorStroke == null)
colorStroke = colorFill;
colorFill = null;
ellipse = new Rectangle2D.Double();
// Use opacity to avoid obscuring points completely
int rule = AlphaComposite.SRC_OVER;
float alpha = (float) (radius / downsample);
var composite = g.getComposite();
if (composite instanceof AlphaComposite) {
var temp = (AlphaComposite) composite;
rule = temp.getRule();
alpha = temp.getAlpha() * alpha;
}
// If we are close to completely transparent, do not paint
if (alpha < 0.01f)
return;
composite = AlphaComposite.getInstance(rule, alpha);
g = (Graphics2D) g2d.create();
g.setComposite(composite);
// ellipse = new Ellipse2D.Double();
} else
ellipse = new Ellipse2D.Double();
g.setStroke(stroke);
for (Point2 p : pathPoints.getAllPoints()) {
if (bounds != null && !bounds.contains(p.getX(), p.getY()))
continue;
ellipse.setFrame(p.getX() - radius, p.getY() - radius, radius * 2, radius * 2);
if (colorFill != null) {
g.setColor(colorFill);
g.fill(ellipse);
}
if (colorStroke != null) {
g.setColor(colorStroke);
g.draw(ellipse);
}
}
if (g != g2d)
g.dispose();
}
Aggregations