use of qupath.lib.regions.ImagePlane in project qupath by qupath.
the class PathObjectTools method mergePointsForSelectedObjectClasses.
// private static void addPathObjectsRecursively(Collection<PathObject> pathObjectsInput, Collection<PathObject> pathObjects, Class<? extends PathObject> cls) {
// Collection<PathObject> buffer = null;
// for (PathObject childObject : pathObjectsInput) {
// if (cls == null || cls.isInstance(childObject)) {
// pathObjects.add(childObject);
// }
// if (childObject.hasChildren()) {
// if (buffer == null)
// buffer = new ArrayList<>();
// else
// buffer.clear();
// childObject.getChildObjects(buffer);
// addPathObjectsRecursively(buffer, pathObjects, cls);
// }
// }
// }
// /**
// * Split annotations containing multi-point ROIs into separate single-point ROIs.
// *
// * @param hierarchy the object hierarchy
// * @param selectedOnly if true, consider only annotations that are currently selected; if false, consider all point annotations in the hierarchy
// * @return true if changes are made to the hierarchy, false otherwise
// */
// public static boolean splitPoints(PathObjectHierarchy hierarchy, boolean selectedOnly) {
// if (hierarchy == null) {
// logger.debug("No hierarchy available, cannot split points!");
// return false;
// }
// return splitPoints(hierarchy, selectedOnly ? hierarchy.getSelectionModel().getSelectedObjects() : hierarchy.getAnnotationObjects());
// }
//
// /**
// * Split annotations containing multi-point ROIs into separate single-point ROIs.
// *
// * @param hierarchy the object hierarchy
// * @param pathObjects a collection of point annotations to split; non-points and non-annotations will be ignored
// * @return pathObjects if changes are made to the hierarchy, false otherwise
// */
// public static boolean splitPoints(PathObjectHierarchy hierarchy, Collection<PathObject> pathObjects) {
// var points = pathObjects.stream().filter(p -> p.isAnnotation() && p.getROI().isPoint() && p.getROI().getNumPoints() > 1).collect(Collectors.toList());
// if (points.isEmpty()) {
// logger.debug("No (multi)point ROIs available to split!");
// return false;
// }
// List<PathObject> newObjects = new ArrayList<>();
// for (PathObject pathObject : points) {
// ROI p = pathObject.getROI();
// ImagePlane plane = p.getImagePlane();
// PathClass pathClass = pathObject.getPathClass();
// for (Point2 p2 : p.getAllPoints()) {
// PathObject temp = PathObjects.createAnnotationObject(ROIs.createPointsROI(p2.getX(), p2.getY(), plane), pathClass);
// newObjects.add(temp);
// }
// }
// hierarchy.removeObjects(points, true);
// hierarchy.addPathObjects(newObjects);
// // Reset the selection
// hierarchy.getSelectionModel().clearSelection();
// return true;
// }
/**
* Merge point annotations sharing the same {@link PathClass} and {@link ImagePlane} as the selected annotations,
* creating multi-point annotations for all matching points and removing the (previously-separated) annotations.
*
* @param hierarchy object hierarchy to modify
* @return true if changes are made to the hierarchy, false otherwise
*/
public static boolean mergePointsForSelectedObjectClasses(PathObjectHierarchy hierarchy) {
var pathClasses = hierarchy.getSelectionModel().getSelectedObjects().stream().filter(p -> p.isAnnotation() && p.getROI().isPoint()).map(p -> p.getPathClass()).collect(Collectors.toSet());
boolean changes = false;
for (PathClass pathClass : pathClasses) changes = changes || mergePointsForClass(hierarchy, pathClass);
return changes;
}
use of qupath.lib.regions.ImagePlane in project qupath by qupath.
the class PointsTool method mousePressed.
@Override
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
if (!e.isPrimaryButtonDown() || e.isConsumed()) {
return;
}
// Get a server, if we can
var viewer = getViewer();
ImageServer<?> server = viewer.getServer();
if (server == null)
return;
var viewerPlane = viewer.getImagePlane();
// Find out the coordinates in the image domain
Point2D p = mouseLocationToImage(e, false, requestPixelSnapping());
double xx = p.getX();
double yy = p.getY();
// If we are outside the image, ignore click
if (xx < 0 || yy < 0 || xx >= server.getWidth() || yy >= server.getHeight())
return;
// See if we have a selected ROI
PathObject currentObjectTemp = viewer.getSelectedObject();
if (!(currentObjectTemp == null || currentObjectTemp instanceof PathROIObject))
return;
PathROIObject currentObject = (PathROIObject) currentObjectTemp;
ROI currentROI = currentObject == null ? null : currentObject.getROI();
RoiEditor editor = viewer.getROIEditor();
double radius = PathPrefs.pointRadiusProperty().get();
ROI points = null;
if (currentROI != null && currentROI.isPoint() && (currentROI.isEmpty() || currentROI.getImagePlane().equals(viewerPlane)))
points = currentROI;
// If Alt is pressed, try to delete a point
if (e.isAltDown()) {
handleAltClick(xx, yy, currentObject);
} else // Create a new ROI if we've got Alt & Shift pressed - or we just don't have a point ROI
if (points == null || (!PathPrefs.multipointToolProperty().get() && !editor.grabHandle(xx, yy, radius, e.isShiftDown())) || (e.isShiftDown() && e.getClickCount() > 1)) {
// PathPoints is effectively ready from the start - don't need to finalize
points = ROIs.createPointsROI(xx, yy, viewerPlane);
currentObject = (PathROIObject) PathObjects.createAnnotationObject(points, PathPrefs.autoSetAnnotationClassProperty().get());
viewer.getHierarchy().addPathObject(currentObject);
viewer.setSelectedObject(currentObject);
// viewer.createAnnotationObject(points);
editor.setROI(points);
editor.grabHandle(xx, yy, radius, e.isShiftDown());
} else if (points != null) {
// Add point to current ROI, or adjust the position of a nearby point
ImagePlane plane = points == null || points.isEmpty() ? viewerPlane : points.getImagePlane();
ROI points2 = addPoint(points, xx, yy, radius, plane);
if (points2 == points) {
// If we didn't add a point, try to grab a handle
if (!editor.grabHandle(xx, yy, radius, e.isShiftDown()))
return;
points2 = (PointsROI) editor.setActiveHandlePosition(xx, yy, 0.25, e.isShiftDown());
} else {
editor.setROI(points2);
editor.grabHandle(xx, yy, radius, e.isShiftDown());
}
if (points2 != points) {
currentObject.setROI(points2);
viewer.getHierarchy().updateObject(currentObject, true);
// viewer.getHierarchy().fireHierarchyChangedEvent(this, currentObject);
}
}
viewer.repaint();
}
use of qupath.lib.regions.ImagePlane in project qupath by qupath.
the class RoiTools method union.
/**
* Create union of multiple ROIs. This assumes that ROIs fall on the same plane, if not an {@link IllegalArgumentException}
* will be thrown. Similarly, ROIs must be of a similar type (e.g. area, point) or an exception will be thrown by Java Topology Suite.
* @param rois
* @return
*/
public static ROI union(Collection<ROI> rois) {
logger.trace("Calculating union of {} ROIs", rois.size());
if (rois.isEmpty())
return ROIs.createEmptyROI();
if (rois.size() == 1)
return rois.iterator().next();
ImagePlane plane = rois.iterator().next().getImagePlane();
List<Geometry> geometries = new ArrayList<>();
for (var r : rois) {
if (!r.getImagePlane().equals(plane)) {
throw new IllegalArgumentException("Cannot merge ROIs - found plane " + r.getImagePlane() + " but expected " + plane);
}
geometries.add(r.getGeometry());
}
return GeometryTools.geometryToROI(GeometryTools.union(geometries), plane);
}
use of qupath.lib.regions.ImagePlane in project qupath by qupath.
the class RoiTools method intersection.
/**
* Create intersection of multiple ROIs. This assumes that ROIs fall on the same plane, if not an {@link IllegalArgumentException}
* will be thrown. Similarly, ROIs must be of a similar type (e.g. area, point) or an exception will be thrown by Java Topology Suite.
* @param rois
* @return
*/
public static ROI intersection(Collection<ROI> rois) {
if (rois.isEmpty())
return ROIs.createEmptyROI();
if (rois.size() == 1)
return rois.iterator().next();
ImagePlane plane = rois.iterator().next().getImagePlane();
List<Geometry> geometries = new ArrayList<>();
for (var r : rois) {
if (!r.getImagePlane().equals(plane)) {
throw new IllegalArgumentException("Cannot merge ROIs - found plane " + r.getImagePlane() + " but expected " + plane);
}
geometries.add(r.getGeometry());
}
Geometry first = geometries.remove(0);
for (var geom : geometries) first = first.intersection(geom);
return GeometryTools.geometryToROI(first, plane);
}
Aggregations