Search in sources :

Example 16 with PathObject

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

the class TMACommands method promptToDeleteTMAGridRowOrColumn.

private static boolean promptToDeleteTMAGridRowOrColumn(ImageData<?> imageData, TMARemoveType type) {
    String typeString = type.toString();
    String title = "Delete TMA " + typeString;
    boolean removeRow = type == TMARemoveType.ROW;
    if (imageData == null) {
        Dialogs.showNoImageError(title);
        return false;
    }
    if (imageData.getHierarchy().getTMAGrid() == null) {
        Dialogs.showErrorMessage(title, "No image with dearrayed TMA cores selected!");
        return false;
    }
    PathObjectHierarchy hierarchy = imageData.getHierarchy();
    PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
    TMACoreObject selectedCore = null;
    if (selected != null)
        selectedCore = PathObjectTools.getAncestorTMACore(selected);
    // Try to identify the row/column that we want
    TMAGrid grid = hierarchy.getTMAGrid();
    int row = -1;
    int col = -1;
    if (selectedCore != null) {
        for (int y = 0; y < grid.getGridHeight(); y++) {
            for (int x = 0; x < grid.getGridWidth(); x++) {
                if (grid.getTMACore(y, x) == selectedCore) {
                    row = y;
                    col = x;
                    break;
                }
            }
        }
    }
    // We need a selected core to know what to remove
    if (row < 0 || col < 0) {
        Dialogs.showErrorMessage(title, "Please select a TMA core to indicate which " + typeString + " to remove");
        return false;
    }
    // Check we have enough rows/columns - if not, this is just a clear operation
    if ((removeRow && grid.getGridHeight() <= 1) || (!removeRow && grid.getGridWidth() <= 1)) {
        if (Dialogs.showConfirmDialog(title, "Are you sure you want to delete the entire TMA grid?"))
            hierarchy.setTMAGrid(null);
        return false;
    }
    // Confirm the removal - add 1 due to 'base 0' probably not being expected by most users...
    int num = removeRow ? row : col;
    if (!Dialogs.showConfirmDialog(title, "Are you sure you want to delete " + typeString + " " + (num + 1) + " from TMA grid?"))
        return false;
    // Create a new grid
    List<TMACoreObject> coresNew = new ArrayList<>();
    for (int r = 0; r < grid.getGridHeight(); r++) {
        if (removeRow && row == r)
            continue;
        for (int c = 0; c < grid.getGridWidth(); c++) {
            if (!removeRow && col == c)
                continue;
            coresNew.add(grid.getTMACore(r, c));
        }
    }
    int newWidth = removeRow ? grid.getGridWidth() : grid.getGridWidth() - 1;
    TMAGrid gridNew = DefaultTMAGrid.create(coresNew, newWidth);
    hierarchy.setTMAGrid(gridNew);
    hierarchy.getSelectionModel().clearSelection();
    // Request new labels
    promptToRelabelTMAGrid(imageData);
    return true;
}
Also used : PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) PathObject(qupath.lib.objects.PathObject) TMACoreObject(qupath.lib.objects.TMACoreObject) DefaultTMAGrid(qupath.lib.objects.hierarchy.DefaultTMAGrid) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) ArrayList(java.util.ArrayList)

Example 17 with PathObject

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

the class Commands method promptToExportImageRegion.

/**
 * Prompt to export the current image region selected in the viewer.
 * @param viewer the viewer containing the image to export
 * @param renderedImage if true, export the rendered (RGB) image rather than original pixel values
 */
