Search in sources :

Example 1 with ImageData

use of qupath.lib.images.ImageData in project qupath by qupath.

the class ProjectImportImagesCommand method getThumbnailRGB.

// /**
// * Add a single ImageServer to a project, without considering sub-images.
// * <p>
// * This includes an optional attempt to request a thumbnail; if this fails, the image will not be added.
// *
// * @param project the project to which the entry should be added
// * @param server the server to add
// * @param type the ImageType that should be set for each entry being added
// * @return
// */
// public static ProjectImageEntry<BufferedImage> addSingleImageToProject(Project<BufferedImage> project, ImageServer<BufferedImage> server, ImageType type) {
// ProjectImageEntry<BufferedImage> entry = null;
// try {
// var img = getThumbnailRGB(server, null);
// entry = project.addImage(server);
// if (entry != null) {
// // Write a thumbnail if we can
// entry.setThumbnail(img);
// // Initialize an ImageData object with a type, if required
// if (type != null) {
// var imageData = new ImageData<>(server, type);
// entry.saveImageData(imageData);
// }
// }
// } catch (IOException e) {
// logger.warn("Error attempting to add " + server, e);
// }
// return entry;
// }
public static BufferedImage getThumbnailRGB(ImageServer<BufferedImage> server, ImageDisplay imageDisplay) throws IOException {
    var img2 = server.getDefaultThumbnail(server.nZSlices() / 2, 0);
    // Try to write RGB images directly
    boolean success = false;
    if (imageDisplay == null && (server.isRGB() || img2.getType() == BufferedImage.TYPE_BYTE_GRAY)) {
        return resizeForThumbnail(img2);
    }
    if (!success) {
        // Try with display transforms
        if (imageDisplay == null) {
            // By wrapping the thumbnail, we avoid slow z-stack/time series requests & determine brightness & contrast just from one plane
            var wrappedServer = new WrappedBufferedImageServer("Dummy", img2, server.getMetadata().getChannels());
            imageDisplay = new ImageDisplay(new ImageData<>(wrappedServer));
        // imageDisplay = new ImageDisplay(new ImageData<>(server));
        }
        for (ChannelDisplayInfo info : imageDisplay.selectedChannels()) {
            imageDisplay.autoSetDisplayRange(info);
        }
        img2 = imageDisplay.applyTransforms(img2, null);
        return resizeForThumbnail(img2);
    }
    return img2;
}
Also used : WrappedBufferedImageServer(qupath.lib.images.servers.WrappedBufferedImageServer) ImageData(qupath.lib.images.ImageData) ChannelDisplayInfo(qupath.lib.display.ChannelDisplayInfo) ImageDisplay(qupath.lib.display.ImageDisplay)

Example 2 with ImageData

use of qupath.lib.images.ImageData in project qupath by qupath.

the class Commands method requestShapeFeatures.

