Search in sources :

Example 86 with PathObject

use of qupath.lib.objects.PathObject 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 87 with PathObject

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

the class AnnotationPane method synchronizeHierarchySelectionToListSelection.

/**
 * Update the selected objects in the hierarchy to match those in the list,
 * unless selection changes should be suppressed.
 */
void synchronizeHierarchySelectionToListSelection() {
    if (hierarchy == null || suppressSelectionChanges)
        return;
    suppressSelectionChanges = true;
    Set<PathObject> selectedSet = new HashSet<>(listAnnotations.getSelectionModel().getSelectedItems());
    PathObject selectedObject = listAnnotations.getSelectionModel().getSelectedItem();
    if (!selectedSet.contains(selectedObject))
        selectedObject = null;
    hierarchy.getSelectionModel().setSelectedObjects(selectedSet, selectedObject);
    suppressSelectionChanges = false;
}
Also used : PathObject(qupath.lib.objects.PathObject) HashSet(java.util.HashSet)

Example 88 with PathObject

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

the class AnnotationPane method setImageData.

void setImageData(ImageData<BufferedImage> imageData) {
    if (this.imageData == imageData)
        return;
    // Deal with listeners for the current ImageData
    if (this.hierarchy != null) {
        hierarchy.removePathObjectListener(this);
        hierarchy.getSelectionModel().removePathObjectSelectionListener(this);
    }
    this.imageData = imageData;
    if (this.imageData != null) {
        hierarchy = imageData.getHierarchy();
        hierarchy.getSelectionModel().addPathObjectSelectionListener(this);
        hierarchy.addPathObjectListener(this);
        PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
        listAnnotations.getItems().setAll(hierarchy.getAnnotationObjects());
        hierarchy.getSelectionModel().setSelectedObject(selected);
    } else {
        listAnnotations.getItems().clear();
    }
    hasImageData.set(this.imageData != null);
    pathClassPane.refresh();
}
Also used : PathObject(qupath.lib.objects.PathObject)

Example 89 with PathObject

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

the class ClassifierBuilderPane method completeClassification.