public static void promptToExportImageRegion(QuPathViewer viewer, boolean renderedImage) {
    if (viewer == null || viewer.getServer() == null) {
        Dialogs.showErrorMessage("Export image region", "No viewer & image selected!");
        return;
    }
    ImageServer<BufferedImage> server = viewer.getServer();
    if (renderedImage)
        server = RenderedImageServer.createRenderedServer(viewer);
    PathObject pathObject = viewer.getSelectedObject();
    ROI roi = pathObject == null ? null : pathObject.getROI();
    double regionWidth = roi == null ? server.getWidth() : roi.getBoundsWidth();
    double regionHeight = roi == null ? server.getHeight() : roi.getBoundsHeight();
    // Create a dialog
    GridPane pane = new GridPane();
    int row = 0;
    pane.add(new Label("Export format"), 0, row);
    ComboBox<ImageWriter<BufferedImage>> comboImageType = new ComboBox<>();
    Function<ImageWriter<BufferedImage>, String> fun = (ImageWriter<BufferedImage> writer) -> writer.getName();
    comboImageType.setCellFactory(p -> GuiTools.createCustomListCell(fun));
    comboImageType.setButtonCell(GuiTools.createCustomListCell(fun));
    var writers = ImageWriterTools.getCompatibleWriters(server, null);
    comboImageType.getItems().setAll(writers);
    comboImageType.setTooltip(new Tooltip("Choose export image format"));
    if (writers.contains(lastWriter))
        comboImageType.getSelectionModel().select(lastWriter);
    else
        comboImageType.getSelectionModel().selectFirst();
    comboImageType.setMaxWidth(Double.MAX_VALUE);
    GridPane.setHgrow(comboImageType, Priority.ALWAYS);
    pane.add(comboImageType, 1, row++);
    TextArea textArea = new TextArea();
    textArea.setPrefRowCount(2);
    textArea.setEditable(false);
    textArea.setWrapText(true);
    // textArea.setPadding(new Insets(15, 0, 0, 0));
    comboImageType.setOnAction(e -> textArea.setText(((ImageWriter<BufferedImage>) comboImageType.getValue()).getDetails()));
    textArea.setText(((ImageWriter<BufferedImage>) comboImageType.getValue()).getDetails());
    pane.add(textArea, 0, row++, 2, 1);
    var label = new Label("Downsample factor");
    pane.add(label, 0, row);
    TextField tfDownsample = new TextField();
    label.setLabelFor(tfDownsample);
    pane.add(tfDownsample, 1, row++);
    tfDownsample.setTooltip(new Tooltip("Amount to scale down image - choose 1 to export at full resolution (note: for large images this may not succeed for memory reasons)"));
    ObservableDoubleValue downsample = Bindings.createDoubleBinding(() -> {
        try {
            return Double.parseDouble(tfDownsample.getText());
        } catch (NumberFormatException e) {
            return Double.NaN;
        }
    }, tfDownsample.textProperty());
    // Define a sensible limit for non-pyramidal images
    long maxPixels = 10000 * 10000;
    Label labelSize = new Label();
    labelSize.setMinWidth(400);
    labelSize.setTextAlignment(TextAlignment.CENTER);
    labelSize.setContentDisplay(ContentDisplay.CENTER);
    labelSize.setAlignment(Pos.CENTER);
    labelSize.setMaxWidth(Double.MAX_VALUE);
    labelSize.setTooltip(new Tooltip("Estimated size of exported image"));
    pane.add(labelSize, 0, row++, 2, 1);
    labelSize.textProperty().bind(Bindings.createStringBinding(() -> {
        if (!Double.isFinite(downsample.get())) {
            labelSize.setStyle("-fx-text-fill: red;");
            return "Invalid downsample value!  Must be >= 1";
        } else {
            long w = (long) (regionWidth / downsample.get() + 0.5);
            long h = (long) (regionHeight / downsample.get() + 0.5);
            String warning = "";
            var writer = comboImageType.getSelectionModel().getSelectedItem();
            boolean supportsPyramid = writer == null ? false : writer.supportsPyramidal();
            if (!supportsPyramid && w * h > maxPixels) {
                labelSize.setStyle("-fx-text-fill: red;");
                warning = " (too big!)";
            } else if (w < 5 || h < 5) {
                labelSize.setStyle("-fx-text-fill: red;");
                warning = " (too small!)";
            } else
                labelSize.setStyle(null);
            return String.format("Output image size: %d x %d pixels%s", w, h, warning);
        }
    }, downsample, comboImageType.getSelectionModel().selectedIndexProperty()));
    tfDownsample.setText(Double.toString(exportDownsample.get()));
    PaneTools.setMaxWidth(Double.MAX_VALUE, labelSize, textArea, tfDownsample, comboImageType);
    PaneTools.setHGrowPriority(Priority.ALWAYS, labelSize, textArea, tfDownsample, comboImageType);
    pane.setVgap(5);
    pane.setHgap(5);
    if (!Dialogs.showConfirmDialog("Export image region", pane))
        return;
    var writer = comboImageType.getSelectionModel().getSelectedItem();
    boolean supportsPyramid = writer == null ? false : writer.supportsPyramidal();
    int w = (int) (regionWidth / downsample.get() + 0.5);
    int h = (int) (regionHeight / downsample.get() + 0.5);
    if (!supportsPyramid && w * h > maxPixels) {
        Dialogs.showErrorNotification("Export image region", "Requested export region too large - try selecting a smaller region, or applying a higher downsample factor");
        return;
    }
    if (downsample.get() < 1 || !Double.isFinite(downsample.get())) {
        Dialogs.showErrorMessage("Export image region", "Downsample factor must be >= 1!");
        return;
    }
    exportDownsample.set(downsample.get());
    // Now that we know the output, we can create a new server to ensure it is downsampled as the necessary resolution
    if (renderedImage && downsample.get() != server.getDownsampleForResolution(0))
        server = new RenderedImageServer.Builder(viewer).downsamples(downsample.get()).build();
    // selectedImageType.set(comboImageType.getSelectionModel().getSelectedItem());
    // Create RegionRequest
    RegionRequest request = null;
    if (pathObject != null && pathObject.hasROI())
        request = RegionRequest.createInstance(server.getPath(), exportDownsample.get(), roi);
    // Create a sensible default file name, and prompt for the actual name
    String ext = writer.getDefaultExtension();
    String writerName = writer.getName();
    String defaultName = GeneralTools.getNameWithoutExtension(new File(ServerTools.getDisplayableImageName(server)));
    if (roi != null) {
        defaultName = String.format("%s (%s, x=%d, y=%d, w=%d, h=%d)", defaultName, GeneralTools.formatNumber(request.getDownsample(), 2), request.getX(), request.getY(), request.getWidth(), request.getHeight());
    }
    File fileOutput = Dialogs.promptToSaveFile("Export image region", null, defaultName, writerName, ext);
    if (fileOutput == null)
        return;
    try {
        if (request == null) {
            if (exportDownsample.get() == 1.0)
                writer.writeImage(server, fileOutput.getAbsolutePath());
            else
                writer.writeImage(ImageServers.pyramidalize(server, exportDownsample.get()), fileOutput.getAbsolutePath());
        } else
            writer.writeImage(server, request, fileOutput.getAbsolutePath());
        lastWriter = writer;
    } catch (IOException e) {
        Dialogs.showErrorMessage("Export region", e);
    }
}
Also used : ObservableDoubleValue(javafx.beans.value.ObservableDoubleValue) TextArea(javafx.scene.control.TextArea) Label(javafx.scene.control.Label) ImageWriter(qupath.lib.images.writers.ImageWriter) BufferedImage(java.awt.image.BufferedImage) TextField(javafx.scene.control.TextField) GridPane(javafx.scene.layout.GridPane) ComboBox(javafx.scene.control.ComboBox) Tooltip(javafx.scene.control.Tooltip) IOException(java.io.IOException) RectangleROI(qupath.lib.roi.RectangleROI) ROI(qupath.lib.roi.interfaces.ROI) PolygonROI(qupath.lib.roi.PolygonROI) PathObject(qupath.lib.objects.PathObject) RegionRequest(qupath.lib.regions.RegionRequest) File(java.io.File)