private static void requestShapeFeatures(ImageData<?> imageData, Collection<ShapeFeatures> features) {
    if (imageData == null)
        return;
    var featureArray = features.toArray(ShapeFeatures[]::new);
    if (featureArray.length == 0)
        return;
    Collection<PathObject> selected = imageData.getHierarchy().getSelectionModel().getSelectedObjects();
    if (selected.isEmpty()) {
        Dialogs.showWarningNotification("Shape features", "No objects selected!");
    } else {
        selected = new ArrayList<>(selected);
        String featureString = Arrays.stream(featureArray).map(f -> "\"" + f.name() + "\"").collect(Collectors.joining(", "));
        QP.addShapeMeasurements(imageData, selected, featureArray);
        imageData.getHistoryWorkflow().addStep(new DefaultScriptableWorkflowStep("Add shape measurements", String.format("addShapeMeasurements(%s)", featureString)));
        if (selected.size() == 1)
            Dialogs.showInfoNotification("Shape features", "Shape features calculated for one object");
        else
            Dialogs.showInfoNotification("Shape features", "Shape features calculated for " + selected.size() + " objects");
    }
}
Also used : Arrays(java.util.Arrays) ServerTools(qupath.lib.images.servers.ServerTools) PathTileObject(qupath.lib.objects.PathTileObject) StackPane(javafx.scene.layout.StackPane) ImageWriter(qupath.lib.images.writers.ImageWriter) ParameterList(qupath.lib.plugins.parameters.ParameterList) ImageRegion(qupath.lib.regions.ImageRegion) Map(java.util.Map) PathObjects(qupath.lib.objects.PathObjects) Screen(javafx.stage.Screen) WorkflowStep(qupath.lib.plugins.workflow.WorkflowStep) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) Project(qupath.lib.projects.Project) ShapeFeatures(qupath.lib.analysis.features.ObjectMeasurements.ShapeFeatures) MeasurementMapPane(qupath.lib.gui.panes.MeasurementMapPane) BorderPane(javafx.scene.layout.BorderPane) StringProperty(javafx.beans.property.StringProperty) RectangleROI(qupath.lib.roi.RectangleROI) CheckBoxListCell(javafx.scene.control.cell.CheckBoxListCell) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) Supplier(java.util.function.Supplier) Bindings(javafx.beans.binding.Bindings) ViewTrackerControlPane(qupath.lib.gui.viewer.recording.ViewTrackerControlPane) Projects(qupath.lib.projects.Projects) ArrayList(java.util.ArrayList) CheckListView(org.controlsfx.control.CheckListView) ROIs(qupath.lib.roi.ROIs) ShapeSimplifier(qupath.lib.roi.ShapeSimplifier) TextAlignment(javafx.scene.text.TextAlignment) PathClassPane(qupath.lib.gui.panes.PathClassPane) GridPane(javafx.scene.layout.GridPane) Files(java.nio.file.Files) GeneralTools(qupath.lib.common.GeneralTools) RegionRequest(qupath.lib.regions.RegionRequest) Window(java.awt.Window) DistanceTools(qupath.lib.analysis.DistanceTools) IOException(java.io.IOException) File(java.io.File) OverlayOptions(qupath.lib.gui.viewer.OverlayOptions) PathObjectTools(qupath.lib.objects.PathObjectTools) ROI(qupath.lib.roi.interfaces.ROI) QP(qupath.lib.scripting.QP) GridLines(qupath.lib.gui.viewer.GridLines) PathPrefs(qupath.lib.gui.prefs.PathPrefs) RenderedImageServer(qupath.lib.gui.images.servers.RenderedImageServer) PaneTools(qupath.lib.gui.tools.PaneTools) PathIO(qupath.lib.io.PathIO) Button(javafx.scene.control.Button) Pos(javafx.geometry.Pos) ImageServer(qupath.lib.images.servers.ImageServer) CombineOp(qupath.lib.roi.RoiTools.CombineOp) LoggerFactory(org.slf4j.LoggerFactory) ObservableDoubleValue(javafx.beans.value.ObservableDoubleValue) ComboBox(javafx.scene.control.ComboBox) ImageServers(qupath.lib.images.servers.ImageServers) PolygonROI(qupath.lib.roi.PolygonROI) QuPathGUI(qupath.lib.gui.QuPathGUI) Pane(javafx.scene.layout.Pane) TextField(javafx.scene.control.TextField) BufferedImage(java.awt.image.BufferedImage) Collection(java.util.Collection) Collectors(java.util.stream.Collectors) PathDetectionObject(qupath.lib.objects.PathDetectionObject) PathObject(qupath.lib.objects.PathObject) QuPathViewer(qupath.lib.gui.viewer.QuPathViewer) Priority(javafx.scene.layout.Priority) List(java.util.List) DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) ProjectIO(qupath.lib.projects.ProjectIO) GuiTools(qupath.lib.gui.tools.GuiTools) TMASummaryViewer(qupath.lib.gui.tma.TMASummaryViewer) ImagePlane(qupath.lib.regions.ImagePlane) PathCellObject(qupath.lib.objects.PathCellObject) Scene(javafx.scene.Scene) WorkflowCommandLogView(qupath.lib.gui.panes.WorkflowCommandLogView) TextArea(javafx.scene.control.TextArea) ButtonType(javafx.scene.control.ButtonType) Action(org.controlsfx.control.action.Action) HashMap(java.util.HashMap) DoubleProperty(javafx.beans.property.DoubleProperty) Function(java.util.function.Function) Dialogs(qupath.lib.gui.dialogs.Dialogs) Insets(javafx.geometry.Insets) ActionTools(qupath.lib.gui.ActionTools) Tooltip(javafx.scene.control.Tooltip) WeakHashMap(java.util.WeakHashMap) ImageData(qupath.lib.images.ImageData) RoiTools(qupath.lib.roi.RoiTools) Modality(javafx.stage.Modality) Logger(org.slf4j.Logger) Label(javafx.scene.control.Label) Iterator(java.util.Iterator) ImageWriterTools(qupath.lib.images.writers.ImageWriterTools) TMACoreObject(qupath.lib.objects.TMACoreObject) Stage(javafx.stage.Stage) Collections(java.util.Collections) ContentDisplay(javafx.scene.control.ContentDisplay) DialogButton(qupath.lib.gui.dialogs.Dialogs.DialogButton) DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) PathObject(qupath.lib.objects.PathObject)

