Search in sources :

Example 26 with ParameterList

use of qupath.lib.plugins.parameters.ParameterList in project qupath by qupath.

the class ImageDetailsPane method editStainVector.

void editStainVector(Object value) {
    if (!(value instanceof StainVector || value instanceof double[]))
        return;
    // JOptionPane.showMessageDialog(null, "Modifying stain vectors not yet implemented...");
    ImageData<BufferedImage> imageData = qupath.getImageData();
    if (imageData == null)
        return;
    ColorDeconvolutionStains stains = imageData.getColorDeconvolutionStains();
    // Default to background values
    int num = -1;
    String name = null;
    String message = null;
    if (value instanceof StainVector) {
        StainVector stainVector = (StainVector) value;
        if (stainVector.isResidual() && imageData.getImageType() != ImageType.BRIGHTFIELD_OTHER) {
            logger.warn("Cannot set residual stain vector - this is computed from the known vectors");
            return;
        }
        num = stains.getStainNumber(stainVector);
        if (num <= 0) {
            logger.error("Could not identify stain vector " + stainVector + " inside " + stains);
            return;
        }
        name = stainVector.getName();
        message = "Set stain vector from ROI?";
    } else
        message = "Set color deconvolution background values from ROI?";
    ROI pathROI = imageData.getHierarchy().getSelectionModel().getSelectedROI();
    boolean wasChanged = false;
    String warningMessage = null;
    boolean editableName = imageData.getImageType() == ImageType.BRIGHTFIELD_OTHER;
    if (pathROI != null) {
        if ((pathROI instanceof RectangleROI) && !pathROI.isEmpty() && ((RectangleROI) pathROI).getArea() < 500 * 500) {
            if (Dialogs.showYesNoDialog("Color deconvolution stains", message)) {
                ImageServer<BufferedImage> server = imageData.getServer();
                BufferedImage img = null;
                try {
                    img = server.readBufferedImage(RegionRequest.createInstance(server.getPath(), 1, pathROI));
                } catch (IOException e) {
                    Dialogs.showErrorMessage("Set stain vector", "Unable to read image region");
                    logger.error("Unable to read region", e);
                }
                int rgb = ColorDeconvolutionHelper.getMedianRGB(img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth()));
                if (num >= 0) {
                    StainVector vectorValue = ColorDeconvolutionHelper.generateMedianStainVectorFromPixels(name, img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth()), stains.getMaxRed(), stains.getMaxGreen(), stains.getMaxBlue());
                    if (!Double.isFinite(vectorValue.getRed() + vectorValue.getGreen() + vectorValue.getBlue())) {
                        Dialogs.showErrorMessage("Set stain vector", "Cannot set stains for the current ROI!\n" + "It might be too close to the background color.");
                        return;
                    }
                    value = vectorValue;
                } else {
                    // Update the background
                    value = new double[] { ColorTools.red(rgb), ColorTools.green(rgb), ColorTools.blue(rgb) };
                }
                wasChanged = true;
            }
        } else {
            warningMessage = "Note: To set stain values from an image region, draw a small, rectangular ROI first";
        }
    }
    // Prompt to set the name / verify stains
    ParameterList params = new ParameterList();
    String title;
    String nameBefore = null;
    String valuesBefore = null;
    String collectiveNameBefore = stains.getName();
    String suggestedName;
    if (collectiveNameBefore.endsWith("default"))
        suggestedName = collectiveNameBefore.substring(0, collectiveNameBefore.lastIndexOf("default")) + "modified";
    else
        suggestedName = collectiveNameBefore;
    params.addStringParameter("collectiveName", "Collective name", suggestedName, "Enter collective name for all 3 stains (e.g. H-DAB Scanner A, H&E Scanner B)");
    if (value instanceof StainVector) {
        nameBefore = ((StainVector) value).getName();
        valuesBefore = ((StainVector) value).arrayAsString(Locale.getDefault(Category.FORMAT));
        params.addStringParameter("name", "Name", nameBefore, "Enter stain name").addStringParameter("values", "Values", valuesBefore, "Enter 3 values (red, green, blue) defining color deconvolution stain vector, separated by spaces");
        title = "Set stain vector";
    } else {
        nameBefore = "Background";
        valuesBefore = GeneralTools.arrayToString(Locale.getDefault(Category.FORMAT), (double[]) value, 2);
        params.addStringParameter("name", "Stain name", nameBefore);
        params.addStringParameter("values", "Stain values", valuesBefore, "Enter 3 values (red, green, blue) defining background, separated by spaces");
        params.setHiddenParameters(true, "name");
        title = "Set background";
    }
    if (warningMessage != null)
        params.addEmptyParameter(warningMessage);
    // Disable editing the name if it should be fixed
    ParameterPanelFX parameterPanel = new ParameterPanelFX(params);
    parameterPanel.setParameterEnabled("name", editableName);
    ;
    if (!Dialogs.showConfirmDialog(title, parameterPanel.getPane()))
        return;
    // Check if anything changed
    String collectiveName = params.getStringParameterValue("collectiveName");
    String nameAfter = params.getStringParameterValue("name");
    String valuesAfter = params.getStringParameterValue("values");
    if (collectiveName.equals(collectiveNameBefore) && nameAfter.equals(nameBefore) && valuesAfter.equals(valuesBefore) && !wasChanged)
        return;
    double[] valuesParsed = ColorDeconvolutionStains.parseStainValues(Locale.getDefault(Category.FORMAT), valuesAfter);
    if (valuesParsed == null) {
        logger.error("Input for setting color deconvolution information invalid! Cannot parse 3 numbers from {}", valuesAfter);
        return;
    }
    if (num >= 0) {
        try {
            stains = stains.changeStain(StainVector.createStainVector(nameAfter, valuesParsed[0], valuesParsed[1], valuesParsed[2]), num);
        } catch (Exception e) {
            logger.error("Error setting stain vectors", e);
            Dialogs.showErrorMessage("Set stain vectors", "Requested stain vectors are not valid!\nAre two stains equal?");
        }
    } else {
        // Update the background
        stains = stains.changeMaxValues(valuesParsed[0], valuesParsed[1], valuesParsed[2]);
    }
    // Set the collective name
    stains = stains.changeName(collectiveName);
    imageData.setColorDeconvolutionStains(stains);
    qupath.getViewer().repaintEntireImage();
}
Also used : StainVector(qupath.lib.color.StainVector) IOException(java.io.IOException) RectangleROI(qupath.lib.roi.RectangleROI) ROI(qupath.lib.roi.interfaces.ROI) BufferedImage(java.awt.image.BufferedImage) ParameterPanelFX(qupath.lib.gui.dialogs.ParameterPanelFX) IOException(java.io.IOException) RectangleROI(qupath.lib.roi.RectangleROI) ParameterList(qupath.lib.plugins.parameters.ParameterList) ColorDeconvolutionStains(qupath.lib.color.ColorDeconvolutionStains)