Example 18 with PathObject

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

the class Commands method convertDetectionsToPoints.

/**
 * Convert detection objects to point annotations based upon their ROI centroids.
 * @param imageData the image data to process
 * @param preferNucleus if true, use a nucleus ROI for cell objects (if available
 */
public static void convertDetectionsToPoints(ImageData<?> imageData, boolean preferNucleus) {
    if (imageData == null) {
        Dialogs.showNoImageError("Convert detections to points");
        return;
    }
    PathObjectHierarchy hierarchy = imageData.getHierarchy();
    Collection<PathObject> pathObjects = hierarchy.getDetectionObjects();
    if (pathObjects.isEmpty()) {
        Dialogs.showErrorMessage("Detections to points", "No detections found!");
        return;
    }
    // Remove any detections that don't have a ROI - can't do much with them
    Iterator<PathObject> iter = pathObjects.iterator();
    while (iter.hasNext()) {
        if (!iter.next().hasROI())
            iter.remove();
    }
    if (pathObjects.isEmpty()) {
        logger.warn("No detections found with ROIs!");
        return;
    }
    // Check if existing objects should be deleted
    String message = pathObjects.size() == 1 ? "Delete detection after converting to a point?" : String.format("Delete %d detections after converting to points?", pathObjects.size());
    var button = Dialogs.showYesNoCancelDialog("Detections to points", message);
    if (button == Dialogs.DialogButton.CANCEL)
        return;
    boolean deleteDetections = button == Dialogs.DialogButton.YES;
    PathObjectTools.convertToPoints(hierarchy, pathObjects, preferNucleus, deleteDetections);
}
Also used : PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) PathObject(qupath.lib.objects.PathObject)

Example 19 with PathObject

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

the class QuPathGUI method setViewerPopupMenu.

