Search in sources :

Example 11 with PathAnnotationObject

use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.

the class ObservableMeasurementTableData method updateMeasurementList.

/**
 * Update the entire measurement list for the current objects.
 * @see #setImageData(ImageData, Collection)
 */
public synchronized void updateMeasurementList() {
    // PathPrefs.setAllredMinPercentagePositive(0);
    builderMap.clear();
    // Add the image name
    if (!PathPrefs.maskImageNamesProperty().get())
        builderMap.put("Image", new ImageNameMeasurementBuilder(imageData));
    // Check if we have any annotations / TMA cores
    boolean containsDetections = false;
    boolean containsAnnotations = false;
    // boolean containsParentAnnotations = false;
    boolean containsTMACores = false;
    boolean containsRoot = false;
    List<PathObject> pathObjectListCopy = new ArrayList<>(list);
    for (PathObject temp : pathObjectListCopy) {
        if (temp instanceof PathAnnotationObject) {
            // if (temp.hasChildren())
            // containsParentAnnotations = true;
            containsAnnotations = true;
        } else if (temp instanceof TMACoreObject) {
            containsTMACores = true;
        } else if (temp instanceof PathDetectionObject) {
            containsDetections = true;
        } else if (temp.isRootObject())
            containsRoot = true;
    }
    boolean detectionsAnywhere = imageData == null ? containsDetections : !imageData.getHierarchy().getDetectionObjects().isEmpty();
    // Include the object displayed name
    // if (containsDetections || containsAnnotations || containsTMACores)
    builderMap.put("Name", new ObjectNameMeasurementBuilder());
    // Include the class
    if (containsAnnotations || containsDetections) {
        builderMap.put("Class", new PathClassMeasurementBuilder());
        // Get the name of the containing TMA core if we have anything other than cores
        if (imageData != null && imageData.getHierarchy().getTMAGrid() != null) {
            builderMap.put("TMA core", new TMACoreNameMeasurementBuilder());
        }
        // Get the name of the first parent object
        builderMap.put("Parent", new ParentNameMeasurementBuilder());
    }
    // Include the TMA missing status, if appropriate
    if (containsTMACores) {
        builderMap.put("Missing", new MissingTMACoreMeasurementBuilder());
    }
    if (containsAnnotations || containsDetections) {
        builderMap.put("ROI", new ROINameMeasurementBuilder());
    }
    // Add centroids
    if (containsAnnotations || containsDetections || containsTMACores) {
        // ROICentroidMeasurementBuilder builder = new ROICentroidMeasurementBuilder(imageData, CentroidType.X);
        // builderMap.put("Centroid X", builder);
        // builder = new ROICentroidMeasurementBuilder(imageData, CentroidType.Y);
        // builderMap.put("Centroid Y", builder);
        ROICentroidMeasurementBuilder builder = new ROICentroidMeasurementBuilder(imageData, CentroidType.X);
        builderMap.put(builder.getName(), builder);
        builder = new ROICentroidMeasurementBuilder(imageData, CentroidType.Y);
        builderMap.put(builder.getName(), builder);
    }
    // If we have metadata, store it
    Set<String> metadataNames = new LinkedHashSet<>();
    metadataNames.addAll(builderMap.keySet());
    for (PathObject pathObject : pathObjectListCopy) {
        if (pathObject instanceof MetadataStore) {
            metadataNames.addAll(((MetadataStore) pathObject).getMetadataKeys());
        }
    }
    // Ensure we have suitable builders
    for (String name : metadataNames) {
        if (!builderMap.containsKey(name))
            builderMap.put(name, new StringMetadataMeasurementBuilder(name));
    }
    // Get all the 'built-in' feature measurements, stored in the measurement list
    Collection<String> features = PathClassifierTools.getAvailableFeatures(pathObjectListCopy);
    // Add derived measurements if we don't have only detections
    if (containsAnnotations || containsTMACores || containsRoot) {
        if (detectionsAnywhere) {
            var builder = new ObjectTypeCountMeasurementBuilder(PathDetectionObject.class);
            builderMap.put(builder.getName(), builder);
            features.add(builder.getName());
        }
        // Here, we allow TMA cores to act like annotations
        manager = new DerivedMeasurementManager(getImageData(), containsAnnotations || containsTMACores);
        for (MeasurementBuilder<?> builder2 : manager.getMeasurementBuilders()) {
            builderMap.put(builder2.getName(), builder2);
            features.add(builder2.getName());
        }
    }
    // If we have an annotation, add shape features
    if (containsAnnotations) {
        boolean anyPoints = false;
        boolean anyAreas = false;
        boolean anyLines = false;
        @SuppressWarnings("unused") boolean anyPolygons = false;
        for (PathObject pathObject : pathObjectListCopy) {
            if (!pathObject.isAnnotation())
                continue;
            ROI roi = pathObject.getROI();
            if (roi == null)
                continue;
            if (roi.isPoint())
                anyPoints = true;
            if (roi.isArea())
                anyAreas = true;
            if (roi.isLine())
                anyLines = true;
            if (pathObject.getROI() instanceof PolygonROI)
                anyPolygons = true;
        }
        // Add point count, if needed
        if (anyPoints) {
            MeasurementBuilder<?> builder = new NumPointsMeasurementBuilder();
            builderMap.put(builder.getName(), builder);
            features.add(builder.getName());
        }
        // Add spatial measurements, if needed
        if (anyAreas) {
            MeasurementBuilder<?> builder = new AreaMeasurementBuilder(imageData);
            builderMap.put(builder.getName(), builder);
            features.add(builder.getName());
            builder = new PerimeterMeasurementBuilder(imageData);
            builderMap.put(builder.getName(), builder);
            features.add(builder.getName());
        }
        if (anyLines) {
            MeasurementBuilder<?> builder = new LineLengthMeasurementBuilder(imageData);
            builderMap.put(builder.getName(), builder);
            features.add(builder.getName());
        }
    // if (anyPolygons) {
    // MeasurementBuilder<?> builder = new MaxDiameterMeasurementBuilder(imageData);
    // builderMap.put(builder.getName(), builder);
    // features.add(builder.getName());
    // 
    // builder = new MinDiameterMeasurementBuilder(imageData);
    // builderMap.put(builder.getName(), builder);
    // features.add(builder.getName());
    // }
    }
    if (containsAnnotations || containsTMACores || containsRoot) {
        var pixelClassifier = getPixelLayer(imageData);
        if (pixelClassifier instanceof ImageServer<?>) {
            ImageServer<BufferedImage> server = (ImageServer<BufferedImage>) pixelClassifier;
            if (server.getMetadata().getChannelType() == ImageServerMetadata.ChannelType.CLASSIFICATION || server.getMetadata().getChannelType() == ImageServerMetadata.ChannelType.PROBABILITY) {
                var pixelManager = new PixelClassificationMeasurementManager(server);
                for (String name : pixelManager.getMeasurementNames()) {
                    // String nameLive = name + " (live)";
                    String nameLive = "(Live) " + name;
                    builderMap.put(nameLive, new PixelClassifierMeasurementBuilder(pixelManager, name));
                    features.add(nameLive);
                }
            }
        }
    }
    // Update all the lists, if necessary
    boolean changes = false;
    if (metadataNames.size() != metadataList.size() || !metadataNames.containsAll(metadataList)) {
        changes = metadataList.setAll(metadataNames);
    }
    if (features.size() != measurementList.size() || !features.containsAll(measurementList))
        changes = measurementList.setAll(features);
    if (changes) {
        if (metadataList.isEmpty())
            fullList.setAll(measurementList);
        else {
            fullList.setAll(metadataList);
            fullList.addAll(measurementList);
        }
    }
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ArrayList(java.util.ArrayList) BufferedImage(java.awt.image.BufferedImage) PolygonROI(qupath.lib.roi.PolygonROI) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) ImageServer(qupath.lib.images.servers.ImageServer) PathDetectionObject(qupath.lib.objects.PathDetectionObject) TMACoreObject(qupath.lib.objects.TMACoreObject) PolygonROI(qupath.lib.roi.PolygonROI) ROI(qupath.lib.roi.interfaces.ROI) MetadataStore(qupath.lib.objects.MetadataStore) PathObject(qupath.lib.objects.PathObject) PixelClassificationMeasurementManager(qupath.opencv.ml.pixel.PixelClassificationMeasurementManager)