Example 27 with ParameterList

use of qupath.lib.plugins.parameters.ParameterList in project qupath by qupath.

the class WatershedCellDetection method buildParameterList.

private ParameterList buildParameterList(final ImageData<BufferedImage> imageData) {
    ParameterList params = new ParameterList();
    // TODO: Use a better way to determining if pixel size is available in microns
    // params.addEmptyParameter("detectionParameters", "Detection parameters", true);
    String microns = IJ.micronSymbol + "m";
    params.addTitleParameter("Setup parameters");
    String defaultChannel = null;
    List<String> channelNames = new ArrayList<>();
    String[] nucleusGuesses = new String[] { "dapi", "hoechst", "nucleus", "nuclei", "nuclear", "hematoxylin", "haematoxylin" };
    for (ImageChannel channel : imageData.getServer().getMetadata().getChannels()) {
        String name = channel.getName();
        channelNames.add(name);
        if (defaultChannel == null) {
            String lower = name.toLowerCase();
            for (String guess : nucleusGuesses) {
                if (lower.contains(guess))
                    defaultChannel = name;
            }
        }
    }
    if (defaultChannel == null)
        defaultChannel = channelNames.get(0);
    if (channelNames.size() != new HashSet<>(channelNames).size())
        logger.warn("Image contains duplicate channel names! This may be confusing for detection and analysis.");
    params.addChoiceParameter("detectionImage", "Detection channel", defaultChannel, channelNames, "Choose the channel that should be used for nucleus detection (e.g. DAPI)");
    params.addChoiceParameter("detectionImageBrightfield", "Detection image", IMAGE_HEMATOXYLIN, Arrays.asList(IMAGE_HEMATOXYLIN, IMAGE_OPTICAL_DENSITY), "Transformed image to which to apply the detection");
    params.addDoubleParameter("requestedPixelSizeMicrons", "Requested pixel size", .5, microns, "Choose pixel size at which detection will be performed - higher values are likely to be faster, but may be less accurate; set <= 0 to use the full image resolution");
    // params.addDoubleParameter("requestedPixelSize", "Requested downsample factor", 1, "");
    params.addTitleParameter("Nucleus parameters");
    params.addDoubleParameter("backgroundRadiusMicrons", "Background radius", 8, microns, "Radius for background estimation, should be > the largest nucleus radius, or <= 0 to turn off background subtraction");
    params.addDoubleParameter("medianRadiusMicrons", "Median filter radius", 0, microns, "Radius of median filter used to reduce image texture (optional)");
    params.addDoubleParameter("sigmaMicrons", "Sigma", 1.5, microns, "Sigma value for Gaussian filter used to reduce noise; increasing the value stops nuclei being fragmented, but may reduce the accuracy of boundaries");
    params.addDoubleParameter("minAreaMicrons", "Minimum area", 10, microns + "^2", "Detected nuclei with an area < minimum area will be discarded");
    params.addDoubleParameter("maxAreaMicrons", "Maximum area", 400, microns + "^2", "Detected nuclei with an area > maximum area will be discarded");
    params.addDoubleParameter("backgroundRadius", "Background radius", 15, "px", "Radius for background estimation, should be > the largest nucleus radius, or <= 0 to turn off background subtraction");
    params.addDoubleParameter("medianRadius", "Median filter radius", 0, "px", "Radius of median filter used to reduce image texture (optional)");
    params.addDoubleParameter("sigma", "Sigma", 3, "px", "Sigma value for Gaussian filter used to reduce noise; increasing the value stops nuclei being fragmented, but may reduce the accuracy of boundaries");
    params.addDoubleParameter("minArea", "Minimum area", 10, "px^2", "Detected nuclei with an area < minimum area will be discarded");
    params.addDoubleParameter("maxArea", "Maximum area", 1000, "px^2", "Detected nuclei with an area > maximum area will be discarded");
    params.addTitleParameter("Intensity parameters");
    params.addDoubleParameter("threshold", "Threshold", 0.1, null, "Intensity threshold - detected nuclei must have a mean intensity >= threshold");
    // params.addDoubleParameter("threshold", "Threshold", 0.1, null, 0, 2.5,
    // "Intensity threshold - detected nuclei must have a mean intensity >= threshold");
    params.addDoubleParameter("maxBackground", "Max background intensity", 2, null, "If background radius > 0, detected nuclei occurring on a background > max background intensity will be discarded");
    // params.addBooleanParameter("mergeAll", "Merge all", true);
    params.addBooleanParameter("watershedPostProcess", "Split by shape", true, "Split merged detected nuclei based on shape ('roundness')");
    params.addBooleanParameter("excludeDAB", "Exclude DAB (membrane staining)", false, "Set to 'true' if regions of high DAB staining should not be considered nuclei; useful if DAB stains cell membranes");
    params.addTitleParameter("Cell parameters");
    params.addDoubleParameter("cellExpansionMicrons", "Cell expansion", 5, microns, 0, 25, "Amount by which to expand detected nuclei to approximate the full cell area");
    params.addDoubleParameter("cellExpansion", "Cell expansion", 5, "px", "Amount by which to expand detected nuclei to approximate the full cell area");
    // params.addBooleanParameter("limitExpansionByNucleusSize", "Limit cell expansion by nucleus size", false, "If checked, nuclei will not be expanded by more than their (estimated) smallest diameter in any direction - may give more realistic results for smaller, or 'thinner' nuclei");
    params.addBooleanParameter("includeNuclei", "Include cell nucleus", true, "If cell expansion is used, optionally include/exclude the nuclei within the detected cells");
    params.addTitleParameter("General parameters");
    params.addBooleanParameter("smoothBoundaries", "Smooth boundaries", true, "Smooth the detected nucleus/cell boundaries");
    params.addBooleanParameter("makeMeasurements", "Make measurements", true, "Add default shape & intensity measurements during detection");
    return params;
}
Also used : ImageChannel(qupath.lib.images.servers.ImageChannel) ArrayList(java.util.ArrayList) ParameterList(qupath.lib.plugins.parameters.ParameterList) HashSet(java.util.HashSet)