private void setViewerPopupMenu(final QuPathViewerPlus viewer) {
    final ContextMenu popup = new ContextMenu();
    MenuItem miAddRow = new MenuItem("Add row");
    miAddRow.setOnAction(e -> viewerManager.addRow(viewer));
    MenuItem miAddColumn = new MenuItem("Add column");
    miAddColumn.setOnAction(e -> viewerManager.addColumn(viewer));
    MenuItem miRemoveRow = new MenuItem("Remove row");
    miRemoveRow.setOnAction(e -> viewerManager.removeViewerRow(viewer));
    MenuItem miRemoveColumn = new MenuItem("Remove column");
    miRemoveColumn.setOnAction(e -> viewerManager.removeViewerColumn(viewer));
    MenuItem miCloseViewer = new MenuItem("Close viewer");
    miCloseViewer.setOnAction(e -> {
        viewerManager.closeViewer(viewer);
    // viewerManager.removeViewer(viewer);
    });
    MenuItem miResizeGrid = new MenuItem("Reset grid size");
    miResizeGrid.setOnAction(e -> {
        viewerManager.resetGridSize();
    });
    MenuItem miToggleSync = ActionTools.createCheckMenuItem(defaultActions.TOGGLE_SYNCHRONIZE_VIEWERS, null);
    MenuItem miMatchResolutions = ActionTools.createMenuItem(defaultActions.MATCH_VIEWER_RESOLUTIONS);
    Menu menuMultiview = MenuTools.createMenu("Multi-view", miToggleSync, miMatchResolutions, miCloseViewer, null, miResizeGrid, null, // null,
    miAddRow, miAddColumn, null, miRemoveRow, miRemoveColumn);
    Menu menuView = MenuTools.createMenu("Display", ActionTools.createCheckMenuItem(defaultActions.SHOW_ANALYSIS_PANE, null), defaultActions.BRIGHTNESS_CONTRAST, null, ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 0.25), "400%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 1), "100%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 2), "50%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 10), "10%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 100), "1%"));
    ToggleGroup groupTools = new ToggleGroup();
    Menu menuTools = MenuTools.createMenu("Set tool", ActionTools.createCheckMenuItem(defaultActions.MOVE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.RECTANGLE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.ELLIPSE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.LINE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.POLYGON_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.POLYLINE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.BRUSH_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.POINTS_TOOL, groupTools), null, ActionTools.createCheckMenuItem(defaultActions.SELECTION_MODE));
    // Handle awkward 'TMA core missing' option
    CheckMenuItem miTMAValid = new CheckMenuItem("Set core valid");
    miTMAValid.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), false));
    CheckMenuItem miTMAMissing = new CheckMenuItem("Set core missing");
    miTMAMissing.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), true));
    Menu menuTMA = new Menu("TMA");
    MenuTools.addMenuItems(menuTMA, miTMAValid, miTMAMissing, null, defaultActions.TMA_ADD_NOTE, null, MenuTools.createMenu("Add", createImageDataAction(imageData -> TMACommands.promptToAddRowBeforeSelected(imageData), "Add TMA row before"), createImageDataAction(imageData -> TMACommands.promptToAddRowAfterSelected(imageData), "Add TMA row after"), createImageDataAction(imageData -> TMACommands.promptToAddColumnBeforeSelected(imageData), "Add TMA column before"), createImageDataAction(imageData -> TMACommands.promptToAddColumnAfterSelected(imageData), "Add TMA column after")), MenuTools.createMenu("Remove", createImageDataAction(imageData -> TMACommands.promptToDeleteTMAGridRow(imageData), "Remove TMA row"), createImageDataAction(imageData -> TMACommands.promptToDeleteTMAGridColumn(imageData), "column")));
    // Create an empty placeholder menu
    Menu menuSetClass = MenuTools.createMenu("Set class");
    // CheckMenuItem miTMAValid = new CheckMenuItem("Set core valid");
    // miTMAValid.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), false));
    // CheckMenuItem miTMAMissing = new CheckMenuItem("Set core missing");
    // miTMAMissing.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), true));
    Menu menuCells = MenuTools.createMenu("Cells", ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_BOUNDARIES_AND_NUCLEI, null), ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_NUCLEI, null), ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_BOUNDARIES, null), ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_CENTROIDS, null));
    MenuItem miClearSelectedObjects = new MenuItem("Delete object");
    miClearSelectedObjects.setOnAction(e -> {
        PathObjectHierarchy hierarchy = viewer.getHierarchy();
        if (hierarchy == null)
            return;
        if (hierarchy.getSelectionModel().singleSelection()) {
            GuiTools.promptToRemoveSelectedObject(hierarchy.getSelectionModel().getSelectedObject(), hierarchy);
        } else {
            GuiTools.promptToClearAllSelectedObjects(viewer.getImageData());
        }
    });
    // Create a standard annotations menu
    Menu menuAnnotations = GuiTools.populateAnnotationsMenu(this, new Menu("Annotations"));
    SeparatorMenuItem topSeparator = new SeparatorMenuItem();
    popup.setOnShowing(e -> {
        // Check if we have any cells
        ImageData<?> imageData = viewer.getImageData();
        if (imageData == null)
            menuCells.setVisible(false);
        else
            menuCells.setVisible(!imageData.getHierarchy().getDetectionObjects().isEmpty());
        // Check what to show for TMA cores or annotations
        Collection<PathObject> selectedObjects = viewer.getAllSelectedObjects();
        PathObject pathObject = viewer.getSelectedObject();
        menuTMA.setVisible(false);
        if (pathObject instanceof TMACoreObject) {
            boolean isMissing = ((TMACoreObject) pathObject).isMissing();
            miTMAValid.setSelected(!isMissing);
            miTMAMissing.setSelected(isMissing);
            menuTMA.setVisible(true);
        }
        // Add clear objects option if we have more than one non-TMA object
        if (imageData == null || imageData.getHierarchy().getSelectionModel().noSelection() || imageData.getHierarchy().getSelectionModel().getSelectedObject() instanceof TMACoreObject)
            miClearSelectedObjects.setVisible(false);
        else {
            if (imageData.getHierarchy().getSelectionModel().singleSelection()) {
                miClearSelectedObjects.setText("Delete object");
                miClearSelectedObjects.setVisible(true);
            } else {
                miClearSelectedObjects.setText("Delete objects");
                miClearSelectedObjects.setVisible(true);
            }
        }
        boolean hasAnnotations = pathObject instanceof PathAnnotationObject || (!selectedObjects.isEmpty() && selectedObjects.stream().allMatch(p -> p.isAnnotation()));
        updateSetAnnotationPathClassMenu(menuSetClass, viewer);
        menuAnnotations.setVisible(hasAnnotations);
        topSeparator.setVisible(hasAnnotations || pathObject instanceof TMACoreObject);
        // Occasionally, the newly-visible top part of a popup menu can have the wrong size?
        popup.setWidth(popup.getPrefWidth());
    });
    // popup.add(menuClassify);
    popup.getItems().addAll(miClearSelectedObjects, menuTMA, menuSetClass, menuAnnotations, topSeparator, menuMultiview, menuCells, menuView, menuTools);
    popup.setAutoHide(true);
    // Enable circle pop-up for quick classification on right-click
    CirclePopupMenu circlePopup = new CirclePopupMenu(viewer.getView(), null);
    viewer.getView().addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
        if ((e.isPopupTrigger() || e.isSecondaryButtonDown()) && e.isShiftDown() && !getAvailablePathClasses().isEmpty()) {
            circlePopup.setAnimationDuration(Duration.millis(200));
            updateSetAnnotationPathClassMenu(circlePopup, viewer);
            circlePopup.show(e.getScreenX(), e.getScreenY());
            e.consume();
            return;
        } else if (circlePopup.isShown())
            circlePopup.hide();
        if (e.isPopupTrigger() || e.isSecondaryButtonDown()) {
            popup.show(viewer.getView().getScene().getWindow(), e.getScreenX(), e.getScreenY());
            e.consume();
        }
    });