Example 12 with PathAnnotationObject

use of qupath.lib.objects.PathAnnotationObject 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;
}
Also used : PathDetectionObject(qupath.lib.objects.PathDetectionObject) ArrayList(java.util.ArrayList) PointsROI(qupath.lib.roi.PointsROI) TreeMap(java.util.TreeMap) PathClass(qupath.lib.objects.classes.PathClass) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) Point2(qupath.lib.geom.Point2) ArrayList(java.util.ArrayList) List(java.util.List)

Example 13 with PathAnnotationObject

use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.

the class ClassifierBuilderPane method hierarchyChanged.

@Override
public void hierarchyChanged(PathObjectHierarchyEvent event) {
    if (event.getSource() == this)
        return;
    if (!Platform.isFxApplicationThread()) {
        Platform.runLater(() -> hierarchyChanged(event));
        return;
    }
    // Flag that the hierarchy has changed if this is any kind of event other than an object classification event
    hierarchyChanged = hierarchyChanged || !event.isObjectClassificationEvent();
    // TODO: Avoid reliance on this, and instead check the training objects used
    if (event.isStructureChangeEvent()) {
        // Don't respond to adding/removing annotation objects without classes set
        if (event.isAddedOrRemovedEvent()) {
            PathObject pathObjectChanged = event.getChangedObjects().get(0);
            if (!(pathObjectChanged instanceof PathAnnotationObject) || pathObjectChanged.getPathClass() == null)
                return;
        }
    } else if (event.isObjectClassificationEvent()) {
        // If classifications have changed, we only care if these contain annotations
        boolean containsAnnotations = containsObjectsOfClass(event.getChangedObjects(), PathAnnotationObject.class);
        if (!containsAnnotations)
            return;
    } else if (event.getEventType() == HierarchyEventType.CHANGE_OTHER) {
        return;
    }
    // TODO: See if calls can be reduced
    maybeUpdate();
}
Also used : PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject)