Example 28 with ParameterList

use of qupath.lib.plugins.parameters.ParameterList in project qupath by qupath.

the class PositivePixelCounterIJ method getDefaultParameterList.

@Override
public ParameterList getDefaultParameterList(final ImageData<BufferedImage> imageData) {
    ColorDeconvolutionStains stains = imageData.getColorDeconvolutionStains();
    String stain1Name = stains == null ? "Hematoxylin" : stains.getStain(1).getName();
    String stain2Name = stains == null ? "DAB" : stains.getStain(2).getName();
    ParameterList params = new ParameterList().addIntParameter("downsampleFactor", "Downsample factor", 4, "", 1, 32, "Amount to downsample image prior to detection - higher values lead to smaller images (and faster but less accurate processing)").addDoubleParameter("gaussianSigmaMicrons", "Gaussian sigma", 2, GeneralTools.micrometerSymbol(), "Gaussian filter size - higher values give a smoother (less-detailed) result").addDoubleParameter("thresholdStain1", stain1Name + " threshold ('Negative')", 0.1, "OD units", "Threshold to use for 'Negative' detection").addDoubleParameter("thresholdStain2", stain2Name + " threshold ('Positive')", 0.3, "OD units", "Threshold to use for 'Positive' stain detection").addBooleanParameter("addSummaryMeasurements", "Add summary measurements to parent", true, "Add summary measurements to parent objects").addBooleanParameter("clearParentMeasurements", "Clear existing parent measurements", true, "Remove any existing measurements from parent objects").addBooleanParameter("appendDetectionParameters", "Add parameters to measurement names", false, "Append the detection parameters to any measurement names").addBooleanParameter("legacyMeasurements0.1.2", "Use legacy measurements (v0.1.2)", false, "Generate measurements compatible with QuPath v0.1.2");
    return params;
}
Also used : ParameterList(qupath.lib.plugins.parameters.ParameterList) ColorDeconvolutionStains(qupath.lib.color.ColorDeconvolutionStains)

