Search in sources :

Example 61 with PathObject

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

the class ObservableMeasurementTableDataTest method test.

@SuppressWarnings("javadoc")
@Test
public void test() {
    // See https://github.com/locationtech/jts/issues/571
    for (int counter = 0; counter < 50; counter++) {
        ImageData<BufferedImage> imageData = new ImageData<>(null);
        PathClass tumorClass = PathClassFactory.getPathClass(StandardPathClasses.TUMOR);
        PathClass stromaClass = PathClassFactory.getPathClass(StandardPathClasses.STROMA);
        // PathClass otherClass = PathClassFactory.getDefaultPathClass(PathClasses.OTHER);
        PathClass artefactClass = PathClassFactory.getPathClass("Artefact");
        PathObjectHierarchy hierarchy = imageData.getHierarchy();
        // Add a parent annotation
        PathObject parent = PathObjects.createAnnotationObject(ROIs.createRectangleROI(500, 500, 1000, 1000, ImagePlane.getDefaultPlane()));
        // Create 100 tumor detections
        // ROI emptyROI = ROIs.createEmptyROI();
        ROI smallROI = ROIs.createRectangleROI(500, 500, 1, 1, ImagePlane.getDefaultPlane());
        for (int i = 0; i < 100; i++) {
            if (i < 25)
                parent.addPathObject(PathObjects.createDetectionObject(smallROI, PathClassFactory.getNegative(tumorClass)));
            else if (i < 50)
                parent.addPathObject(PathObjects.createDetectionObject(smallROI, PathClassFactory.getOnePlus(tumorClass)));
            else if (i < 75)
                parent.addPathObject(PathObjects.createDetectionObject(smallROI, PathClassFactory.getTwoPlus(tumorClass)));
            else if (i < 100)
                parent.addPathObject(PathObjects.createDetectionObject(smallROI, PathClassFactory.getThreePlus(tumorClass)));
        }
        // Create 100 stroma detections
        for (int i = 0; i < 100; i++) {
            if (i < 50)
                parent.addPathObject(PathObjects.createDetectionObject(smallROI, PathClassFactory.getNegative(stromaClass)));
            else if (i < 60)
                parent.addPathObject(PathObjects.createDetectionObject(smallROI, PathClassFactory.getOnePlus(stromaClass)));
            else if (i < 70)
                parent.addPathObject(PathObjects.createDetectionObject(smallROI, PathClassFactory.getTwoPlus(stromaClass)));
            else if (i < 100)
                parent.addPathObject(PathObjects.createDetectionObject(smallROI, PathClassFactory.getThreePlus(stromaClass)));
        }
        // Create 50 artefact detections
        for (int i = 0; i < 50; i++) {
            parent.addPathObject(PathObjects.createDetectionObject(smallROI, artefactClass));
        }
        hierarchy.addPathObject(parent);
        ObservableMeasurementTableData model = new ObservableMeasurementTableData();
        model.setImageData(imageData, Collections.singletonList(parent));
        // Check tumor counts
        assertEquals(100, model.getNumericValue(parent, "Num Tumor (base)"), EPSILON);
        assertEquals(25, model.getNumericValue(parent, "Num Tumor: Negative"), EPSILON);
        assertEquals(25, model.getNumericValue(parent, "Num Tumor: 1+"), EPSILON);
        assertEquals(25, model.getNumericValue(parent, "Num Tumor: 2+"), EPSILON);
        assertEquals(25, model.getNumericValue(parent, "Num Tumor: 3+"), EPSILON);
        assertTrue(Double.isNaN(model.getNumericValue(parent, "Num Tumor: 4+")));
        // Check tumor H-score, Allred score & positive %
        assertEquals(150, model.getNumericValue(parent, "Tumor: H-score"), EPSILON);
        assertEquals(75, model.getNumericValue(parent, "Tumor: Positive %"), EPSILON);
        assertEquals(2, model.getNumericValue(parent, "Tumor: Allred intensity"), EPSILON);
        assertEquals(5, model.getNumericValue(parent, "Tumor: Allred proportion"), EPSILON);
        assertEquals(7, model.getNumericValue(parent, "Tumor: Allred score"), EPSILON);
        // Check tumor H-score unaffected when tumor detections added without intensity classification
        for (int i = 0; i < 10; i++) parent.addPathObject(PathObjects.createDetectionObject(smallROI, tumorClass));
        hierarchy.fireHierarchyChangedEvent(this);
        model.refreshEntries();
        // model.setImageData(imageData, Collections.singletonList(parent));
        assertEquals(100, model.getNumericValue(parent, "Num Stroma (base)"), EPSILON);
        assertEquals(50, model.getNumericValue(parent, "Num Stroma: Negative"), EPSILON);
        assertEquals(150, model.getNumericValue(parent, "Tumor: H-score"), EPSILON);
        assertEquals(75, model.getNumericValue(parent, "Tumor: Positive %"), EPSILON);
        // Check stroma scores
        assertEquals(100, model.getNumericValue(parent, "Num Stroma (base)"), EPSILON);
        assertEquals(120, model.getNumericValue(parent, "Stroma: H-score"), EPSILON);
        // Check complete scores
        assertEquals(135, model.getNumericValue(parent, "Stroma + Tumor: H-score"), EPSILON);
        // Add a new parent that completely contains the current object, and confirm complete scores agree
        PathObject parentNew = PathObjects.createAnnotationObject(ROIs.createRectangleROI(0, 0, 2000, 2000, ImagePlane.getDefaultPlane()));
        hierarchy.addPathObject(parentNew);
        model.refreshEntries();
        assertEquals(135, model.getNumericValue(parent, "Stroma + Tumor: H-score"), EPSILON);
        assertEquals(135, model.getNumericValue(parentNew, "Stroma + Tumor: H-score"), EPSILON);
        // Create a new object and demonstrate Allred dependence on a single cell
        PathObject parentAllred = PathObjects.createAnnotationObject(ROIs.createRectangleROI(4000, 4000, 1000, 1000, ImagePlane.getDefaultPlane()));
        ROI newROI = ROIs.createEllipseROI(4500, 4500, 10, 10, ImagePlane.getDefaultPlane());
        for (int i = 0; i < 100; i++) parentAllred.addPathObject(PathObjects.createDetectionObject(newROI, PathClassFactory.getNegative(tumorClass)));
        hierarchy.addPathObject(parentAllred);
        model.refreshEntries();
        assertEquals(0, model.getNumericValue(parentAllred, "Tumor: Allred score"), EPSILON);
        parentAllred.addPathObject(PathObjects.createDetectionObject(newROI, PathClassFactory.getThreePlus(tumorClass)));
        hierarchy.fireHierarchyChangedEvent(parentAllred);
        model.refreshEntries();
        assertEquals(4, model.getNumericValue(parentAllred, "Tumor: Allred score"), EPSILON);
    }
}
Also used : PathClass(qupath.lib.objects.classes.PathClass) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) ObservableMeasurementTableData(qupath.lib.gui.measure.ObservableMeasurementTableData) PathObject(qupath.lib.objects.PathObject) ImageData(qupath.lib.images.ImageData) ROI(qupath.lib.roi.interfaces.ROI) BufferedImage(java.awt.image.BufferedImage) Test(org.junit.jupiter.api.Test)