Example 14 with PathAnnotationObject

use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.

the class QuPathGUI method updateSetAnnotationPathClassMenu.

void updateSetAnnotationPathClassMenu(final ObservableList<MenuItem> menuSetClassItems, final QuPathViewer viewer, final boolean useFancyIcons) {
    // We need a viewer and an annotation, as well as some PathClasses, otherwise we just need to ensure the menu isn't visible
    if (viewer == null || !(viewer.getSelectedObject() instanceof PathAnnotationObject) || availablePathClasses.isEmpty()) {
        menuSetClassItems.clear();
        return;
    }
    PathObject mainPathObject = viewer.getSelectedObject();
    PathClass currentClass = mainPathObject.getPathClass();
    ToggleGroup group = new ToggleGroup();
    List<MenuItem> itemList = new ArrayList<>();
    RadioMenuItem selected = null;
    for (PathClass pathClass : availablePathClasses) {
        PathClass pathClassToSet = pathClass.getName() == null ? null : pathClass;
        String name = pathClass.getName() == null ? "None" : pathClass.toString();
        Action actionSetClass = new Action(name, e -> {
            List<PathObject> changed = new ArrayList<>();
            for (PathObject pathObject : viewer.getAllSelectedObjects()) {
                if (!pathObject.isAnnotation() || pathObject.getPathClass() == pathClassToSet)
                    continue;
                pathObject.setPathClass(pathClassToSet);
                changed.add(pathObject);
            }
            if (!changed.isEmpty())
                viewer.getHierarchy().fireObjectClassificationsChangedEvent(this, changed);
        });
        Node shape;
        if (useFancyIcons) {
            Ellipse r = new Ellipse(TOOLBAR_ICON_SIZE / 2.0, TOOLBAR_ICON_SIZE / 2.0, TOOLBAR_ICON_SIZE, TOOLBAR_ICON_SIZE);
            if ("None".equals(name)) {
                r.setFill(Color.rgb(255, 255, 255, 0.75));
            } else
                r.setFill(ColorToolsFX.getCachedColor(pathClass.getColor()));
            r.setOpacity(0.8);
            DropShadow effect = new DropShadow(6, -3, 3, Color.GRAY);
            r.setEffect(effect);
            shape = r;
        } else {
            Rectangle r = new Rectangle(0, 0, 8, 8);
            r.setFill("None".equals(name) ? Color.TRANSPARENT : ColorToolsFX.getCachedColor(pathClass.getColor()));
            shape = r;
        }
        // actionSetClass.setGraphic(r);
        RadioMenuItem item = ActionUtils.createRadioMenuItem(actionSetClass);
        item.graphicProperty().unbind();
        item.setGraphic(shape);
        item.setToggleGroup(group);
        itemList.add(item);
        if (pathClassToSet == currentClass)
            selected = item;
    }
    group.selectToggle(selected);
    menuSetClassItems.setAll(itemList);
}
Also used : Action(org.controlsfx.control.action.Action) Ellipse(javafx.scene.shape.Ellipse) Node(javafx.scene.Node) ArrayList(java.util.ArrayList) Rectangle(javafx.scene.shape.Rectangle) MenuItem(javafx.scene.control.MenuItem) CheckMenuItem(javafx.scene.control.CheckMenuItem) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) RadioMenuItem(javafx.scene.control.RadioMenuItem) RadioMenuItem(javafx.scene.control.RadioMenuItem) DropShadow(javafx.scene.effect.DropShadow) PathClass(qupath.lib.objects.classes.PathClass) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) ToggleGroup(javafx.scene.control.ToggleGroup)

