Search in sources :

Example 16 with PathClass

use of qupath.lib.objects.classes.PathClass in project qupath by qupath.

the class TileClassificationsToAnnotationsPlugin method getDefaultParameterList.

@Override
public ParameterList getDefaultParameterList(final ImageData<T> imageData) {
    if (!parametersInitialized) {
        Set<PathClass> pathClasses = PathClassifierTools.getRepresentedPathClasses(imageData.getHierarchy(), PathTileObject.class);
        List<PathClass> choices = new ArrayList<>(pathClasses);
        Collections.sort(choices, new Comparator<PathClass>() {

            @Override
            public int compare(PathClass pc1, PathClass pc2) {
                return pc1.getName().compareTo(pc2.getName());
            }
        });
        PathClass allClasses = PathClassFactory.getPathClass("All classes");
        PathClass defaultChoice = allClasses;
        choices.add(0, allClasses);
        // PathClass classTumor = PathClassFactory.getDefaultPathClass(PathClasses.TUMOR); // Tumor is the most likely choice, so default to it if available
        // PathClass defaultChoice = choices.contains(classTumor) ? classTumor : choices.get(0);
        params = new ParameterList();
        params.addChoiceParameter("pathClass", "Choose class", defaultChoice, choices, "Choose PathClass to create annotations from").addBooleanParameter("deleteTiles", "Delete existing child objects", false, "Delete the tiles that were used for creating annotations - further training will not be possible after these are deleted").addBooleanParameter("clearAnnotations", "Clear existing annotations", true, "Remove all existing annotations (often a good idea if they were used to train a classifier, but are no longer needed)").addBooleanParameter("splitAnnotations", "Split new annotations", false, "Split newly-created annotations into distinct regions (rather than have one large, possibly-discontinuous object)");
    // .addDoubleParameter("simplify", "Simplify shapes", 0);
    }
    return params;
}
Also used : PathClass(qupath.lib.objects.classes.PathClass) ArrayList(java.util.ArrayList) ParameterList(qupath.lib.plugins.parameters.ParameterList)

Example 17 with PathClass

use of qupath.lib.objects.classes.PathClass in project qupath by qupath.

the class PathClassPane method promptToAddClass.

/**
 * Prompt to add a new classification.
 * @return true if a new classification was added, false otherwise
 */
boolean promptToAddClass() {
    String input = Dialogs.showInputDialog("Add class", "Class name", "");
    if (input == null || input.trim().isEmpty())
        return false;
    PathClass pathClass = PathClassFactory.getPathClass(input);
    var list = qupath.getAvailablePathClasses();
    if (list.contains(pathClass)) {
        Dialogs.showErrorMessage("Add class", "Class '" + input + "' already exists!");
        return false;
    } else if (input.toLowerCase().equals("null")) {
        Dialogs.showErrorMessage("Add class", "Cannot add a 'null' class, try another name!");
        return false;
    }
    list.add(pathClass);
    listClasses.getSelectionModel().clearAndSelect(listClasses.getItems().size() - 1);
    return true;
}
Also used : PathClass(qupath.lib.objects.classes.PathClass)

Example 18 with PathClass

use of qupath.lib.objects.classes.PathClass in project qupath by qupath.

the class DefaultProject method loadPathClasses.

Collection<PathClass> loadPathClasses() throws IOException {
    var path = Paths.get(ensureDirectoryExists(getClassifiersPath()).toString(), "classes.json");
    if (!Files.isRegularFile(path))
        return Collections.emptyList();
    Gson gson = GsonTools.getInstance();
    try (var reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
        var element = gson.fromJson(reader, JsonObject.class);
        JsonElement pathClassesElement = element.get("pathClasses");
        if (pathClassesElement != null && pathClassesElement.isJsonArray()) {
            JsonArray pathClassesArray = pathClassesElement.getAsJsonArray();
            List<PathClass> pathClasses = new ArrayList<>();
            for (int i = 0; i < pathClassesArray.size(); i++) {
                JsonObject pathClassObject = pathClassesArray.get(i).getAsJsonObject();
                if (pathClassObject.has("name")) {
                    String name = pathClassObject.get("name").getAsString();
                    Integer color = null;
                    if (pathClassObject.has("color") && !pathClassObject.get("color").isJsonNull()) {
                        color = pathClassObject.get("color").getAsInt();
                    }
                    PathClass pathClass = PathClassFactory.getPathClass(name, color);
                    if (color != null)
                        // Make sure we have the color we want
                        pathClass.setColor(color);
                    pathClasses.add(pathClass);
                }
            }
            return pathClasses;
        } else
            return Collections.emptyList();
    }
}
Also used : JsonArray(com.google.gson.JsonArray) PathClass(qupath.lib.objects.classes.PathClass) JsonElement(com.google.gson.JsonElement) ArrayList(java.util.ArrayList) Gson(com.google.gson.Gson) JsonObject(com.google.gson.JsonObject)