Example 62 with PathObject

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

the class MoveTool method mouseReleased.

@Override
public void mouseReleased(MouseEvent e) {
    super.mouseReleased(e);
    if (e.isConsumed())
        return;
    var viewer = getViewer();
    RoiEditor editor = viewer.getROIEditor();
    if (editor != null && (editor.hasActiveHandle() || editor.isTranslating())) {
        boolean roiChanged = (editor.isTranslating() && editor.finishTranslation()) || editor.hasActiveHandle();
        editor.resetActiveHandle();
        // if (editor.isTranslating())
        // editor.finishTranslation();
        e.consume();
        PathObject pathObject = viewer.getSelectedObject();
        if (requestParentClipping(e) && pathObject instanceof PathAnnotationObject) {
            ROI roiNew = refineROIByParent(pathObject.getROI());
            ((PathAnnotationObject) pathObject).setROI(roiNew);
        }
        if (pathObject != null && pathObject.hasROI() && pathObject.getROI().isEmpty()) {
            if (pathObject.getParent() != null)
                viewer.getHierarchy().removeObject(pathObject, true);
            viewer.setSelectedObject(null);
        } else {
            PathObjectHierarchy hierarchy = viewer.getHierarchy();
            if (pathObject instanceof TMACoreObject) {
                hierarchy.fireHierarchyChangedEvent(pathObject);
            } else if (pathObject != null) {
                // Handle ROI changes only if required
                if (roiChanged) {
                    var updatedROI = editor.getROI();
                    if (pathObject.getROI() != updatedROI && pathObject instanceof PathROIObject)
                        ((PathROIObject) pathObject).setROI(updatedROI);
                    // PathObject parentPrevious = pathObject.getParent();
                    hierarchy.removeObjectWithoutUpdate(pathObject, true);
                    if (getCurrentParent() == null || !PathPrefs.clipROIsForHierarchyProperty().get() || e.isShiftDown())
                        hierarchy.addPathObject(pathObject);
                    else
                        hierarchy.addPathObjectBelowParent(getCurrentParent(), pathObject, true);
                // PathObject parentNew = pathObject.getParent();
                // if (parentPrevious == parentNew)
                // hierarchy.fireHierarchyChangedEvent(this, parentPrevious);
                // else
                // hierarchy.fireHierarchyChangedEvent(this);
                }
            }
            viewer.setSelectedObject(pathObject);
        }
    }
    // Optionally continue a dragging movement until the canvas comes to a standstill
    if (pDragging != null && requestDynamicDragging && System.currentTimeMillis() - lastDragTimestamp < 100 && (dx * dx + dy * dy > viewer.getDownsampleFactor())) {
        mover = new ViewerMover(viewer);
        mover.startMoving(dx, dy, false);
    } else
        viewer.setDoFasterRepaint(false);
    // Make sure we don't have a previous point (to prevent weird dragging artefacts)
    pDragging = null;
// // If we were translating, stop
// if (editor.isTranslating()) {
// editor.finishTranslation();
// // TODO: Make this more efficient!
// viewer.getPathObjectHierarchy().fireHierarchyChangedEvent();
// return;
// }
}
Also used : PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) RoiEditor(qupath.lib.roi.RoiEditor) TMACoreObject(qupath.lib.objects.TMACoreObject) PathROIObject(qupath.lib.objects.PathROIObject) ROI(qupath.lib.roi.interfaces.ROI)