// // It's necessary to make the Window the owner, since otherwise the context menu does not disappear when clicking elsewhere on the viewer
// viewer.getView().setOnContextMenuRequested(e -> {
// popup.show(viewer.getView().getScene().getWindow(), e.getScreenX(), e.getScreenY());
// //			popup.show(viewer.getView(), e.getScreenX(), e.getScreenY());
// });
}
Also used : Change(javafx.collections.ListChangeListener.Change) PathObjectHierarchyView(qupath.lib.gui.panes.PathObjectHierarchyView) SelectedMeasurementTableView(qupath.lib.gui.panes.SelectedMeasurementTableView) Version(qupath.lib.common.Version) ProjectBrowser(qupath.lib.gui.panes.ProjectBrowser) ListChangeListener(javafx.collections.ListChangeListener) Map(java.util.Map) Path(java.nio.file.Path) ReleaseVersion(qupath.lib.gui.extensions.UpdateChecker.ReleaseVersion) Rectangle2D(javafx.geometry.Rectangle2D) PathObjects(qupath.lib.objects.PathObjects) Rectangle(javafx.scene.shape.Rectangle) BooleanProperty(javafx.beans.property.BooleanProperty) Project(qupath.lib.projects.Project) ObservableList(javafx.collections.ObservableList) Divider(javafx.scene.control.SplitPane.Divider) QuPathExtension(qupath.lib.gui.extensions.QuPathExtension) ByteArrayOutputStream(java.io.ByteArrayOutputStream) FXCollections(javafx.collections.FXCollections) PathIcons(qupath.lib.gui.tools.IconFactory.PathIcons) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) Bindings(javafx.beans.binding.Bindings) LinkedHashMap(java.util.LinkedHashMap) TreeTableView(javafx.scene.control.TreeTableView) PreferencePane(qupath.lib.gui.panes.PreferencePane) Commands(qupath.lib.gui.commands.Commands) QuPathStyleManager(qupath.lib.gui.prefs.QuPathStyleManager) IOException(java.io.IOException) OverlayOptions(qupath.lib.gui.viewer.OverlayOptions) Preferences(java.util.prefs.Preferences) ROI(qupath.lib.roi.interfaces.ROI) PathTools(qupath.lib.gui.viewer.tools.PathTools) ParameterPanelFX(qupath.lib.gui.dialogs.ParameterPanelFX) DragDropImportListener(qupath.lib.gui.viewer.DragDropImportListener) ImageView(javafx.scene.image.ImageView) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) Image(javafx.scene.image.Image) PathIO(qupath.lib.io.PathIO) EventHandler(javafx.event.EventHandler) ImageServer(qupath.lib.images.servers.ImageServer) BooleanBinding(javafx.beans.binding.BooleanBinding) TextInputControl(javafx.scene.control.TextInputControl) URLDecoder(java.net.URLDecoder) UncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler) Date(java.util.Date) URISyntaxException(java.net.URISyntaxException) ObjectInputStream(java.io.ObjectInputStream) KeyCombination(javafx.scene.input.KeyCombination) DefaultImageRegionStore(qupath.lib.gui.images.stores.DefaultImageRegionStore) ByteArrayInputStream(java.io.ByteArrayInputStream) Locale(java.util.Locale) GitHubProject(qupath.lib.gui.extensions.GitHubProject) ImageIO(javax.imageio.ImageIO) RotateEvent(javafx.scene.input.RotateEvent) WindowEvent(javafx.stage.WindowEvent) PathInteractivePlugin(qupath.lib.plugins.PathInteractivePlugin) Orientation(javafx.geometry.Orientation) MenuItem(javafx.scene.control.MenuItem) Ellipse(javafx.scene.shape.Ellipse) ImageServerProvider(qupath.lib.images.servers.ImageServerProvider) Collection(java.util.Collection) Font(javafx.scene.text.Font) ServiceLoader(java.util.ServiceLoader) Collectors(java.util.stream.Collectors) BorderStroke(javafx.scene.layout.BorderStroke) PathObject(qupath.lib.objects.PathObject) Objects(java.util.Objects) ImageTypeSetting(qupath.lib.gui.prefs.PathPrefs.ImageTypeSetting) ProjectIO(qupath.lib.projects.ProjectIO) GuiTools(qupath.lib.gui.tools.GuiTools) ExecutorCompletionService(java.util.concurrent.ExecutorCompletionService) Scene(javafx.scene.Scene) ListView(javafx.scene.control.ListView) ReadOnlyObjectProperty(javafx.beans.property.ReadOnlyObjectProperty) SimpleStringProperty(javafx.beans.property.SimpleStringProperty) Action(org.controlsfx.control.action.Action) PathClassFactory(qupath.lib.objects.classes.PathClassFactory) ScriptEditor(qupath.lib.gui.scripting.ScriptEditor) TableColumn(javafx.scene.control.TableColumn) HashSet(java.util.HashSet) Insets(javafx.geometry.Insets) DetectionDisplayMode(qupath.lib.gui.viewer.OverlayOptions.DetectionDisplayMode) ExecutorService(java.util.concurrent.ExecutorService) KeyCode(javafx.scene.input.KeyCode) ActionAccelerator(qupath.lib.gui.ActionTools.ActionAccelerator) Logger(org.slf4j.Logger) Dialog(javafx.scene.control.Dialog) Label(javafx.scene.control.Label) MenuBar(javafx.scene.control.MenuBar) ActionIcon(qupath.lib.gui.ActionTools.ActionIcon) ServerBuilder(qupath.lib.images.servers.ImageServerBuilder.ServerBuilder) ScrollEvent(javafx.scene.input.ScrollEvent) Consumer(java.util.function.Consumer) SimpleBooleanProperty(javafx.beans.property.SimpleBooleanProperty) Stage(javafx.stage.Stage) ViewerPlusDisplayOptions(qupath.lib.gui.viewer.ViewerPlusDisplayOptions) Comparator(java.util.Comparator) PathTool(qupath.lib.gui.viewer.tools.PathTool) Arrays(java.util.Arrays) ServerTools(qupath.lib.images.servers.ServerTools) ActionUtils(org.controlsfx.control.action.ActionUtils) ActionDescription(qupath.lib.gui.ActionTools.ActionDescription) ReadOnlyBooleanProperty(javafx.beans.property.ReadOnlyBooleanProperty) StackPane(javafx.scene.layout.StackPane) AnnotationPane(qupath.lib.gui.panes.AnnotationPane) JFXPanel(javafx.embed.swing.JFXPanel) Category(java.util.Locale.Category) ParameterList(qupath.lib.plugins.parameters.ParameterList) TabPane(javafx.scene.control.TabPane) ScriptException(javax.script.ScriptException) CountingPanelCommand(qupath.lib.gui.commands.CountingPanelCommand) SplitPane(javafx.scene.control.SplitPane) Border(javafx.scene.layout.Border) Event(javafx.event.Event) Set(java.util.Set) KeyEvent(javafx.scene.input.KeyEvent) Screen(javafx.stage.Screen) AffineTransform(java.awt.geom.AffineTransform) QuPathViewerListener(qupath.lib.gui.viewer.QuPathViewerListener) StandardCharsets(java.nio.charset.StandardCharsets) Executors(java.util.concurrent.Executors) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) Platform(javafx.application.Platform) Region(javafx.scene.layout.Region) CommandFinderTools(qupath.lib.gui.tools.CommandFinderTools) InputDisplayCommand(qupath.lib.gui.commands.InputDisplayCommand) ImageRegionStoreFactory(qupath.lib.gui.images.stores.ImageRegionStoreFactory) ThreadTools(qupath.lib.common.ThreadTools) DefaultScriptEditor(qupath.lib.gui.scripting.DefaultScriptEditor) GitHubRepo(qupath.lib.gui.extensions.GitHubProject.GitHubRepo) BorderPane(javafx.scene.layout.BorderPane) ButtonData(javafx.scene.control.ButtonBar.ButtonData) SimpleDateFormat(java.text.SimpleDateFormat) PathPlugin(qupath.lib.plugins.PathPlugin) Projects(qupath.lib.projects.Projects) StandardCopyOption(java.nio.file.StandardCopyOption) ArrayList(java.util.ArrayList) TabClosingPolicy(javafx.scene.control.TabPane.TabClosingPolicy) QuPathViewerPlus(qupath.lib.gui.viewer.QuPathViewerPlus) ObjectOutputStream(java.io.ObjectOutputStream) LinkedHashSet(java.util.LinkedHashSet) Color(javafx.scene.paint.Color) CirclePopupMenu(jfxtras.scene.menu.CirclePopupMenu) TitledPane(javafx.scene.control.TitledPane) Files(java.nio.file.Files) ToolBar(javafx.scene.control.ToolBar) GeneralTools(qupath.lib.common.GeneralTools) Node(javafx.scene.Node) CheckBox(javafx.scene.control.CheckBox) ProjectCommands(qupath.lib.gui.commands.ProjectCommands) File(java.io.File) PathObjectTools(qupath.lib.objects.PathObjectTools) Menu(javafx.scene.control.Menu) Cursor(javafx.scene.Cursor) KeyCodeCombination(javafx.scene.input.KeyCodeCombination) Paths(java.nio.file.Paths) SimpleObjectProperty(javafx.beans.property.SimpleObjectProperty) Tab(javafx.scene.control.Tab) PathPrefs(qupath.lib.gui.prefs.PathPrefs) StringBinding(javafx.beans.binding.StringBinding) Pos(javafx.geometry.Pos) Area(java.awt.geom.Area) CheckMenuItem(javafx.scene.control.CheckMenuItem) LoggerFactory(org.slf4j.LoggerFactory) UpdateChecker(qupath.lib.gui.extensions.UpdateChecker) Parent(javafx.scene.Parent) ContextMenu(javafx.scene.control.ContextMenu) URI(java.net.URI) ImageServers(qupath.lib.images.servers.ImageServers) TableView(javafx.scene.control.TableView) ImageType(qupath.lib.images.ImageData.ImageType) Shape(java.awt.Shape) BufferedImage(java.awt.image.BufferedImage) GroovyLanguage(qupath.lib.gui.scripting.languages.GroovyLanguage) ImageServerBuilder(qupath.lib.images.servers.ImageServerBuilder) FileNotFoundException(java.io.FileNotFoundException) TreeView(javafx.scene.control.TreeView) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) QuPathViewer(qupath.lib.gui.viewer.QuPathViewer) List(java.util.List) Duration(javafx.util.Duration) ColorToolsFX(qupath.lib.gui.tools.ColorToolsFX) Optional(java.util.Optional) LogManager(qupath.lib.gui.logging.LogManager) RadioMenuItem(javafx.scene.control.RadioMenuItem) WorkflowCommandLogView(qupath.lib.gui.panes.WorkflowCommandLogView) TextArea(javafx.scene.control.TextArea) ButtonType(javafx.scene.control.ButtonType) MouseEvent(javafx.scene.input.MouseEvent) HashMap(java.util.HashMap) BrightnessContrastCommand(qupath.lib.gui.commands.BrightnessContrastCommand) UriImageSupport(qupath.lib.images.servers.ImageServerBuilder.UriImageSupport) Dialogs(qupath.lib.gui.dialogs.Dialogs) SwingUtilities(javax.swing.SwingUtilities) HostServices(javafx.application.HostServices) ZoomEvent(javafx.scene.input.ZoomEvent) TMACommands(qupath.lib.gui.commands.TMACommands) Tooltip(javafx.scene.control.Tooltip) ImageDetailsPane(qupath.lib.gui.panes.ImageDetailsPane) ImageData(qupath.lib.images.ImageData) Desktop(java.awt.Desktop) RoiTools(qupath.lib.roi.RoiTools) ObjectProperty(javafx.beans.property.ObjectProperty) Iterator(java.util.Iterator) ProjectImageEntry(qupath.lib.projects.ProjectImageEntry) TableRow(javafx.scene.control.TableRow) PathClass(qupath.lib.objects.classes.PathClass) TMACoreObject(qupath.lib.objects.TMACoreObject) DropShadow(javafx.scene.effect.DropShadow) MenuTools(qupath.lib.gui.tools.MenuTools) BorderStrokeStyle(javafx.scene.layout.BorderStrokeStyle) ActionEvent(javafx.event.ActionEvent) ToggleGroup(javafx.scene.control.ToggleGroup) LogViewerCommand(qupath.lib.gui.commands.LogViewerCommand) SwingFXUtils(javafx.embed.swing.SwingFXUtils) Collections(java.util.Collections) InputStream(java.io.InputStream) DialogButton(qupath.lib.gui.dialogs.Dialogs.DialogButton) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) CirclePopupMenu(jfxtras.scene.menu.CirclePopupMenu) TMACoreObject(qupath.lib.objects.TMACoreObject) ContextMenu(javafx.scene.control.ContextMenu) MenuItem(javafx.scene.control.MenuItem) CheckMenuItem(javafx.scene.control.CheckMenuItem) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) RadioMenuItem(javafx.scene.control.RadioMenuItem) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) CheckMenuItem(javafx.scene.control.CheckMenuItem) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) ToggleGroup(javafx.scene.control.ToggleGroup) CirclePopupMenu(jfxtras.scene.menu.CirclePopupMenu) Menu(javafx.scene.control.Menu) ContextMenu(javafx.scene.control.ContextMenu)