Example 19 with PathClass

use of qupath.lib.objects.classes.PathClass in project qupath by qupath.

the class SummaryMeasurementTableCommand method showTable.

/**
 * Show a measurement table for the specified image data.
 * @param imageData the image data
 * @param type the object type to show
 */
public void showTable(ImageData<BufferedImage> imageData, Class<? extends PathObject> type) {
    if (imageData == null) {
        Dialogs.showNoImageError("Show measurement table");
        return;
    }
    final PathObjectHierarchy hierarchy = imageData.getHierarchy();
    ObservableMeasurementTableData model = new ObservableMeasurementTableData();
    model.setImageData(imageData, imageData == null ? Collections.emptyList() : imageData.getHierarchy().getObjects(null, type));
    SplitPane splitPane = new SplitPane();
    HistogramDisplay histogramDisplay = new HistogramDisplay(model, true);
    // table.setTableMenuButtonVisible(true);
    TableView<PathObject> table = new TableView<>();
    table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
    table.getSelectionModel().getSelectedItems().addListener(new ListChangeListener<PathObject>() {

        @Override
        public void onChanged(ListChangeListener.Change<? extends PathObject> c) {
            synchronizeSelectionModelToTable(hierarchy, c, table);
        }
    });
    StringProperty displayedName = new SimpleStringProperty(ServerTools.getDisplayableImageName(imageData.getServer()));
    var title = Bindings.createStringBinding(() -> {
        if (type == null)
            return "Results " + displayedName.get();
        else
            return PathObjectTools.getSuitableName(type, false) + " results - " + displayedName.get();
    }, displayedName);
    // Handle double-click as a way to center on a ROI
    // var enter = new KeyCodeCombination(KeyCode.ENTER);
    table.setRowFactory(params -> {
        var row = new TableRow<PathObject>();
        row.setOnMouseClicked(e -> {
            if (e.getClickCount() == 2) {
                maybeCenterROI(row.getItem());
            }
        });
        // });
        return row;
    });
    // Create columns according to the table model
    // for (int i = 0; i < model.getColumnCount(); i++) {
    // // Add string column
    // if (model.getColumnClass(i).equals(String.class)) {
    // TableColumn<PathObject, String> col = null;
    // col = new TableColumn<>(model.getColumnName(i));
    // col.setCellValueFactory(new Callback<CellDataFeatures<PathObject, String>, ObservableValue<String>>() {
    // public ObservableValue<String> call(CellDataFeatures<PathObject, String> val) {
    // return new SimpleStringProperty(val.getValue().getDisplayedName());
    // }
    // });
    // col.setCellFactory(column -> new BasicTableCell<String>());
    // table.getColumns().add(col);
    // }
    // }
    boolean tmaCoreList = TMACoreObject.class.isAssignableFrom(type);
    // Add TMA core columns, if suitable
    if (tmaCoreList) {
        TableColumn<PathObject, ROI> col = new TableColumn<>("Image");
        col.setCellValueFactory(val -> new SimpleObjectProperty<>(val.getValue().getROI()));
        double maxWidth = maxDimForTMACore;
        double padding = 10;
        col.setCellFactory(column -> new TMACoreTableCell(table, imageData.getServer(), maxWidth, padding));
        col.widthProperty().addListener((v, o, n) -> table.refresh());
        col.setMaxWidth(maxWidth + padding * 2);
        table.getColumns().add(col);
        // While here, make sure we have fewer bins - don't usually have all that many cores
        histogramDisplay.setNumBins(10);
    }
    // Create numeric columns
    for (String columnName : model.getAllNames()) {
        // Add column
        if (model.isStringMeasurement(columnName)) {
            TableColumn<PathObject, String> col = new TableColumn<>(columnName);
            col.setCellValueFactory(column -> model.createStringMeasurement(column.getValue(), column.getTableColumn().getText()));
            col.setCellFactory(column -> new BasicTableCell<>());
            table.getColumns().add(col);
        } else {
            TableColumn<PathObject, Number> col = new TableColumn<>(columnName);
            col.setCellValueFactory(column -> model.createNumericMeasurement(column.getValue(), column.getTableColumn().getText()));
            col.setCellFactory(column -> new NumericTableCell<PathObject>(histogramDisplay));
            table.getColumns().add(col);
        }
    }
    // Set the PathObjects - need to deal with sorting, since a FilteredList won't handle it directly
    SortedList<PathObject> items = new SortedList<>(model.getItems());
    items.comparatorProperty().bind(table.comparatorProperty());
    table.setItems(items);
    List<ButtonBase> buttons = new ArrayList<>();
    ToggleButton btnHistogram = new ToggleButton("Show histograms");
    btnHistogram.selectedProperty().addListener((v, o, n) -> {
        if (n) {
            Pane paneHistograms = histogramDisplay.getPane();
            splitPane.getItems().add(paneHistograms);
        } else if (histogramDisplay != null)
            splitPane.getItems().remove(histogramDisplay.getPane());
    });
    buttons.add(btnHistogram);
    // Button btnScatterplot = new Button("Show scatterplots");
    // btnScatterplot.setOnAction(e -> {
    // SwingUtilities.invokeLater(() -> {
    // JDialog dialog = new ScatterplotDisplay(null, "Scatterplots: " + displayedName, model).getDialog();
    // dialog.setLocationRelativeTo(null);
    // dialog.setVisible(true);
    // });
    // });
    // buttons.add(btnScatterplot);
    Button btnCopy = new Button("Copy to clipboard");
    btnCopy.setOnAction(e -> {
        // TODO: Deal with repetition immediately below...
        Set<String> excludeColumns = new HashSet<>();
        for (TableColumn<?, ?> col : table.getColumns()) {
            if (!col.isVisible())
                excludeColumns.add(col.getText());
        }
        copyTableContentsToClipboard(model, excludeColumns);
    });
    buttons.add(btnCopy);
    Button btnSave = new Button("Save");
    btnSave.setOnAction(e -> {
        Set<String> excludeColumns = new HashSet<>();
        for (TableColumn<?, ?> col : table.getColumns()) {
            if (!col.isVisible())
                excludeColumns.add(col.getText());
        }
        File fileOutput = promptForOutputFile();
        if (fileOutput == null)
            return;
        if (saveTableModel(model, fileOutput, excludeColumns)) {
            WorkflowStep step;
            String includeColumns;
            if (excludeColumns.isEmpty())
                includeColumns = "";
            else {
                List<String> includeColumnList = new ArrayList<>(model.getAllNames());
                includeColumnList.removeAll(excludeColumns);
                includeColumns = ", " + includeColumnList.stream().map(s -> "'" + s + "'").collect(Collectors.joining(", "));
            }
            String path = qupath.getProject() == null ? fileOutput.toURI().getPath() : fileOutput.getParentFile().toURI().getPath();
            if (type == TMACoreObject.class) {
                step = new DefaultScriptableWorkflowStep("Save TMA measurements", String.format("saveTMAMeasurements('%s'%s)", path, includeColumns));
            } else if (type == PathAnnotationObject.class) {
                step = new DefaultScriptableWorkflowStep("Save annotation measurements", String.format("saveAnnotationMeasurements('%s\'%s)", path, includeColumns));
            } else if (type == PathDetectionObject.class) {
                step = new DefaultScriptableWorkflowStep("Save detection measurements", String.format("saveDetectionMeasurements('%s'%s)", path, includeColumns));
            } else {
                step = new DefaultScriptableWorkflowStep("Save measurements", String.format("saveMeasurements('%s', %s%s)", path, type == null ? null : type.getName(), includeColumns));
            }
            imageData.getHistoryWorkflow().addStep(step);
        }
    });
    buttons.add(btnSave);
    Stage frame = new Stage();
    frame.initOwner(qupath.getStage());
    frame.titleProperty().bind(title);
    BorderPane paneTable = new BorderPane();
    paneTable.setCenter(table);
    // Add text field to filter visible columns
    TextField tfColumnFilter = new TextField();
    GridPane paneFilter = new GridPane();
    paneFilter.add(new Label("Column filter"), 0, 0);
    paneFilter.add(tfColumnFilter, 1, 0);
    GridPane.setHgrow(tfColumnFilter, Priority.ALWAYS);
    paneFilter.setHgap(5);
    if (tmaCoreList) {
        CheckBox cbHideMissing = new CheckBox("Hide missing cores");
        paneFilter.add(cbHideMissing, 2, 0);
        cbHideMissing.selectedProperty().addListener((v, o, n) -> {
            if (n) {
                model.setPredicate(p -> (!(p instanceof TMACoreObject)) || !((TMACoreObject) p).isMissing());
            } else
                model.setPredicate(null);
        });
        cbHideMissing.setSelected(true);
    }
    paneFilter.setPadding(new Insets(2, 5, 2, 5));
    paneTable.setBottom(paneFilter);
    StringProperty columnFilter = tfColumnFilter.textProperty();
    columnFilter.addListener((v, o, n) -> {
        String val = n.toLowerCase().trim();
        if (val.isEmpty()) {
            for (TableColumn<?, ?> col : table.getColumns()) {
                if (!col.isVisible())
                    col.setVisible(true);
            }
            return;
        }
        for (TableColumn<?, ?> col : table.getColumns()) {
            col.setVisible(col.getText().toLowerCase().contains(val));
        }
    });
    BorderPane pane = new BorderPane();
    // pane.setCenter(table);
    splitPane.getItems().add(paneTable);
    pane.setCenter(splitPane);
    GridPane panelButtons = PaneTools.createColumnGridControls(buttons.toArray(new ButtonBase[0]));
    pane.setBottom(panelButtons);
    PathObjectHierarchyListener listener = new PathObjectHierarchyListener() {

        @Override
        public void hierarchyChanged(PathObjectHierarchyEvent event) {
            if (event.isChanging())
                return;
            if (!Platform.isFxApplicationThread()) {
                Platform.runLater(() -> hierarchyChanged(event));
                return;
            }
            if (imageData != null)
                displayedName.set(ServerTools.getDisplayableImageName(imageData.getServer()));
            model.refreshEntries();
            table.refresh();
            if (histogramDisplay != null)
                histogramDisplay.refreshHistogram();
        }
    };
    QuPathViewer viewer = qupath.getViewer();
    TableViewerListener tableViewerListener = new TableViewerListener(viewer, table);
    frame.setOnShowing(e -> {
        hierarchy.addPathObjectListener(listener);
        viewer.addViewerListener(tableViewerListener);
    });
    frame.setOnHiding(e -> {
        hierarchy.removePathObjectListener(listener);
        viewer.removeViewerListener(tableViewerListener);
    });
    Scene scene = new Scene(pane, 600, 500);
    frame.setScene(scene);
    frame.show();
    // Add ability to remove entries from table
    ContextMenu menu = new ContextMenu();
    Menu menuLimitClasses = new Menu("Show classes");
    menu.setOnShowing(e -> {
        Set<PathClass> representedClasses = model.getBackingListEntries().stream().map(p -> p.getPathClass() == null ? null : p.getPathClass().getBaseClass()).collect(Collectors.toCollection(() -> new HashSet<>()));
        representedClasses.remove(null);
        if (representedClasses.isEmpty()) {
            menuLimitClasses.setVisible(false);
        } else {
            menuLimitClasses.setVisible(true);
        }
        menuLimitClasses.getItems().clear();
        List<PathClass> sortedClasses = new ArrayList<>(representedClasses);
        Collections.sort(sortedClasses);
        MenuItem miClass = new MenuItem("All");
        miClass.setOnAction(e2 -> {
            model.setPredicate(null);
            histogramDisplay.refreshHistogram();
        });
        menuLimitClasses.getItems().add(miClass);
        for (PathClass pathClass : sortedClasses) {
            miClass = new MenuItem(pathClass.getName());
            miClass.setOnAction(e2 -> {
                model.setPredicate(p -> pathClass.isAncestorOf(p.getPathClass()));
                histogramDisplay.refreshHistogram();
            });
            menuLimitClasses.getItems().add(miClass);
        }
    });
    if (type != TMACoreObject.class) {
        menu.getItems().add(menuLimitClasses);
        table.setContextMenu(menu);
    }
}
Also used : Button(javafx.scene.control.Button) Pos(javafx.geometry.Pos) Arrays(java.util.Arrays) ImageServer(qupath.lib.images.servers.ImageServer) ServerTools(qupath.lib.images.servers.ServerTools) LoggerFactory(org.slf4j.LoggerFactory) HistogramDisplay(qupath.lib.gui.charts.HistogramDisplay) PathTableData(qupath.lib.gui.measure.PathTableData) MultipleSelectionModel(javafx.scene.control.MultipleSelectionModel) ObservableMeasurementTableData(qupath.lib.gui.measure.ObservableMeasurementTableData) ListChangeListener(javafx.collections.ListChangeListener) ContextMenu(javafx.scene.control.ContextMenu) PathObjectHierarchyEvent(qupath.lib.objects.hierarchy.events.PathObjectHierarchyEvent) Map(java.util.Map) TableView(javafx.scene.control.TableView) QuPathGUI(qupath.lib.gui.QuPathGUI) SortedList(javafx.collections.transformation.SortedList) Pane(javafx.scene.layout.Pane) Shape(java.awt.Shape) PrintWriter(java.io.PrintWriter) SplitPane(javafx.scene.control.SplitPane) TextField(javafx.scene.control.TextField) MenuItem(javafx.scene.control.MenuItem) BufferedImage(java.awt.image.BufferedImage) ButtonBase(javafx.scene.control.ButtonBase) Collection(java.util.Collection) Set(java.util.Set) Canvas(javafx.scene.canvas.Canvas) WorkflowStep(qupath.lib.plugins.workflow.WorkflowStep) QuPathViewerListener(qupath.lib.gui.viewer.QuPathViewerListener) Collectors(java.util.stream.Collectors) StandardCharsets(java.nio.charset.StandardCharsets) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathDetectionObject(qupath.lib.objects.PathDetectionObject) PathObject(qupath.lib.objects.PathObject) Platform(javafx.application.Platform) QuPathViewer(qupath.lib.gui.viewer.QuPathViewer) Priority(javafx.scene.layout.Priority) List(java.util.List) DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) ToggleButton(javafx.scene.control.ToggleButton) Clipboard(javafx.scene.input.Clipboard) GuiTools(qupath.lib.gui.tools.GuiTools) ClipboardContent(javafx.scene.input.ClipboardContent) BorderPane(javafx.scene.layout.BorderPane) StringProperty(javafx.beans.property.StringProperty) TableViewSelectionModel(javafx.scene.control.TableView.TableViewSelectionModel) Scene(javafx.scene.Scene) SimpleStringProperty(javafx.beans.property.SimpleStringProperty) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) Bindings(javafx.beans.binding.Bindings) ArrayList(java.util.ArrayList) TableColumn(javafx.scene.control.TableColumn) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) Dialogs(qupath.lib.gui.dialogs.Dialogs) TableCell(javafx.scene.control.TableCell) Insets(javafx.geometry.Insets) GridPane(javafx.scene.layout.GridPane) ImageData(qupath.lib.images.ImageData) Logger(org.slf4j.Logger) Label(javafx.scene.control.Label) GeneralTools(qupath.lib.common.GeneralTools) RegionRequest(qupath.lib.regions.RegionRequest) TableRow(javafx.scene.control.TableRow) CheckBox(javafx.scene.control.CheckBox) PathClass(qupath.lib.objects.classes.PathClass) IOException(java.io.IOException) TMACoreObject(qupath.lib.objects.TMACoreObject) PathObjectSelectionModel(qupath.lib.objects.hierarchy.events.PathObjectSelectionModel) File(java.io.File) PathObjectTools(qupath.lib.objects.PathObjectTools) Menu(javafx.scene.control.Menu) ROI(qupath.lib.roi.interfaces.ROI) SelectionMode(javafx.scene.control.SelectionMode) Stage(javafx.stage.Stage) SimpleObjectProperty(javafx.beans.property.SimpleObjectProperty) SwingFXUtils(javafx.embed.swing.SwingFXUtils) PathObjectHierarchyListener(qupath.lib.objects.hierarchy.events.PathObjectHierarchyListener) Collections(java.util.Collections) Image(javafx.scene.image.Image) PathPrefs(qupath.lib.gui.prefs.PathPrefs) ContentDisplay(javafx.scene.control.ContentDisplay) PaneTools(qupath.lib.gui.tools.PaneTools) WorkflowStep(qupath.lib.plugins.workflow.WorkflowStep) DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) SortedList(javafx.collections.transformation.SortedList) ArrayList(java.util.ArrayList) Label(javafx.scene.control.Label) PathObjectHierarchyEvent(qupath.lib.objects.hierarchy.events.PathObjectHierarchyEvent) SplitPane(javafx.scene.control.SplitPane) ListChangeListener(javafx.collections.ListChangeListener) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) Button(javafx.scene.control.Button) ToggleButton(javafx.scene.control.ToggleButton) Stage(javafx.stage.Stage) TextField(javafx.scene.control.TextField) TableView(javafx.scene.control.TableView) HashSet(java.util.HashSet) QuPathViewer(qupath.lib.gui.viewer.QuPathViewer) GridPane(javafx.scene.layout.GridPane) TMACoreObject(qupath.lib.objects.TMACoreObject) SimpleStringProperty(javafx.beans.property.SimpleStringProperty) Scene(javafx.scene.Scene) ROI(qupath.lib.roi.interfaces.ROI) TableColumn(javafx.scene.control.TableColumn) Pane(javafx.scene.layout.Pane) SplitPane(javafx.scene.control.SplitPane) BorderPane(javafx.scene.layout.BorderPane) GridPane(javafx.scene.layout.GridPane) HistogramDisplay(qupath.lib.gui.charts.HistogramDisplay) PathObject(qupath.lib.objects.PathObject) CheckBox(javafx.scene.control.CheckBox) TableRow(javafx.scene.control.TableRow) File(java.io.File) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) BorderPane(javafx.scene.layout.BorderPane) Insets(javafx.geometry.Insets) PathObjectHierarchyListener(qupath.lib.objects.hierarchy.events.PathObjectHierarchyListener) StringProperty(javafx.beans.property.StringProperty) SimpleStringProperty(javafx.beans.property.SimpleStringProperty) ContextMenu(javafx.scene.control.ContextMenu) DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) PathClass(qupath.lib.objects.classes.PathClass) ContextMenu(javafx.scene.control.ContextMenu) Menu(javafx.scene.control.Menu) ToggleButton(javafx.scene.control.ToggleButton) MenuItem(javafx.scene.control.MenuItem) ButtonBase(javafx.scene.control.ButtonBase) ObservableMeasurementTableData(qupath.lib.gui.measure.ObservableMeasurementTableData)

Example 20 with PathClass

use of qupath.lib.objects.classes.PathClass 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)

Aggregations

PathClass (qupath.lib.objects.classes.PathClass)66 ArrayList (java.util.ArrayList)42 PathObject (qupath.lib.objects.PathObject)34 List (java.util.List)29 Map (java.util.Map)25 IOException (java.io.IOException)21 Logger (org.slf4j.Logger)20 LoggerFactory (org.slf4j.LoggerFactory)20 Collections (java.util.Collections)17 Collectors (java.util.stream.Collectors)17 BufferedImage (java.awt.image.BufferedImage)16 LinkedHashMap (java.util.LinkedHashMap)16 ROI (qupath.lib.roi.interfaces.ROI)16 HashMap (java.util.HashMap)15 ImageData (qupath.lib.images.ImageData)15 PathClassFactory (qupath.lib.objects.classes.PathClassFactory)15 PathObjectHierarchy (qupath.lib.objects.hierarchy.PathObjectHierarchy)15 ParameterList (qupath.lib.plugins.parameters.ParameterList)15 Collection (java.util.Collection)14 TreeMap (java.util.TreeMap)11