Search in sources :

Example 1 with ROI

use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.

the class DelaunayTriangulation method computeDelaunay.

void computeDelaunay(final List<PathObject> pathObjectList, final double pixelWidth, final double pixelHeight) {
    if (pathObjectList.size() <= 2)
        return;
    this.vertexMap = new HashMap<>(pathObjectList.size(), 1f);
    // Extract the centroids
    double minX = Double.POSITIVE_INFINITY;
    double minY = Double.POSITIVE_INFINITY;
    double maxX = Double.NEGATIVE_INFINITY;
    double maxY = Double.NEGATIVE_INFINITY;
    List<Point2f> centroids = new ArrayList<>(pathObjectList.size());
    for (PathObject pathObject : pathObjectList) {
        ROI pathROI = null;
        // First, try to get a nucleus ROI if we have a cell - otherwise just get the normal ROI
        pathROI = getROI(pathObject);
        // Check if we have a ROI at all
        if (pathROI == null) {
            centroids.add(null);
            continue;
        }
        double x = pathROI.getCentroidX();
        double y = pathROI.getCentroidY();
        if (Double.isNaN(x) || Double.isNaN(y)) {
            centroids.add(null);
            continue;
        }
        if (x < minX)
            minX = x;
        else if (x > maxX)
            maxX = x;
        if (y < minY)
            minY = y;
        else if (y > maxY)
            maxY = y;
        centroids.add(new Point2f((float) x, (float) y));
    }
    // Create Delaunay triangulation, updating vertex map
    Subdiv2D subdiv = new Subdiv2D();
    Rect bounds = new Rect((int) minX - 1, (int) minY - 1, (int) (maxX - minX) + 100, (int) (maxY - minY) + 100);
    subdiv.initDelaunay(bounds);
    for (int i = 0; i < centroids.size(); i++) {
        Point2f p = centroids.get(i);
        if (p == null)
            continue;
        int v = subdiv.insert(p);
        vertexMap.put(v, pathObjectList.get(i));
    }
    updateNodeMap(subdiv, pixelWidth, pixelHeight);
// // Connect only the closest paired nodes
// Map<DelaunayNode, Double> medianDistances = new HashMap<>();
// for (DelaunayNode node : nodeMap.values()) {
// medianDistances.put(node, node.medianDistance());
// }
// 
// for (DelaunayNode node : nodeMap.values()) {
// if (node.nNeighbors() <= 2)
// continue;
// double distance = medianDistances.get(node);
// Iterator<DelaunayNode> iter = node.nodeList.iterator();
// while (iter.hasNext()) {
// DelaunayNode node2 = iter.next();
// if (distance(node, node2) >= distance) {
// node2.nodeList.remove(node);
// iter.remove();
// }
// }
// }
// // Optionally require a minimum number of connected nodes
// List<DelaunayNode> toRemove = new ArrayList<>();
// for (DelaunayNode node : nodeMap.values()) {
// if (node.nNeighbors() <= 2) {
// toRemove.add(node);
// }
// }
// for (DelaunayNode node : toRemove) {
// for (DelaunayNode node2 : node.nodeList)
// node2.nodeList.remove(node);
// node.nodeList.clear();
// }
// for (DelaunayNode node : nodeMap.values()) {
// node.ensureDistancesUpdated();
// node.ensureTrianglesCalculated();
// }
}
Also used : Rect(org.bytedeco.opencv.opencv_core.Rect) Point2f(org.bytedeco.opencv.opencv_core.Point2f) PathObject(qupath.lib.objects.PathObject) ArrayList(java.util.ArrayList) Subdiv2D(org.bytedeco.opencv.opencv_imgproc.Subdiv2D) ROI(qupath.lib.roi.interfaces.ROI)

Example 2 with ROI

use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.

the class DelaunayTriangulation method getConnectedNodes.

/**
 * Get connected nodes.  Returned as a list where pairs are consecutive, i.e.
 * get(i) links to get(i+1)
 * (although get(i+1) doesn't necessarily link to get(i+2)...)
 *
 * @param pathObjects
 * @param connections
 * @return
 */