Example 20 with PathObject

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

the class QuPathGUI method setupViewer.

void setupViewer(final QuPathViewerPlus viewer) {
    viewer.getView().setFocusTraversable(true);
    // Update active viewer as required
    viewer.getView().focusedProperty().addListener((e, f, nowFocussed) -> {
        if (nowFocussed) {
            viewerManager.setActiveViewer(viewer);
        }
    });
    viewer.getView().addEventFilter(MouseEvent.MOUSE_PRESSED, e -> viewer.getView().requestFocus());
    viewer.zoomToFitProperty().bind(zoomToFit);
    // Create popup menu
    setViewerPopupMenu(viewer);
    viewer.getView().widthProperty().addListener((e, f, g) -> {
        if (viewer.getZoomToFit())
            updateMagnificationString();
    });
    viewer.getView().heightProperty().addListener((e, f, g) -> {
        if (viewer.getZoomToFit())
            updateMagnificationString();
    });
    // Enable drag and drop
    dragAndDrop.setupTarget(viewer.getView());
    // Listen to the scroll wheel
    viewer.getView().setOnScroll(e -> {
        if (viewer == viewerManager.getActiveViewer() || !viewerManager.getSynchronizeViewers()) {
            double scrollUnits = e.getDeltaY() * PathPrefs.getScaledScrollSpeed();
            // Use shift down to adjust opacity
            if (e.isShortcutDown()) {
                OverlayOptions options = viewer.getOverlayOptions();
                options.setOpacity((float) (options.getOpacity() + scrollUnits * 0.001));
                return;
            }
            // Avoid zooming at the end of a gesture when using touchscreens
            if (e.isInertia())
                return;
            if (PathPrefs.invertScrollingProperty().get())
                scrollUnits = -scrollUnits;
            double newDownsampleFactor = viewer.getDownsampleFactor() * Math.pow(viewer.getDefaultZoomFactor(), scrollUnits);
            newDownsampleFactor = Math.min(viewer.getMaxDownsample(), Math.max(newDownsampleFactor, viewer.getMinDownsample()));
            viewer.setDownsampleFactor(newDownsampleFactor, e.getX(), e.getY());
        }
    });
    viewer.getView().addEventFilter(RotateEvent.ANY, e -> {
        if (!PathPrefs.useRotateGesturesProperty().get())
            return;
        // logger.debug("Rotating: " + e.getAngle());
        viewer.setRotation(viewer.getRotation() + Math.toRadians(e.getAngle()));
        e.consume();
    });
    viewer.getView().addEventFilter(ZoomEvent.ANY, e -> {
        if (!PathPrefs.useZoomGesturesProperty().get())
            return;
        double zoomFactor = e.getZoomFactor();
        if (Double.isNaN(zoomFactor))
            return;
        logger.debug("Zooming: " + e.getZoomFactor() + " (" + e.getTotalZoomFactor() + ")");
        viewer.setDownsampleFactor(viewer.getDownsampleFactor() / zoomFactor, e.getX(), e.getY());
        e.consume();
    });
    viewer.getView().addEventFilter(ScrollEvent.ANY, new ScrollEventPanningFilter(viewer));
    viewer.getView().addEventHandler(KeyEvent.KEY_PRESSED, e -> {
        PathObject pathObject = viewer.getSelectedObject();
        if (!e.isConsumed() && pathObject != null) {
            if (pathObject.isTMACore()) {
                TMACoreObject core = (TMACoreObject) pathObject;
                if (e.getCode() == KeyCode.ENTER) {
                    defaultActions.TMA_ADD_NOTE.handle(new ActionEvent(e.getSource(), e.getTarget()));
                    e.consume();
                } else if (e.getCode() == KeyCode.BACK_SPACE) {
                    core.setMissing(!core.isMissing());
                    viewer.getHierarchy().fireObjectsChangedEvent(this, Collections.singleton(core));
                    e.consume();
                }
            } else if (pathObject.isAnnotation()) {
                if (e.getCode() == KeyCode.ENTER) {
                    GuiTools.promptToSetActiveAnnotationProperties(viewer.getHierarchy());
                    e.consume();
                }
            }
        }
    });
}
Also used : PathObject(qupath.lib.objects.PathObject) OverlayOptions(qupath.lib.gui.viewer.OverlayOptions) TMACoreObject(qupath.lib.objects.TMACoreObject) ActionEvent(javafx.event.ActionEvent)

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