private void completeClassification(final PathObjectHierarchy hierarchy, final Collection<PathObject> classifiedObjects, final Collection<PathObject> originalObjects, final Map<PathClass, List<PathObject>> mapTest, final boolean testOnTrainingData) {
    if (!Platform.isFxApplicationThread())
        Platform.runLater(() -> completeClassification(hierarchy, classifiedObjects, originalObjects, mapTest, testOnTrainingData));
    else {
        // Test the classifications of the test set... which may or may not be the same as the training set
        if (mapTest != null) {
            int nCorrect = 0;
            List<PathClass> pathClasses = new ArrayList<>(mapTest.keySet());
            Collections.sort(pathClasses);
            ConfusionMatrix<PathClass> confusion = new ConfusionMatrix<>(pathClasses);
            int nCorrectTumor = 0;
            // int nWrong = 0;
            int nUnclassified = 0;
            int n = 0;
            PathClass tumorClass = PathClassFactory.getPathClass(StandardPathClasses.TUMOR);
            // If we have multiple classes, it can be beneficial to see how tumor vs. everything else performs
            // Create a tumor vs. everything else classifier
            boolean multiclassContainsTumor = mapTest.containsKey(tumorClass) && mapTest.size() > 2;
            for (Entry<PathClass, List<PathObject>> entry : mapTest.entrySet()) {
                PathClass pathClass = entry.getKey();
                boolean isTumor = pathClass.equals(tumorClass);
                for (PathObject testObject : entry.getValue()) {
                    PathClass tempClass = testObject.getPathClass();
                    if (tempClass == null) {
                        nUnclassified++;
                        n++;
                        continue;
                    }
                    // We've probably applied an intensity classifier by now
                    PathClass resultClass = tempClass.getBaseClass();
                    confusion.registerClassification(pathClass, resultClass);
                    if (resultClass.equals(pathClass))
                        nCorrect++;
                    if (multiclassContainsTumor && (isTumor && pathClass.equals(resultClass) || (!isTumor && !resultClass.equals(tumorClass))))
                        nCorrectTumor++;
                    n++;
                }
            }
            // Log the results
            if (testOnTrainingData) {
                logger.info(String.format("Percentage of correctly classified objects in TRAINING set: %.2f%% (n=%d)", nCorrect * 100. / n, n));
                logger.warn("It is *strongly* advised not to report accuracies based on testing using the training set!");
            } else {
                logger.info(String.format("Percentage of correctly classified objects in test set: %.2f%% (n=%d)", nCorrect * 100. / n, n));
                if (multiclassContainsTumor)
                    logger.info(String.format("Percentage of correctly classified objects in test set (Tumor vs. everything else): %.2f%% (n=%d)", nCorrectTumor * 100. / n, n));
            }
            if (nUnclassified > 0)
                logger.info(String.format("Number of unclassified objects in the test set: %d (%.2f%%)", nUnclassified, nUnclassified * 100. / n));
            logger.info("Confusion matrix\n" + confusion.toString());
            // Only interested in changes from now
            hierarchyChanged = false;
        }
        progressIndicator.setVisible(false);
        // Update the classification of any proxy objects
        int nChanged = classifiedObjects.parallelStream().mapToInt(p -> {
            if (p instanceof PathObjectClassificationProxy && ((PathObjectClassificationProxy) p).updateObject())
                return 1;
            else
                return 0;
        }).sum();
        if (classifiedObjects != originalObjects)
            logger.info("Number of reclassified objects: {} of {}", nChanged, classifiedObjects.size());
        // Update displayed list - names may have changed - and classifier summary
        updateClassifierSummary(null);
        btnSaveClassifier.setDisable(!classifier.isValid());
        hierarchy.fireObjectClassificationsChangedEvent(this, originalObjects);
        lastClassifierCompleted = classifier;
        updatingClassification = false;
    }
}
Also used : Button(javafx.scene.control.Button) RunSavedClassifierWorkflowStep(qupath.lib.plugins.workflow.RunSavedClassifierWorkflowStep) Arrays(java.util.Arrays) BufferedInputStream(java.io.BufferedInputStream) ListCell(javafx.scene.control.ListCell) HierarchyEventType(qupath.lib.objects.hierarchy.events.PathObjectHierarchyEvent.HierarchyEventType) ObjectInputStream(java.io.ObjectInputStream) LoggerFactory(org.slf4j.LoggerFactory) Random(java.util.Random) VBox(javafx.scene.layout.VBox) Task(javafx.concurrent.Task) ParameterList(qupath.lib.plugins.parameters.ParameterList) ReadOnlyObjectWrapper(javafx.beans.property.ReadOnlyObjectWrapper) ComboBox(javafx.scene.control.ComboBox) ContextMenu(javafx.scene.control.ContextMenu) PathObjectHierarchyEvent(qupath.lib.objects.hierarchy.events.PathObjectHierarchyEvent) Map(java.util.Map) StandardPathClasses(qupath.lib.objects.classes.PathClassFactory.StandardPathClasses) Parameterizable(qupath.lib.plugins.parameters.Parameterizable) TableView(javafx.scene.control.TableView) QuPathGUI(qupath.lib.gui.QuPathGUI) Pane(javafx.scene.layout.Pane) PrintWriter(java.io.PrintWriter) MenuItem(javafx.scene.control.MenuItem) BufferedImage(java.awt.image.BufferedImage) Collection(java.util.Collection) Set(java.util.Set) Collectors(java.util.stream.Collectors) FileNotFoundException(java.io.FileNotFoundException) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) Platform(javafx.application.Platform) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) Priority(javafx.scene.layout.Priority) List(java.util.List) Project(qupath.lib.projects.Project) ToggleButton(javafx.scene.control.ToggleButton) PathObjectClassifier(qupath.lib.classifiers.PathObjectClassifier) Entry(java.util.Map.Entry) BorderPane(javafx.scene.layout.BorderPane) Scene(javafx.scene.Scene) ListView(javafx.scene.control.ListView) TextArea(javafx.scene.control.TextArea) PathClassFactory(qupath.lib.objects.classes.PathClassFactory) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) TreeSet(java.util.TreeSet) BufferedOutputStream(java.io.BufferedOutputStream) ArrayList(java.util.ArrayList) TableColumn(javafx.scene.control.TableColumn) LinkedHashMap(java.util.LinkedHashMap) Dialogs(qupath.lib.gui.dialogs.Dialogs) Insets(javafx.geometry.Insets) ProgressBar(javafx.scene.control.ProgressBar) Normalization(qupath.lib.classifiers.Normalization) ObjectOutputStream(java.io.ObjectOutputStream) SplitType(qupath.process.gui.ml.legacy.PathClassificationLabellingHelper.SplitType) Callback(javafx.util.Callback) Tooltip(javafx.scene.control.Tooltip) GridPane(javafx.scene.layout.GridPane) ImageData(qupath.lib.images.ImageData) ProgressIndicator(javafx.scene.control.ProgressIndicator) PathClassifierTools(qupath.lib.classifiers.PathClassifierTools) Modality(javafx.stage.Modality) Logger(org.slf4j.Logger) Label(javafx.scene.control.Label) TitledPane(javafx.scene.control.TitledPane) Iterator(java.util.Iterator) ProjectImageEntry(qupath.lib.projects.ProjectImageEntry) PathClass(qupath.lib.objects.classes.PathClass) FileOutputStream(java.io.FileOutputStream) IOException(java.io.IOException) FileInputStream(java.io.FileInputStream) File(java.io.File) PathObjectTools(qupath.lib.objects.PathObjectTools) Cursor(javafx.scene.Cursor) ROI(qupath.lib.roi.interfaces.ROI) SelectionMode(javafx.scene.control.SelectionMode) TreeMap(java.util.TreeMap) Stage(javafx.stage.Stage) ParameterPanelFX(qupath.lib.gui.dialogs.ParameterPanelFX) ObservableValue(javafx.beans.value.ObservableValue) PathObjectHierarchyListener(qupath.lib.objects.hierarchy.events.PathObjectHierarchyListener) ChangeListener(javafx.beans.value.ChangeListener) Collections(java.util.Collections) PathClass(qupath.lib.objects.classes.PathClass) PathObject(qupath.lib.objects.PathObject) ArrayList(java.util.ArrayList) ParameterList(qupath.lib.plugins.parameters.ParameterList) List(java.util.List) ArrayList(java.util.ArrayList)