@Deprecated
public Collection<double[]> getConnectedNodes(final Collection<PathObject> pathObjects, Collection<double[]> connections) {
    if (connections == null)
        connections = new HashSet<>();
    if (nodeMap == null || pathObjects.isEmpty())
        return connections;
    for (PathObject temp : pathObjects) {
        DelaunayNode node = nodeMap.get(temp);
        if (node == null)
            continue;
        ROI roi = getROI(temp);
        double x1 = roi.getCentroidX();
        double y1 = roi.getCentroidY();
        for (DelaunayNode node2 : node.nodeList) {
            ROI roi2 = getROI(node2.getPathObject());
            double x2 = roi2.getCentroidX();
            double y2 = roi2.getCentroidY();
            if (x1 < x2 || (x1 == x2 && y1 <= y2))
                connections.add(new double[] { x1, y1, x2, y2 });
            else
                connections.add(new double[] { x2, y2, x1, y1 });
        }
    }
    return connections;
}
Also used : PathObject(qupath.lib.objects.PathObject) ROI(qupath.lib.roi.interfaces.ROI) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 3 with ROI

use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.

the class SplitAnnotationsPlugin method getTasks.

@Override
protected Collection<Runnable> getTasks(final PluginRunner<T> runner) {
    Collection<? extends PathObject> parentObjects = getParentObjects(runner);
    if (parentObjects == null || parentObjects.isEmpty())
        return Collections.emptyList();
    // Add a single task, to avoid multithreading - which may complicate setting parents
    List<Runnable> tasks = new ArrayList<>(1);
    PathObjectHierarchy hierarchy = getHierarchy(runner);
    // Want to reset selection
    PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
    tasks.add(() -> {
        /*
			 * Resolving the hierarchy with many objects can be very slow.
			 * Here, we take an object, split it and then add it below the original object in the hierarchy.
			 * We then just need to remove the originals, allowing the newly-added objects to have their 
			 * parents reassigned.
			 */
        List<PathObject> toAdd = new ArrayList<>();
        List<PathObject> toRemove = new ArrayList<>();
        List<PathObject> localSplit = new ArrayList<>();
        Set<PathObject> toSelect = new HashSet<>();
        for (PathObject pathObject : parentObjects) {
            localSplit.clear();
            ROI roiOrig = pathObject.getROI();
            if (roiOrig == null) {
                toSelect.add(pathObject);
                continue;
            }
            var splitROIs = RoiTools.splitROI(roiOrig);
            if (splitROIs.size() == 1)
                continue;
            toRemove.add(pathObject);
            for (var r : splitROIs) {
                var annotation = PathObjects.createAnnotationObject(r, pathObject.getPathClass());
                annotation.setLocked(pathObject.isLocked());
                localSplit.add(annotation);
            }
            if (pathObject.hasChildren()) {
                for (var temp : localSplit) hierarchy.addPathObjectBelowParent(pathObject, temp, false);
            } else
                pathObject.addPathObjects(localSplit);
            toAdd.addAll(localSplit);
        }
        if (toAdd.isEmpty() && toRemove.isEmpty())
            return;
        hierarchy.getSelectionModel().clearSelection();
        toSelect.addAll(toAdd);
        hierarchy.removeObjects(toRemove, true);
        // hierarchy.addPathObjects(toAdd, false);
        hierarchy.getSelectionModel().selectObjects(toSelect);
        if (toSelect.contains(selected))
            hierarchy.getSelectionModel().setSelectedObject(selected, true);
    });
    return tasks;
}
Also used : PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) PathObject(qupath.lib.objects.PathObject) ArrayList(java.util.ArrayList) ROI(qupath.lib.roi.interfaces.ROI) HashSet(java.util.HashSet)

Example 4 with ROI

use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.

the class RigidObjectEditorCommand method createTransformedObject.

PathObject createTransformedObject() {
    ROI roi = originalObject.getROI();
    ROI shape = GeometryTools.geometryToROI(transformer.getTransformedShape(), roi.getImagePlane());
    return PathObjects.createAnnotationObject(shape, originalObject.getPathClass());
}
Also used : PolylineROI(qupath.lib.roi.PolylineROI) ROI(qupath.lib.roi.interfaces.ROI)