Example 29 with ParameterList

use of qupath.lib.plugins.parameters.ParameterList in project qupath by qupath.

the class LoadResourceCommand method run.

@Override
public void run() {
    String title = resourceType.getDialogTitle();
    var cachedServers = new WeakHashMap<ImageData<BufferedImage>, ImageServer<BufferedImage>>();
    var overlay = PixelClassificationOverlay.create(qupath.getOverlayOptions(), cachedServers, new ColorModelRenderer(null));
    overlay.setMaxThreads(nThreads);
    for (var viewer : qupath.getViewers()) viewer.setCustomPixelLayerOverlay(overlay);
    var comboClassifiers = new ComboBox<String>();
    try {
        updateAvailableItems(comboClassifiers.getItems());
    } catch (IOException e) {
        logger.error(e.getLocalizedMessage(), e);
    }
    var selectedResource = Bindings.createObjectBinding(() -> {
        String name = comboClassifiers.getSelectionModel().getSelectedItem();
        cachedServers.clear();
        if (name != null) {
            try {
                var project = qupath.getProject();
                var manager = resourceType.getManager(project);
                S resource;
                if (manager != null && manager.contains(name))
                    resource = manager.get(name);
                else
                    resource = extras.get(name);
                if (resource instanceof UriResource) {
                    UriUpdater.fixUris((UriResource) resource, project);
                }
                return resource;
            } catch (Exception ex) {
                // TODO: Investigate why this is triggered twice
                Dialogs.showErrorNotification(resourceType.getDialogTitle(), ex);
            }
        }
        return null;
    }, comboClassifiers.getSelectionModel().selectedItemProperty());
    var label = new Label(resourceType.choosePrompt());
    label.setLabelFor(comboClassifiers);
    selectedResource.addListener((v, o, n) -> {
        cachedServers.clear();
        updateServers(n, cachedServers);
    });
    // Add file chooser
    var menu = new ContextMenu();
    var miLoadClassifier = new MenuItem("Import from files");
    miLoadClassifier.setOnAction(e -> {
        List<File> files = Dialogs.promptForMultipleFiles(title, null, resourceType.filePrompt(), "json");
        if (files == null || files.isEmpty())
            return;
        try {
            addExternalJson(files, resourceType.getManager(qupath.getProject()), extras);
            updateAvailableItems(comboClassifiers.getItems());
        } catch (IOException ex) {
            Dialogs.showErrorMessage(title, ex);
        }
    });
    var miOpenAsText = new MenuItem("Show as text");
    miOpenAsText.setOnAction(e -> {
        var name = comboClassifiers.getSelectionModel().getSelectedItem();
        var resource = selectedResource.get();
        if (resource == null)
            return;
        try {
            // Pass the resource class, since it can be required for including the appropriate JSON properties
            var json = GsonTools.getInstance(true).toJson(resource, resourceType.getResourceClass());
            if (!name.endsWith(".json"))
                name = name + ".json";
            // Show in script editor if possible; this may include better formatting and syntax highlighting
            var scriptEditor = qupath == null ? null : qupath.getScriptEditor();
            if (scriptEditor != null)
                scriptEditor.showScript(name, json);
            else
                Dialogs.showTextWindow(qupath.getStage(), name, json, Modality.NONE, false);
        } catch (Exception ex) {
            Dialogs.showErrorMessage("Show model as text", "Unable to create a text representation of '" + name + "', sorry!");
        }
    });
    miOpenAsText.disableProperty().bind(selectedResource.isNull());
    // Enable setting number of threads
    var miThreads = new MenuItem("Set parallel threads");
    miThreads.setOnAction(e -> {
        var params = new ParameterList().addIntParameter("nThreads", "Number of parallel threads", nThreads, null, "Number of threads to use for live prediction");
        if (!Dialogs.showParameterDialog("Set parallel threads", params))
            return;
        // var result = Dialogs.showInputDialog("Set parallel threads", "Number of threads to use for live prediction", (double)nThreads);
        var val = params.getIntParameterValue("nThreads");
        if (val == nThreads)
            return;
        if (val < 0)
            nThreads = PathPrefs.numCommandThreadsProperty().get();
        else
            nThreads = Math.max(1, val);
        if (overlay != null)
            overlay.setMaxThreads(nThreads);
    });
    menu.getItems().addAll(miLoadClassifier, miOpenAsText, new SeparatorMenuItem(), miThreads);
    var btnLoadExistingClassifier = GuiTools.createMoreButton(menu, Side.RIGHT);
    var classifierName = new SimpleStringProperty(null);
    classifierName.bind(comboClassifiers.getSelectionModel().selectedItemProperty());
    var pane = new GridPane();
    pane.setPadding(new Insets(10.0));
    pane.setHgap(5);
    pane.setVgap(10);
    pane.setPrefWidth(350.0);
    int row = 0;
    PaneTools.addGridRow(pane, row++, 0, "Choose model to apply to the current image", label, comboClassifiers, btnLoadExistingClassifier);
    PaneTools.setToExpandGridPaneWidth(comboClassifiers);
    if (resourceType.getResourceClass().equals(PixelClassifier.class)) {
        var labelRegion = new Label("Region");
        var comboRegionFilter = PixelClassifierUI.createRegionFilterCombo(qupath.getOverlayOptions());
        @SuppressWarnings("unchecked") var tilePane = PixelClassifierUI.createPixelClassifierButtons(qupath.imageDataProperty(), (ObjectExpression<PixelClassifier>) selectedResource, classifierName);
        PaneTools.addGridRow(pane, row++, 0, "Control where the pixel classification is applied during preview", labelRegion, comboRegionFilter, comboRegionFilter);
        PaneTools.addGridRow(pane, row++, 0, "Apply pixel classification", tilePane, tilePane, tilePane);
        PaneTools.setToExpandGridPaneWidth(tilePane);
    } else if (resourceType.getResourceClass().equals(DensityMapBuilder.class)) {
        @SuppressWarnings("unchecked") var buttonPane = DensityMapUI.createButtonPane(qupath, qupath.imageDataProperty(), (ObjectExpression<DensityMapBuilder>) selectedResource, classifierName, Bindings.createObjectBinding(() -> overlay), false);
        PaneTools.addGridRow(pane, row++, 0, null, buttonPane, buttonPane, buttonPane);
        PaneTools.setToExpandGridPaneWidth(buttonPane);
    }
    // Handle drag and drop
    pane.setOnDragOver(e -> {
        e.acceptTransferModes(TransferMode.COPY);
        e.consume();
    });
    pane.setOnDragDropped(e -> {
        logger.trace("File(s) dragged onto pane");
        Dragboard dragboard = e.getDragboard();
        if (dragboard.hasFiles()) {
            try {
                addExternalJson(dragboard.getFiles(), resourceType.getManager(qupath.getProject()), extras);
                updateAvailableItems(comboClassifiers.getItems());
            } catch (Exception ex) {
                Dialogs.showErrorMessage(title, ex);
            }
        }
    });
    var stage = new Stage();
    stage.setTitle(title);
    stage.setScene(new Scene(pane));
    stage.initOwner(qupath.getStage());
    stage.sizeToScene();
    stage.setResizable(false);
    stage.show();
    stage.setOnHiding(e -> {
        if (overlay != null)
            overlay.stop();
        logger.debug("Resetting overlay");
        for (var viewer : qupath.getViewers()) {
            if (viewer.getCustomPixelLayerOverlay() == overlay)
                viewer.resetCustomPixelLayerOverlay();
        }
    });
    stage.focusedProperty().addListener((v, o, n) -> {
        if (n && overlay != null) {
            for (var viewer : qupath.getViewers()) viewer.setCustomPixelLayerOverlay(overlay);
        }
        // Make sure we have all the servers we need - but don't reset existing ones
        updateServers(selectedResource.get(), cachedServers);
    });
    overlay.setLivePrediction(true);
}
Also used : UriResource(qupath.lib.io.UriResource) Insets(javafx.geometry.Insets) Label(javafx.scene.control.Label) ContextMenu(javafx.scene.control.ContextMenu) BufferedImage(java.awt.image.BufferedImage) Stage(javafx.stage.Stage) Dragboard(javafx.scene.input.Dragboard) GridPane(javafx.scene.layout.GridPane) ComboBox(javafx.scene.control.ComboBox) DensityMapBuilder(qupath.lib.analysis.heatmaps.DensityMaps.DensityMapBuilder) MenuItem(javafx.scene.control.MenuItem) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) IOException(java.io.IOException) SimpleStringProperty(javafx.beans.property.SimpleStringProperty) SeparatorMenuItem(javafx.scene.control.SeparatorMenuItem) Scene(javafx.scene.Scene) IOException(java.io.IOException) ColorModelRenderer(qupath.lib.gui.images.stores.ColorModelRenderer) PixelClassifier(qupath.lib.classifiers.pixel.PixelClassifier) ParameterList(qupath.lib.plugins.parameters.ParameterList) File(java.io.File) ObjectExpression(javafx.beans.binding.ObjectExpression) WeakHashMap(java.util.WeakHashMap)

