Search in sources :

Example 11 with ImagePlane

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;
}
Also used : PathClassTools(qupath.lib.objects.classes.PathClassTools) LoggerFactory(org.slf4j.LoggerFactory) HashMap(java.util.HashMap) PathClassFactory(qupath.lib.objects.classes.PathClassFactory) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) Function(java.util.function.Function) ArrayList(java.util.ArrayList) MeasurementList(qupath.lib.measurements.MeasurementList) EllipseROI(qupath.lib.roi.EllipseROI) HashSet(java.util.HashSet) ROIs(qupath.lib.roi.ROIs) PointsROI(qupath.lib.roi.PointsROI) Point2(qupath.lib.geom.Point2) ImageRegion(qupath.lib.regions.ImageRegion) Map(java.util.Map) PreparedGeometry(org.locationtech.jts.geom.prep.PreparedGeometry) LinkedHashSet(java.util.LinkedHashSet) LineROI(qupath.lib.roi.LineROI) Line2D(java.awt.geom.Line2D) RoiTools(qupath.lib.roi.RoiTools) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Predicate(java.util.function.Predicate) Collection(java.util.Collection) PathClass(qupath.lib.objects.classes.PathClass) Set(java.util.Set) AffineTransform(java.awt.geom.AffineTransform) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) ROI(qupath.lib.roi.interfaces.ROI) List(java.util.List) Entry(java.util.Map.Entry) ImagePlane(qupath.lib.regions.ImagePlane) Geometry(org.locationtech.jts.geom.Geometry) Comparator(java.util.Comparator) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) Collections(java.util.Collections) PreparedGeometryFactory(org.locationtech.jts.geom.prep.PreparedGeometryFactory) STRtree(org.locationtech.jts.index.strtree.STRtree) PathClass(qupath.lib.objects.classes.PathClass)

Example 12 with ImagePlane

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();
}
Also used : PathObject(qupath.lib.objects.PathObject) RoiEditor(qupath.lib.roi.RoiEditor) Point2D(java.awt.geom.Point2D) ImagePlane(qupath.lib.regions.ImagePlane) PathROIObject(qupath.lib.objects.PathROIObject) ROI(qupath.lib.roi.interfaces.ROI) PointsROI(qupath.lib.roi.PointsROI)

Example 13 with ImagePlane

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);
}
Also used : PreparedGeometry(org.locationtech.jts.geom.prep.PreparedGeometry) Geometry(org.locationtech.jts.geom.Geometry) ArrayList(java.util.ArrayList) ImagePlane(qupath.lib.regions.ImagePlane)

Example 14 with ImagePlane

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);
}
Also used : PreparedGeometry(org.locationtech.jts.geom.prep.PreparedGeometry) Geometry(org.locationtech.jts.geom.Geometry) ArrayList(java.util.ArrayList) ImagePlane(qupath.lib.regions.ImagePlane)

Aggregations

ImagePlane (qupath.lib.regions.ImagePlane)14 ArrayList (java.util.ArrayList)9 PathObject (qupath.lib.objects.PathObject)8 HashMap (java.util.HashMap)7 ROI (qupath.lib.roi.interfaces.ROI)7 Geometry (org.locationtech.jts.geom.Geometry)6 List (java.util.List)5 PointsROI (qupath.lib.roi.PointsROI)5 Collection (java.util.Collection)4 Map (java.util.Map)4 Collectors (java.util.stream.Collectors)4 Logger (org.slf4j.Logger)4 LoggerFactory (org.slf4j.LoggerFactory)4 PathClass (qupath.lib.objects.classes.PathClass)4 PathClassFactory (qupath.lib.objects.classes.PathClassFactory)4 PathClassTools (qupath.lib.objects.classes.PathClassTools)4 RoiTools (qupath.lib.roi.RoiTools)4 Collections (java.util.Collections)3 Comparator (java.util.Comparator)3 PreparedGeometry (org.locationtech.jts.geom.prep.PreparedGeometry)3