Example 90 with PathObject

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

the class ClassifierBuilderPane method showRetainedTrainingMap.

void showRetainedTrainingMap(final RetainedTrainingObjects retainedObjects) {
    Map<String, Map<PathClass, List<PathObject>>> map = retainedObjects.getMap();
    // Determine columns
    Set<PathClass> pathClasses = new TreeSet<>();
    for (Map<PathClass, List<PathObject>> temp : map.values()) {
        pathClasses.addAll(temp.keySet());
    }
    // Don't show a badly-formed table with nothing in it...
    if (pathClasses.isEmpty()) {
        Dialogs.showMessageDialog("Training objects", "No training objects selected!");
        return;
    }
    // Set up table
    TableView<String> table = new TableView<>();
    table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
    table.getItems().setAll(map.keySet());
    Collections.sort(table.getItems());
    // Create columns
    TableColumn<String, String> colName = new TableColumn<>("Image");
    colName.setCellValueFactory(column -> new ReadOnlyObjectWrapper<>(column.getValue()));
    // colName.setCellValueFactory(column -> new ReadOnlyObjectWrapper<>(ServerTools.getDefaultShortServerName(column.getValue())));
    colName.setPrefWidth(240);
    table.getColumns().add(colName);
    int nColWidth = 80;
    for (PathClass pathClass : pathClasses) {
        TableColumn<String, Integer> col = new TableColumn<>(pathClass.getName());
        col.setCellValueFactory(column -> {
            if (map.get(column.getValue()).get(pathClass) == null)
                return new ReadOnlyObjectWrapper<Integer>(0);
            else
                return new ReadOnlyObjectWrapper<Integer>(map.get(column.getValue()).get(pathClass).size());
        });
        col.setPrefWidth(nColWidth);
        table.getColumns().add(col);
    }
    table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
    // Show
    Stage dialog = new Stage();
    dialog.initOwner(qupath.getStage());
    dialog.setTitle("Training objects");
    dialog.setScene(new Scene(table));
    dialog.showAndWait();
}
Also used : Scene(javafx.scene.Scene) TableColumn(javafx.scene.control.TableColumn) PathClass(qupath.lib.objects.classes.PathClass) PathObject(qupath.lib.objects.PathObject) TreeSet(java.util.TreeSet) Stage(javafx.stage.Stage) ParameterList(qupath.lib.plugins.parameters.ParameterList) List(java.util.List) ArrayList(java.util.ArrayList) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) TreeMap(java.util.TreeMap) TableView(javafx.scene.control.TableView)

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