Example 30 with ParameterList

use of qupath.lib.plugins.parameters.ParameterList in project qupath by qupath.

the class CreateTrainingImageCommand method promptToCreateTrainingImage.

/**
 * Prompt to create a training image, based upon annotations throughout a project.
 * @param project
 * @param availableClasses
 * @return the entry of the new training image, created within the project
 */
public static ProjectImageEntry<BufferedImage> promptToCreateTrainingImage(Project<BufferedImage> project, List<PathClass> availableClasses) {
    if (project == null) {
        Dialogs.showErrorMessage(NAME, "You need a project!");
        return null;
    }
    if (availableClasses.isEmpty()) {
        Dialogs.showErrorMessage(NAME, "Please ensure classifications are available in QuPath!");
        return null;
    }
    List<PathClass> pathClasses = new ArrayList<>(availableClasses);
    if (!pathClasses.contains(pathClass))
        pathClass = pathClasses.get(0);
    var params = new ParameterList().addEmptyParameter("Generates a single image from regions extracted from the project.").addEmptyParameter("Before running this command, add classified rectangle annotations to select the regions.").addChoiceParameter("pathClass", "Classification", pathClass, pathClasses, "Select classification for annotated regions").addIntParameter("maxWidth", "Preferred image width", maxWidth, "px", "Preferred maximum width of the training image, in pixels").addBooleanParameter("doZ", "Do z-stacks", doZ, "Take all slices of a z-stack, where possible").addBooleanParameter("rectanglesOnly", "Rectangles only", rectanglesOnly, "Only extract regions annotated with rectangles. Otherwise, the bounding box of all regions with the classification will be taken.").addEmptyParameter("Note this command requires images to have similar bit-depths/channels/pixel sizes for compatibility.");
    if (!Dialogs.showParameterDialog(NAME, params))
        return null;
    pathClass = (PathClass) params.getChoiceParameterValue("pathClass");
    maxWidth = params.getIntParameterValue("maxWidth");
    doZ = params.getBooleanParameterValue("doZ");
    rectanglesOnly = params.getBooleanParameterValue("rectanglesOnly");
    var task = new Task<SparseImageServer>() {

        @Override
        protected SparseImageServer call() throws Exception {
            return createSparseServer(project, pathClass, maxWidth, doZ, rectanglesOnly);
        }
    };
    var dialog = new ProgressDialog(task);
    dialog.setTitle(NAME);
    dialog.setHeaderText("Creating training image...");
    Executors.newSingleThreadExecutor().submit(task);
    dialog.showAndWait();
    try {
        var server = task.get();
        // var server = createSparseServer(project, pathClass, maxWidth, doZ, rectanglesOnly);
        if (server == null || server.getManager().getRegions().isEmpty()) {
            Dialogs.showErrorMessage("Sparse image server", "No suitable annotations found in the current project!");
            return null;
        }
        var entry = ProjectCommands.addSingleImageToProject(project, server, null);
        server.close();
        project.syncChanges();
        return entry;
    } catch (Exception e) {
        Dialogs.showErrorMessage("Sparse image server", e);
        return null;
    }
}
Also used : PathClass(qupath.lib.objects.classes.PathClass) Task(javafx.concurrent.Task) ArrayList(java.util.ArrayList) ParameterList(qupath.lib.plugins.parameters.ParameterList) ProgressDialog(org.controlsfx.dialog.ProgressDialog) IOException(java.io.IOException)

Aggregations

ParameterList (qupath.lib.plugins.parameters.ParameterList)53 BufferedImage (java.awt.image.BufferedImage)15 ArrayList (java.util.ArrayList)13 IOException (java.io.IOException)11 List (java.util.List)9 Collectors (java.util.stream.Collectors)8 BorderPane (javafx.scene.layout.BorderPane)8 PathObject (qupath.lib.objects.PathObject)8 Logger (org.slf4j.Logger)7 LoggerFactory (org.slf4j.LoggerFactory)7 GeneralTools (qupath.lib.common.GeneralTools)7 Dialogs (qupath.lib.gui.dialogs.Dialogs)7 ImageServer (qupath.lib.images.servers.ImageServer)7 Insets (javafx.geometry.Insets)6 Tooltip (javafx.scene.control.Tooltip)6 Collection (java.util.Collection)5 Map (java.util.Map)5 SimpleStringProperty (javafx.beans.property.SimpleStringProperty)5 ContextMenu (javafx.scene.control.ContextMenu)5 Label (javafx.scene.control.Label)5