Example 15 with PathAnnotationObject

use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.

the class ImageJMacroRunner method runMacro.

static void runMacro(final ParameterList params, final ImageData<BufferedImage> imageData, final ImageDisplay imageDisplay, final PathObject pathObject, final String macroText) {
    // Don't try if interrupted
    if (Thread.currentThread().isInterrupted()) {
        logger.warn("Skipping macro for {} - thread interrupted", pathObject);
        return;
    }
    PathImage<ImagePlus> pathImage;
    // Extract parameters
    double downsampleFactor = params.getDoubleParameterValue("downsampleFactor");
    boolean sendROI = params.getBooleanParameterValue("sendROI");
    boolean sendOverlay = params.getBooleanParameterValue("sendOverlay");
    ROI pathROI = pathObject.getROI();
    ImageDisplay imageDisplay2 = params.containsKey("useTransform") && Boolean.TRUE.equals(params.getBooleanParameterValue("useTransform")) ? imageDisplay : null;
    ImageServer<BufferedImage> server = imageDisplay2 == null || imageDisplay2.availableChannels().isEmpty() ? imageData.getServer() : ChannelDisplayTransformServer.createColorTransformServer(imageData.getServer(), imageDisplay.availableChannels());
    RegionRequest region = RegionRequest.createInstance(imageData.getServer().getPath(), downsampleFactor, pathROI);
    // Check the size of the region to extract - abort if it is too large of if ther isn't enough RAM
    try {
        IJTools.isMemorySufficient(region, imageData);
    } catch (Exception e1) {
        Dialogs.showErrorMessage("ImageJ macro error", e1.getMessage());
        return;
    }
    try {
        if (sendOverlay)
            pathImage = IJExtension.extractROIWithOverlay(server, pathObject, imageData.getHierarchy(), region, sendROI, null);
        else
            pathImage = IJExtension.extractROI(server, pathObject, region, sendROI);
    } catch (IOException e) {
        logger.error("Unable to extract image region " + region, e);
        return;
    }
    // IJHelpers.getImageJInstance();
    // ImageJ ij = IJHelpers.getImageJInstance();
    // if (ij != null && WindowManager.getIDList() == null)
    // ij.setVisible(false);
    // Determine a sensible argument to pass
    String argument;
    if (pathObject instanceof TMACoreObject || !pathObject.hasROI())
        argument = pathObject.getDisplayedName();
    else
        argument = String.format("Region (%d, %d, %d, %d)", region.getX(), region.getY(), region.getWidth(), region.getHeight());
    // Check if we have an image already - if so, we need to be more cautious so we don't accidentally use it...
    // boolean hasImage = WindowManager.getCurrentImage() != null;
    // Actually run the macro
    final ImagePlus imp = pathImage.getImage();
    imp.setProperty("QuPath region", argument);
    WindowManager.setTempCurrentImage(imp);
    // Ensure we've requested an instance, since this also loads any required extra plugins
    IJExtension.getImageJInstance();
    // TODO: Pay attention to how threading should be done... I think Swing EDT ok?
    try {
        // SwingUtilities.invokeAndWait(() -> {
        boolean cancelled = false;
        ImagePlus impResult = null;
        try {
            IJ.redirectErrorMessages();
            Interpreter interpreter = new Interpreter();
            impResult = interpreter.runBatchMacro(macroText, imp);
            // If we had an error, return
            if (interpreter.wasError()) {
                Thread.currentThread().interrupt();
                return;
            }
            // Get the resulting image, if available
            if (impResult == null)
                impResult = WindowManager.getCurrentImage();
        } catch (RuntimeException e) {
            logger.error(e.getLocalizedMessage());
            // DisplayHelpers.showErrorMessage("ImageJ macro error", e.getLocalizedMessage());
            Thread.currentThread().interrupt();
            cancelled = true;
        } finally {
            // IJ.runMacro(macroText, argument);
            WindowManager.setTempCurrentImage(null);
        // IJ.run("Close all");
        }
        if (cancelled)
            return;
        // Get the current image when the macro has finished - which may or may not be the same as the original
        if (impResult == null)
            impResult = imp;
        boolean changes = false;
        if (params.getBooleanParameterValue("clearObjects") && pathObject.hasChildren()) {
            pathObject.clearPathObjects();
            changes = true;
        }
        if (params.getBooleanParameterValue("getROI") && impResult.getRoi() != null) {
            Roi roi = impResult.getRoi();
            Calibration cal = impResult.getCalibration();
            PathObject pathObjectNew = roi == null ? null : IJTools.convertToAnnotation(roi, cal.xOrigin, cal.yOrigin, downsampleFactor, region.getPlane());
            if (pathObjectNew != null) {
                // If necessary, trim any returned annotation
                if (pathROI != null && !(pathROI instanceof RectangleROI) && pathObjectNew.isAnnotation() && RoiTools.isShapeROI(pathROI) && RoiTools.isShapeROI(pathObjectNew.getROI())) {
                    ROI roiNew = RoiTools.combineROIs(pathROI, pathObjectNew.getROI(), CombineOp.INTERSECT);
                    ((PathAnnotationObject) pathObjectNew).setROI(roiNew);
                }
                // Only add if we have something
                if (pathObjectNew.getROI() instanceof LineROI || !pathObjectNew.getROI().isEmpty()) {
                    pathObject.addPathObject(pathObjectNew);
                    // imageData.getHierarchy().addPathObject(IJHelpers.convertToPathObject(imp, imageData.getServer(), imp.getRoi(), downsampleFactor, false), true);
                    changes = true;
                }
            }
        }
        boolean exportAsDetection = ((String) params.getChoiceParameterValue("getOverlayAs")).equals("Detections") ? true : false;
        if (params.getBooleanParameterValue("getOverlay") && impResult.getOverlay() != null) {
            var overlay = impResult.getOverlay();
            List<PathObject> childObjects = QuPath_Send_Overlay_to_QuPath.createObjectsFromROIs(imp, Arrays.asList(overlay.toArray()), downsampleFactor, exportAsDetection, true, region.getPlane());
            if (!childObjects.isEmpty()) {
                pathObject.addPathObjects(childObjects);
                changes = true;
            }
        // for (Roi roi : impResult.getOverlay().toArray()) {
        // pathObject.addPathObject(IJTools.convertToPathObject(imp, imageData.getServer(), roi, downsampleFactor, true));
        // changes = true;
        // }
        }
        if (changes) {
            Platform.runLater(() -> imageData.getHierarchy().fireHierarchyChangedEvent(null));
        }
    // });
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
Also used : Interpreter(ij.macro.Interpreter) TMACoreObject(qupath.lib.objects.TMACoreObject) IOException(java.io.IOException) Calibration(ij.measure.Calibration) ImagePlus(ij.ImagePlus) RectangleROI(qupath.lib.roi.RectangleROI) LineROI(qupath.lib.roi.LineROI) ROI(qupath.lib.roi.interfaces.ROI) Roi(ij.gui.Roi) BufferedImage(java.awt.image.BufferedImage) InvocationTargetException(java.lang.reflect.InvocationTargetException) IOException(java.io.IOException) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) RectangleROI(qupath.lib.roi.RectangleROI) LineROI(qupath.lib.roi.LineROI) RegionRequest(qupath.lib.regions.RegionRequest) ImageDisplay(qupath.lib.display.ImageDisplay)

Aggregations

PathAnnotationObject (qupath.lib.objects.PathAnnotationObject)19 PathObject (qupath.lib.objects.PathObject)16 ArrayList (java.util.ArrayList)11 ROI (qupath.lib.roi.interfaces.ROI)11 TMACoreObject (qupath.lib.objects.TMACoreObject)9 PathObjectHierarchy (qupath.lib.objects.hierarchy.PathObjectHierarchy)7 BufferedImage (java.awt.image.BufferedImage)6 List (java.util.List)6 TextArea (javafx.scene.control.TextArea)5 Tooltip (javafx.scene.control.Tooltip)5 IOException (java.io.IOException)4 Collections (java.util.Collections)4 Collectors (java.util.stream.Collectors)4 Point2D (java.awt.geom.Point2D)3 File (java.io.File)3 Collection (java.util.Collection)3 LinkedHashMap (java.util.LinkedHashMap)3 Bindings (javafx.beans.binding.Bindings)3 SimpleBooleanProperty (javafx.beans.property.SimpleBooleanProperty)3 Scene (javafx.scene.Scene)3