Example 63 with PathObject

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

the class PathClassifierTools method getAvailableFeatures.

/**
 * Get a set containing the names of all measurements found in the measurement lists of a specified object collection.
 *
 * @param pathObjects
 * @return
 */
public static Set<String> getAvailableFeatures(final Collection<? extends PathObject> pathObjects) {
    Set<String> featureSet = new LinkedHashSet<>();
    // This has a small optimization that takes into consideration the fact that many objects share references to exactly the same MeasurementLists -
    // so by checking the last list that was added, there is no need to bother the set to add the same thing again.
    List<String> lastNames = null;
    for (PathObject pathObject : pathObjects) {
        if (!pathObject.hasMeasurements())
            continue;
        List<String> list = pathObject.getMeasurementList().getMeasurementNames();
        if (lastNames != list)
            featureSet.addAll(list);
        lastNames = list;
    }
    return featureSet;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) PathObject(qupath.lib.objects.PathObject)

Example 64 with PathObject

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

the class PathClassifierTools method runClassifier.

/**
 * Apply a classifier to the detection objects in a hierarchy.
 * @param hierarchy
 * @param classifier
 */
public static void runClassifier(final PathObjectHierarchy hierarchy, final PathObjectClassifier classifier) {
    // Apply classifier to everything
    // If we have a TMA grid, do one core at a time
    long startTime = System.currentTimeMillis();
    TMAGrid tmaGrid = hierarchy.getTMAGrid();
    Collection<PathObject> pathObjects = new ArrayList<>();
    int nClassified = 0;
    // tmaGrid = null;
    if (tmaGrid != null) {
        for (TMACoreObject core : tmaGrid.getTMACoreList()) {
            pathObjects = PathObjectTools.getDescendantObjects(core, pathObjects, PathDetectionObject.class);
            nClassified += classifier.classifyPathObjects(pathObjects);
            pathObjects.clear();
        }
    } else {
        hierarchy.getObjects(pathObjects, PathDetectionObject.class);
        nClassified = classifier.classifyPathObjects(pathObjects);
    }
    long endTime = System.currentTimeMillis();
    logger.info(String.format("Classification time: %.2f seconds", (endTime - startTime) / 1000.));
    // Fire a change event for all detection objects
    if (nClassified > 0)
        hierarchy.fireObjectClassificationsChangedEvent(classifier, hierarchy.getObjects(null, PathDetectionObject.class));
    else
        logger.warn("No objects classified!");
}
Also used : PathDetectionObject(qupath.lib.objects.PathDetectionObject) PathObject(qupath.lib.objects.PathObject) TMACoreObject(qupath.lib.objects.TMACoreObject) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) ArrayList(java.util.ArrayList)

Example 65 with PathObject

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

the class ImageJMacroRunner method runPlugin.