Example 5 with ROI

use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.

the class RigidObjectEditorCommand method run.

@Override
public void run() {
    // Object is already being edited
    if (this.originalObject != null) {
        // viewer.setSelectedObject(tempObject);
        return;
    }
    // Get the selected object
    viewer = qupath.getViewer();
    PathObject pathObject = getSelectedObject(viewer);
    if (pathObject == null || !(pathObject.isAnnotation() || pathObject.isTMACore())) {
        Dialogs.showErrorNotification("Rotate annotation", "No annotation selected!");
        return;
    }
    if (pathObject.isLocked()) {
        Dialogs.showErrorNotification("Rotate annotation", "Selected annotation is locked!");
        return;
    }
    // if (pathObject.getROI().isPoint()) {
    // Dialogs.showErrorNotification("Rotate annotation", "Point annotations cannot be rotated, sorry!");
    // return;
    // }
    ImageRegion bounds = viewer.getServerBounds();
    if (pathObject.isTMACore()) {
        for (PathObject child : pathObject.getChildObjectsAsArray()) {
            if (isSuitableAnnotation(child)) {
                originalObjectROIs.put(child, child.getROI());
            }
        }
        if (originalObjectROIs.isEmpty()) {
            Dialogs.showErrorMessage("Rigid refinement problem", "TMA core must contain empty annotations objects for rigid refinement");
            return;
        }
    }
    originalObjectROIs.put(pathObject, pathObject.getROI());
    this.originalObject = pathObject;
    viewer.setActiveTool(null);
    qupath.setToolSwitchingEnabled(false);
    viewer.addViewerListener(this);
    viewer.getView().addEventHandler(MouseEvent.ANY, mouseListener);
    // // Remove selected object & create an overlay showing the currently-being-edited version
    // viewer.getHierarchy().removeObject(originalObject, true, true);
    transformer = new RoiAffineTransformer(bounds, originalObject.getROI());
    // editingROI = new RotatedROI((PathArea)originalObject.getROI());
    // editingROI.setAngle(Math.PI/3);
    overlay = new AffineEditOverlay(viewer.getOverlayOptions());
    viewer.getCustomOverlayLayers().add(overlay);
    PathPrefs.paintSelectedBoundsProperty().set(false);
    // Create & show temporary object
    for (Entry<PathObject, ROI> entry : originalObjectROIs.entrySet()) ((PathROIObject) entry.getKey()).setROI(transformer.getTransformedROI(entry.getValue(), false));
    // Reset any existing editor (and its visible handles)
    viewer.getROIEditor().setROI(null);
    viewer.repaint();
// tempObject = createTransformedObject();
// ((PathAnnotationObject)tempObject).setLocked(true);
// viewer.setSelectedObject(tempObject);
}
Also used : PathObject(qupath.lib.objects.PathObject) ImageRegion(qupath.lib.regions.ImageRegion) PolylineROI(qupath.lib.roi.PolylineROI) ROI(qupath.lib.roi.interfaces.ROI)

Aggregations

ROI (qupath.lib.roi.interfaces.ROI)87 PathObject (qupath.lib.objects.PathObject)61 ArrayList (java.util.ArrayList)31 BufferedImage (java.awt.image.BufferedImage)24 PathObjectHierarchy (qupath.lib.objects.hierarchy.PathObjectHierarchy)24 IOException (java.io.IOException)20 RegionRequest (qupath.lib.regions.RegionRequest)19 List (java.util.List)17 Collectors (java.util.stream.Collectors)17 RectangleROI (qupath.lib.roi.RectangleROI)17 Logger (org.slf4j.Logger)16 LoggerFactory (org.slf4j.LoggerFactory)16 PolygonROI (qupath.lib.roi.PolygonROI)16 PathAnnotationObject (qupath.lib.objects.PathAnnotationObject)15 Point2D (java.awt.geom.Point2D)14 Collection (java.util.Collection)14 Collections (java.util.Collections)14 Geometry (org.locationtech.jts.geom.Geometry)14 PathClass (qupath.lib.objects.classes.PathClass)14 ImagePlane (qupath.lib.regions.ImagePlane)13