Example 3 with ImageData

use of qupath.lib.images.ImageData in project qupath by qupath.

the class TMACommands method promptToExportTMAData.

/**
 * Prompt to export summary TMA data for a specific image to a directory.
 * @param qupath
 * @param imageData
 */
public static void promptToExportTMAData(QuPathGUI qupath, ImageData<BufferedImage> imageData) {
    String title = "Export TMA data";
    if (imageData == null) {
        Dialogs.showNoImageError(title);
        return;
    }
    PathObjectHierarchy hierarchy = imageData == null ? null : imageData.getHierarchy();
    if (hierarchy == null || hierarchy.isEmpty() || hierarchy.getTMAGrid() == null || hierarchy.getTMAGrid().nCores() == 0) {
        Dialogs.showErrorMessage(title, "No TMA data available!");
        return;
    }
    var overlayOptions = qupath.getViewers().stream().filter(v -> v.getImageData() == imageData).map(v -> v.getOverlayOptions()).findFirst().orElse(qupath.getOverlayOptions());
    String defaultName = ServerTools.getDisplayableImageName(imageData.getServer());
    File file = Dialogs.promptToSaveFile(null, null, defaultName, "TMA data", ".qptma");
    if (file != null) {
        if (!file.getName().endsWith(".qptma"))
            file = new File(file.getParentFile(), file.getName() + ".qptma");
        double downsample = PathPrefs.tmaExportDownsampleProperty().get();
        TMADataIO.writeTMAData(file, imageData, overlayOptions, downsample);
        WorkflowStep step = new DefaultScriptableWorkflowStep("Export TMA data", "exportTMAData(\"" + GeneralTools.escapeFilePath(file.getParentFile().getAbsolutePath()) + "\", " + downsample + ")");
        imageData.getHistoryWorkflow().addStep(step);
    // PathAwtIO.writeTMAData(file, imageData, viewer.getOverlayOptions(), Double.NaN);
    }
}
Also used : Arrays(java.util.Arrays) ServerTools(qupath.lib.images.servers.ServerTools) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) ArrayList(java.util.ArrayList) Dialogs(qupath.lib.gui.dialogs.Dialogs) TMADataIO(qupath.lib.gui.tma.TMADataIO) ParameterList(qupath.lib.plugins.parameters.ParameterList) Map(java.util.Map) WeakHashMap(java.util.WeakHashMap) RunningStatistics(qupath.lib.analysis.stats.RunningStatistics) QuPathGUI(qupath.lib.gui.QuPathGUI) ImageData(qupath.lib.images.ImageData) BufferedImage(java.awt.image.BufferedImage) GeneralTools(qupath.lib.common.GeneralTools) PathObjects(qupath.lib.objects.PathObjects) TMACoreObject(qupath.lib.objects.TMACoreObject) WorkflowStep(qupath.lib.plugins.workflow.WorkflowStep) Collectors(java.util.stream.Collectors) File(java.io.File) PathObjectTools(qupath.lib.objects.PathObjectTools) PathObject(qupath.lib.objects.PathObject) DefaultTMAGrid(qupath.lib.objects.hierarchy.DefaultTMAGrid) List(java.util.List) BooleanProperty(javafx.beans.property.BooleanProperty) DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) QP(qupath.lib.scripting.QP) StringProperty(javafx.beans.property.StringProperty) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) PathPrefs(qupath.lib.gui.prefs.PathPrefs) DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) WorkflowStep(qupath.lib.plugins.workflow.WorkflowStep) DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) File(java.io.File)

Example 4 with ImageData

use of qupath.lib.images.ImageData 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 5 with ImageData

use of qupath.lib.images.ImageData in project qupath by qupath.

the class BrightnessContrastCommand method createDialog.