@Override
public boolean runPlugin(final PluginRunner<BufferedImage> runner, final String arg) {
    if (!parseArgument(runner.getImageData(), arg))
        return false;
    if (dialog == null) {
        dialog = new Stage();
        dialog.initOwner(qupath.getStage());
        dialog.setTitle("ImageJ macro runner");
        BorderPane pane = new BorderPane();
        if (arg != null)
            macroText = arg;
        // Create text area
        final TextArea textArea = new TextArea();
        textArea.setPrefRowCount(12);
        textArea.setPrefSize(400, 400);
        textArea.setWrapText(true);
        textArea.setFont(Font.font("Courier"));
        if (macroText != null)
            textArea.setText(macroText);
        BorderPane panelMacro = new BorderPane();
        // panelMacro.setBorder(BorderFactory.createTitledBorder("Macro"));
        panelMacro.setCenter(textArea);
        ParameterPanelFX parameterPanel = new ParameterPanelFX(getParameterList(runner.getImageData()));
        panelMacro.setBottom(parameterPanel.getPane());
        // Create button panel
        Button btnRun = new Button("Run");
        btnRun.setOnAction(e -> {
            macroText = textArea.getText().trim();
            if (macroText.length() == 0)
                return;
            PathObjectHierarchy hierarchy = getHierarchy(runner);
            PathObject pathObject = hierarchy.getSelectionModel().singleSelection() ? hierarchy.getSelectionModel().getSelectedObject() : null;
            if (pathObject instanceof PathAnnotationObject || pathObject instanceof TMACoreObject) {
                SwingUtilities.invokeLater(() -> {
                    runMacro(params, qupath.getViewer().getImageData(), qupath.getViewer().getImageDisplay(), pathObject, macroText);
                });
            } else {
                // DisplayHelpers.showErrorMessage(getClass().getSimpleName(), "Sorry, ImageJ macros can only be run for single selected images");
                // logger.warn("ImageJ macro being run in current thread");
                // runPlugin(runner, arg); // TODO: Consider running in a background thread?
                // Run in a background thread
                Collection<? extends PathObject> parents = getParentObjects(runner);
                if (parents.isEmpty()) {
                    Dialogs.showErrorMessage("ImageJ macro runner", "No annotation or TMA core objects selected!");
                    return;
                }
                List<Runnable> tasks = new ArrayList<>();
                for (PathObject parent : parents) addRunnableTasks(qupath.getViewer().getImageData(), parent, tasks);
                qupath.submitShortTask(() -> runner.runTasks(tasks, true));
            // runner.runTasks(tasks);
            // Runnable r = new Runnable() {
            // public void run() {
            // runPlugin(runner, arg);
            // }
            // };
            // new Thread(r).start();
            }
        });
        Button btnClose = new Button("Close");
        btnClose.setOnAction(e -> dialog.hide());
        GridPane panelButtons = PaneTools.createRowGridControls(btnRun, btnClose);
        pane.setCenter(panelMacro);
        pane.setBottom(panelButtons);
        panelButtons.setPadding(new Insets(5, 0, 0, 0));
        pane.setPadding(new Insets(10, 10, 10, 10));
        dialog.setScene(new Scene(pane));
    }
    dialog.show();
    return true;
}
Also used : PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) BorderPane(javafx.scene.layout.BorderPane) GridPane(javafx.scene.layout.GridPane) Insets(javafx.geometry.Insets) TextArea(javafx.scene.control.TextArea) TMACoreObject(qupath.lib.objects.TMACoreObject) ArrayList(java.util.ArrayList) Scene(javafx.scene.Scene) ParameterPanelFX(qupath.lib.gui.dialogs.ParameterPanelFX) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) Button(javafx.scene.control.Button) Stage(javafx.stage.Stage)

Aggregations

PathObject (qupath.lib.objects.PathObject)182 ArrayList (java.util.ArrayList)84 ROI (qupath.lib.roi.interfaces.ROI)74 PathObjectHierarchy (qupath.lib.objects.hierarchy.PathObjectHierarchy)61 List (java.util.List)48 BufferedImage (java.awt.image.BufferedImage)37 IOException (java.io.IOException)37 PathClass (qupath.lib.objects.classes.PathClass)37 Collectors (java.util.stream.Collectors)35 PathAnnotationObject (qupath.lib.objects.PathAnnotationObject)34 Map (java.util.Map)33 Logger (org.slf4j.Logger)33 LoggerFactory (org.slf4j.LoggerFactory)33 ImageData (qupath.lib.images.ImageData)31 TMACoreObject (qupath.lib.objects.TMACoreObject)31 Collection (java.util.Collection)29 Collections (java.util.Collections)29 HashMap (java.util.HashMap)28 PathObjectTools (qupath.lib.objects.PathObjectTools)26 Arrays (java.util.Arrays)25