protected Stage createDialog() {
    if (!isInitialized())
        initializeSliders();
    initializePopup();
    changed(null, null, qupath.getImageData());
    BorderPane pane = new BorderPane();
    GridPane box = new GridPane();
    String blank = "      ";
    Label labelMin = new Label("Min display");
    // labelMin.setTooltip(new Tooltip("Set minimum lookup table value - double-click to edit manually"));
    Label labelMinValue = new Label(blank);
    labelMinValue.setTooltip(new Tooltip("Set minimum lookup table value - double-click to edit manually"));
    labelMinValue.textProperty().bind(Bindings.createStringBinding(() -> {
        // If value < 10, return 2 dp, otherwise 1 dp. Should be more useful for 16-/32-bit images.
        return sliderMin.getValue() < 10 ? String.format("%.2f", sliderMin.getValue()) : String.format("%.1f", sliderMin.getValue());
    }, table.getSelectionModel().selectedItemProperty(), sliderMin.valueProperty()));
    box.add(labelMin, 0, 0);
    box.add(sliderMin, 1, 0);
    box.add(labelMinValue, 2, 0);
    Label labelMax = new Label("Max display");
    labelMax.setTooltip(new Tooltip("Set maximum lookup table value - double-click to edit manually"));
    Label labelMaxValue = new Label(blank);
    labelMaxValue.setTooltip(new Tooltip("Set maximum lookup table value - double-click to edit manually"));
    labelMaxValue.textProperty().bind(Bindings.createStringBinding(() -> {
        // If value < 10, return 2 dp, otherwise 1 dp. Should be more useful for 16-/32-bit images.
        return sliderMax.getValue() < 10 ? String.format("%.2f", sliderMax.getValue()) : String.format("%.1f", sliderMax.getValue());
    }, table.getSelectionModel().selectedItemProperty(), sliderMax.valueProperty()));
    box.add(labelMax, 0, 1);
    box.add(sliderMax, 1, 1);
    box.add(labelMaxValue, 2, 1);
    box.setVgap(5);
    GridPane.setFillWidth(sliderMin, Boolean.TRUE);
    GridPane.setFillWidth(sliderMax, Boolean.TRUE);
    box.prefWidthProperty().bind(pane.widthProperty());
    box.setPadding(new Insets(5, 0, 5, 0));
    GridPane.setHgrow(sliderMin, Priority.ALWAYS);
    GridPane.setHgrow(sliderMax, Priority.ALWAYS);
    // In the absence of a better way, make it possible to enter display range values
    // manually by double-clicking on the corresponding label
    labelMinValue.setOnMouseClicked(e -> {
        if (e.getClickCount() == 2) {
            ChannelDisplayInfo infoVisible = getCurrentInfo();
            if (infoVisible == null)
                return;
            Double value = Dialogs.showInputDialog("Display range", "Set display range minimum", (double) infoVisible.getMinDisplay());
            if (value != null && !Double.isNaN(value)) {
                sliderMin.setValue(value);
                // Update display directly if out of slider range
                if (value < sliderMin.getMin() || value > sliderMin.getMax()) {
                    imageDisplay.setMinMaxDisplay(infoVisible, (float) value.floatValue(), (float) infoVisible.getMaxDisplay());
                    // infoVisible.setMinDisplay(value.floatValue());
                    // viewer.updateThumbnail();
                    updateSliders();
                    viewer.repaintEntireImage();
                }
            }
        }
    });
    labelMaxValue.setOnMouseClicked(e -> {
        if (e.getClickCount() == 2) {
            ChannelDisplayInfo infoVisible = getCurrentInfo();
            if (infoVisible == null)
                return;
            Double value = Dialogs.showInputDialog("Display range", "Set display range maximum", (double) infoVisible.getMaxDisplay());
            if (value != null && !Double.isNaN(value)) {
                sliderMax.setValue(value);
                // Update display directly if out of slider range
                if (value < sliderMax.getMin() || value > sliderMax.getMax()) {
                    imageDisplay.setMinMaxDisplay(infoVisible, (float) infoVisible.getMinDisplay(), (float) value.floatValue());
                    // infoVisible.setMaxDisplay(value.floatValue());
                    // viewer.updateThumbnail();
                    updateSliders();
                    viewer.repaintEntireImage();
                }
            }
        }
    });
    Button btnAuto = new Button("Auto");
    btnAuto.setOnAction(e -> {
        if (imageDisplay == null)
            return;
        // if (histogram == null)
        // return;
        // //				setSliders((float)histogram.getEdgeMin(), (float)histogram.getEdgeMax());
        ChannelDisplayInfo info = getCurrentInfo();
        double saturation = PathPrefs.autoBrightnessContrastSaturationPercentProperty().get() / 100.0;
        imageDisplay.autoSetDisplayRange(info, saturation);
        for (ChannelDisplayInfo info2 : table.getSelectionModel().getSelectedItems()) {
            imageDisplay.autoSetDisplayRange(info2, saturation);
        }
        updateSliders();
        handleSliderChange();
    });
    Button btnReset = new Button("Reset");
    btnReset.setOnAction(e -> {
        for (ChannelDisplayInfo info : table.getSelectionModel().getSelectedItems()) {
            imageDisplay.setMinMaxDisplay(info, info.getMinAllowed(), info.getMaxAllowed());
        }
        sliderMin.setValue(sliderMin.getMin());
        sliderMax.setValue(sliderMax.getMax());
    });
    Stage dialog = new Stage();
    dialog.initOwner(qupath.getStage());
    dialog.setTitle("Brightness & contrast");
    // Create color/channel display table
    table = new TableView<>(imageDisplay == null ? FXCollections.observableArrayList() : imageDisplay.availableChannels());
    table.setPlaceholder(new Text("No channels available"));
    table.addEventHandler(KeyEvent.KEY_PRESSED, new CopyTableListener());
    table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
    table.getSelectionModel().selectedItemProperty().addListener((v, o, n) -> {
        updateHistogram();
        updateSliders();
    });
    TableColumn<ChannelDisplayInfo, ChannelDisplayInfo> col1 = new TableColumn<>("Color");
    col1.setCellValueFactory(new Callback<CellDataFeatures<ChannelDisplayInfo, ChannelDisplayInfo>, ObservableValue<ChannelDisplayInfo>>() {

        @Override
        public ObservableValue<ChannelDisplayInfo> call(CellDataFeatures<ChannelDisplayInfo, ChannelDisplayInfo> p) {
            return new SimpleObjectProperty<ChannelDisplayInfo>(p.getValue());
        }
    });
    col1.setCellFactory(column -> {
        return new TableCell<ChannelDisplayInfo, ChannelDisplayInfo>() {

            @Override
            protected void updateItem(ChannelDisplayInfo item, boolean empty) {
                super.updateItem(item, empty);
                if (item == null || empty) {
                    setText(null);
                    setGraphic(null);
                    return;
                }
                setText(item.getName());
                Rectangle square = new Rectangle(0, 0, 10, 10);
                Integer rgb = item.getColor();
                if (rgb == null)
                    square.setFill(Color.TRANSPARENT);
                else
                    square.setFill(ColorToolsFX.getCachedColor(rgb));
                setGraphic(square);
            }
        };
    });
    col1.setSortable(false);
    TableColumn<ChannelDisplayInfo, Boolean> col2 = new TableColumn<>("Selected");
    col2.setCellValueFactory(new Callback<CellDataFeatures<ChannelDisplayInfo, Boolean>, ObservableValue<Boolean>>() {

        @Override
        public ObservableValue<Boolean> call(CellDataFeatures<ChannelDisplayInfo, Boolean> item) {
            SimpleBooleanProperty property = new SimpleBooleanProperty(imageDisplay.selectedChannels().contains(item.getValue()));
            // Remove repaint code here - now handled by table selection changes
            property.addListener((v, o, n) -> {
                imageDisplay.setChannelSelected(item.getValue(), n);
                table.refresh();
                Platform.runLater(() -> viewer.repaintEntireImage());
            });
            return property;
        }
    });
    col2.setCellFactory(column -> {
        CheckBoxTableCell<ChannelDisplayInfo, Boolean> cell = new CheckBoxTableCell<>();
        // Select cells when clicked - means a click anywhere within the row forces selection.
        // Previously, clicking within the checkbox didn't select the row.
        cell.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
            if (e.isPopupTrigger())
                return;
            int ind = cell.getIndex();
            var tableView = cell.getTableView();
            if (ind < tableView.getItems().size()) {
                if (e.isShiftDown())
                    tableView.getSelectionModel().select(ind);
                else
                    tableView.getSelectionModel().clearAndSelect(ind);
                var channel = cell.getTableRow().getItem();
                // Handle clicks within the cell but outside the checkbox
                if (e.getTarget() == cell && channel != null && imageDisplay != null) {
                    updateDisplay(channel, !imageDisplay.selectedChannels().contains(channel));
                }
                e.consume();
            }
        });
        return cell;
    });
    col2.setSortable(false);
    col2.setEditable(true);
    col2.setResizable(false);
    // Handle color change requests when an appropriate row is double-clicked
    table.setRowFactory(tableView -> {
        TableRow<ChannelDisplayInfo> row = new TableRow<>();
        row.setOnMouseClicked(e -> {
            if (e.getClickCount() == 2) {
                ChannelDisplayInfo info = row.getItem();
                var imageData = viewer.getImageData();
                if (info instanceof DirectServerChannelInfo && imageData != null) {
                    DirectServerChannelInfo multiInfo = (DirectServerChannelInfo) info;
                    int c = multiInfo.getChannel();
                    var channel = imageData.getServer().getMetadata().getChannel(c);
                    Color color = ColorToolsFX.getCachedColor(multiInfo.getColor());
                    picker.setValue(color);
                    Dialog<ButtonType> colorDialog = new Dialog<>();
                    colorDialog.setTitle("Channel properties");
                    colorDialog.getDialogPane().getButtonTypes().setAll(ButtonType.APPLY, ButtonType.CANCEL);
                    var paneColor = new GridPane();
                    int r = 0;
                    var labelName = new Label("Channel name");
                    var tfName = new TextField(channel.getName());
                    labelName.setLabelFor(tfName);
                    PaneTools.addGridRow(paneColor, r++, 0, "Enter a name for the current channel", labelName, tfName);
                    var labelColor = new Label("Channel color");
                    labelColor.setLabelFor(picker);
                    PaneTools.addGridRow(paneColor, r++, 0, "Choose the color for the current channel", labelColor, picker);
                    paneColor.setVgap(5.0);
                    paneColor.setHgap(5.0);
                    colorDialog.getDialogPane().setContent(paneColor);
                    Optional<ButtonType> result = colorDialog.showAndWait();
                    if (result.orElse(ButtonType.CANCEL) == ButtonType.APPLY) {
                        // if (!DisplayHelpers.showMessageDialog("Choose channel color", picker))
                        // return;
                        String name = tfName.getText().trim();
                        if (name.isEmpty()) {
                            Dialogs.showErrorMessage("Set channel name", "The channel name must not be empty!");
                            return;
                        }
                        Color color2 = picker.getValue();
                        if (color == color2 && name.equals(channel.getName()))
                            return;
                        // Update the server metadata
                        int colorUpdated = ColorToolsFX.getRGB(color2);
                        if (imageData != null) {
                            var server = imageData.getServer();
                            var metadata = server.getMetadata();
                            var channels = new ArrayList<>(metadata.getChannels());
                            channels.set(c, ImageChannel.getInstance(name, colorUpdated));
                            var metadata2 = new ImageServerMetadata.Builder(metadata).channels(channels).build();
                            imageData.updateServerMetadata(metadata2);
                        }
                        // Update the display
                        multiInfo.setLUTColor((int) (color2.getRed() * 255), (int) (color2.getGreen() * 255), (int) (color2.getBlue() * 255));
                        // Add color property
                        imageDisplay.saveChannelColorProperties();
                        viewer.repaintEntireImage();
                        updateHistogram();
                        table.refresh();
                    }
                }
            }
        });
        return row;
    });
    table.getColumns().add(col1);
    table.getColumns().add(col2);
    table.setEditable(true);
    table.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);
    // Hack... space for a scrollbar
    col1.prefWidthProperty().bind(table.widthProperty().subtract(col2.widthProperty()).subtract(25));
    // col2.setResizable(false);
    // col2.setMaxWidth(100);
    // col2.setPrefWidth(50);
    // col2.setResizable(false);
    // col1.prefWidthProperty().bind(table.widthProperty().multiply(0.7));
    // col2.prefWidthProperty().bind(table.widthProperty().multiply(0.2));
    // table.getColumnModel().getColumn(0).setCellRenderer(new ChannelCellRenderer());
    // table.getColumnModel().getColumn(1).setMaxWidth(table.getColumnModel().getColumn(1).getPreferredWidth());
    BorderPane panelColor = new BorderPane();
    // panelColor.setBorder(BorderFactory.createTitledBorder("Color display"));
    BorderPane paneTableAndFilter = new BorderPane(table);
    TextField tfFilter = new TextField("");
    tfFilter.textProperty().bindBidirectional(filterText);
    tfFilter.setTooltip(new Tooltip("Enter text to find specific channels by name"));
    tfFilter.setPromptText("Filter channels by name");
    paneTableAndFilter.setBottom(tfFilter);
    predicate.addListener((v, o, n) -> updatePredicate());
    panelColor.setCenter(paneTableAndFilter);
    CheckBox cbShowGrayscale = new CheckBox("Show grayscale");
    cbShowGrayscale.selectedProperty().bindBidirectional(showGrayscale);
    cbShowGrayscale.setTooltip(new Tooltip("Show single channel with grayscale lookup table"));
    if (imageDisplay != null)
        cbShowGrayscale.setSelected(!imageDisplay.useColorLUTs());
    showGrayscale.addListener(o -> {
        if (imageDisplay == null)
            return;
        Platform.runLater(() -> viewer.repaintEntireImage());
        table.refresh();
    });
    CheckBox cbKeepDisplaySettings = new CheckBox("Keep settings");
    cbKeepDisplaySettings.selectedProperty().bindBidirectional(PathPrefs.keepDisplaySettingsProperty());
    cbKeepDisplaySettings.setTooltip(new Tooltip("Retain same display settings where possible when opening similar images"));
    FlowPane paneCheck = new FlowPane();
    paneCheck.getChildren().add(cbShowGrayscale);
    paneCheck.getChildren().add(cbKeepDisplaySettings);
    paneCheck.setHgap(10);
    paneCheck.setPadding(new Insets(5, 0, 0, 0));
    panelColor.setBottom(paneCheck);
    pane.setCenter(panelColor);
    // Create brightness/contrast panel
    BorderPane panelSliders = new BorderPane();
    panelSliders.setTop(box);
    GridPane panelButtons = PaneTools.createColumnGridControls(btnAuto, btnReset);
    panelSliders.setBottom(panelButtons);
    panelSliders.setPadding(new Insets(5, 0, 5, 0));
    BorderPane panelMinMax = new BorderPane();
    // panelMinMax.setBorder(BorderFactory.createTitledBorder("Brightness/Contrast"));
    panelMinMax.setTop(panelSliders);
    histogramPanel.setShowTickLabels(false);
    histogramPanel.getChart().setAnimated(false);
    // histogramPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    // panelMinMax.setCenter(histogramPanel.getChart());
    panelMinMax.setCenter(chartWrapper.getPane());
    chartWrapper.getPane().setPrefSize(200, 200);
    // histogramPanel.getChart().setPrefSize(200, 200);
    // histogramPanel.setPreferredSize(new Dimension(200, 120));
    pane.setBottom(panelMinMax);
    pane.setPadding(new Insets(10, 10, 10, 10));
    Scene scene = new Scene(pane, 350, 500);
    dialog.setScene(scene);
    dialog.setMinWidth(300);
    dialog.setMinHeight(400);
    dialog.setMaxWidth(600);
    dialog.setMaxHeight(800);
    updateTable();
    if (!table.getItems().isEmpty())
        table.getSelectionModel().select(0);
    updateDisplay(getCurrentInfo(), true);
    updateHistogram();
    updateSliders();
    // Update sliders when receiving focus - in case the display has been updated elsewhere
    dialog.focusedProperty().addListener((v, o, n) -> {
        if (n)
            updateSliders();
    });
    return dialog;
}
Also used : EventHandler(javafx.event.EventHandler) Button(javafx.scene.control.Button) ImageServer(qupath.lib.images.servers.ImageServer) LoggerFactory(org.slf4j.LoggerFactory) KeyCombination(javafx.scene.input.KeyCombination) ContextMenu(javafx.scene.control.ContextMenu) DirectServerChannelInfo(qupath.lib.display.DirectServerChannelInfo) TableView(javafx.scene.control.TableView) QuPathGUI(qupath.lib.gui.QuPathGUI) HistogramData(qupath.lib.gui.charts.HistogramPanelFX.HistogramData) TextField(javafx.scene.control.TextField) MenuItem(javafx.scene.control.MenuItem) BufferedImage(java.awt.image.BufferedImage) Predicate(java.util.function.Predicate) ObjectBinding(javafx.beans.binding.ObjectBinding) FilteredList(javafx.collections.transformation.FilteredList) Set(java.util.Set) Rectangle(javafx.scene.shape.Rectangle) ChannelDisplayInfo(qupath.lib.display.ChannelDisplayInfo) KeyEvent(javafx.scene.input.KeyEvent) Collectors(java.util.stream.Collectors) CellDataFeatures(javafx.scene.control.TableColumn.CellDataFeatures) Platform(javafx.application.Platform) Text(javafx.scene.text.Text) QuPathViewer(qupath.lib.gui.viewer.QuPathViewer) Priority(javafx.scene.layout.Priority) List(java.util.List) BooleanProperty(javafx.beans.property.BooleanProperty) PropertyChangeListener(java.beans.PropertyChangeListener) Clipboard(javafx.scene.input.Clipboard) FlowPane(javafx.scene.layout.FlowPane) CheckBoxTableCell(javafx.scene.control.cell.CheckBoxTableCell) ColorToolsFX(qupath.lib.gui.tools.ColorToolsFX) Optional(java.util.Optional) NumberAxis(javafx.scene.chart.NumberAxis) ClipboardContent(javafx.scene.input.ClipboardContent) BorderPane(javafx.scene.layout.BorderPane) StringProperty(javafx.beans.property.StringProperty) Scene(javafx.scene.Scene) TextArea(javafx.scene.control.TextArea) SimpleStringProperty(javafx.beans.property.SimpleStringProperty) ButtonType(javafx.scene.control.ButtonType) MouseEvent(javafx.scene.input.MouseEvent) FXCollections(javafx.collections.FXCollections) ImageChannel(qupath.lib.images.servers.ImageChannel) Bindings(javafx.beans.binding.Bindings) ImageDisplay(qupath.lib.display.ImageDisplay) ArrayList(java.util.ArrayList) TableColumn(javafx.scene.control.TableColumn) HashSet(java.util.HashSet) Dialogs(qupath.lib.gui.dialogs.Dialogs) TableCell(javafx.scene.control.TableCell) Insets(javafx.geometry.Insets) Slider(javafx.scene.control.Slider) HistogramPanelFX(qupath.lib.gui.charts.HistogramPanelFX) Callback(javafx.util.Callback) Tooltip(javafx.scene.control.Tooltip) PropertyChangeEvent(java.beans.PropertyChangeEvent) LinkedHashSet(java.util.LinkedHashSet) GridPane(javafx.scene.layout.GridPane) ColorPicker(javafx.scene.control.ColorPicker) ImageData(qupath.lib.images.ImageData) KeyCode(javafx.scene.input.KeyCode) Color(javafx.scene.paint.Color) Logger(org.slf4j.Logger) Dialog(javafx.scene.control.Dialog) Label(javafx.scene.control.Label) TableRow(javafx.scene.control.TableRow) DecimalFormat(java.text.DecimalFormat) CheckBox(javafx.scene.control.CheckBox) ThresholdedChartWrapper(qupath.lib.gui.charts.HistogramPanelFX.ThresholdedChartWrapper) KeyCodeCombination(javafx.scene.input.KeyCodeCombination) SimpleBooleanProperty(javafx.beans.property.SimpleBooleanProperty) SelectionMode(javafx.scene.control.SelectionMode) Stage(javafx.stage.Stage) SimpleObjectProperty(javafx.beans.property.SimpleObjectProperty) ObservableValue(javafx.beans.value.ObservableValue) Histogram(qupath.lib.analysis.stats.Histogram) ChangeListener(javafx.beans.value.ChangeListener) PathPrefs(qupath.lib.gui.prefs.PathPrefs) ImageServerMetadata(qupath.lib.images.servers.ImageServerMetadata) PaneTools(qupath.lib.gui.tools.PaneTools) CellDataFeatures(javafx.scene.control.TableColumn.CellDataFeatures) Label(javafx.scene.control.Label) ObservableValue(javafx.beans.value.ObservableValue) Rectangle(javafx.scene.shape.Rectangle) ArrayList(java.util.ArrayList) DirectServerChannelInfo(qupath.lib.display.DirectServerChannelInfo) Button(javafx.scene.control.Button) Dialog(javafx.scene.control.Dialog) Stage(javafx.stage.Stage) TextField(javafx.scene.control.TextField) FlowPane(javafx.scene.layout.FlowPane) ButtonType(javafx.scene.control.ButtonType) GridPane(javafx.scene.layout.GridPane) Tooltip(javafx.scene.control.Tooltip) Color(javafx.scene.paint.Color) Scene(javafx.scene.Scene) TableColumn(javafx.scene.control.TableColumn) CheckBox(javafx.scene.control.CheckBox) TableRow(javafx.scene.control.TableRow) BorderPane(javafx.scene.layout.BorderPane) SimpleBooleanProperty(javafx.beans.property.SimpleBooleanProperty) Insets(javafx.geometry.Insets) CheckBoxTableCell(javafx.scene.control.cell.CheckBoxTableCell) TableCell(javafx.scene.control.TableCell) CheckBoxTableCell(javafx.scene.control.cell.CheckBoxTableCell) Text(javafx.scene.text.Text) ChannelDisplayInfo(qupath.lib.display.ChannelDisplayInfo)

Aggregations

ImageData (qupath.lib.images.ImageData)32 BufferedImage (java.awt.image.BufferedImage)27 Collectors (java.util.stream.Collectors)26 Logger (org.slf4j.Logger)26 LoggerFactory (org.slf4j.LoggerFactory)26 List (java.util.List)25 ArrayList (java.util.ArrayList)23 IOException (java.io.IOException)21 PathObject (qupath.lib.objects.PathObject)21 File (java.io.File)19 Collection (java.util.Collection)19 Dialogs (qupath.lib.gui.dialogs.Dialogs)19 ImageServer (qupath.lib.images.servers.ImageServer)19 Collections (java.util.Collections)17 Map (java.util.Map)17 GeneralTools (qupath.lib.common.GeneralTools)17 QuPathGUI (qupath.lib.gui.QuPathGUI)17 Arrays (java.util.Arrays)16 PathPrefs (qupath.lib.gui.prefs.PathPrefs)15 Bindings (javafx.beans.binding.Bindings)14