Search in sources :

Example 6 with ROI

use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.

the class SpecifyAnnotationCommand method init.

private void init() {
    pane = new GridPane();
    int row = 0;
    var cbMicrons = new CheckBox("Use " + GeneralTools.micrometerSymbol());
    var units = Bindings.createStringBinding(() -> {
        if (cbMicrons.isSelected())
            return GeneralTools.micrometerSymbol();
        return "px";
    }, cbMicrons.selectedProperty());
    var comboType = new ComboBox<ROI_TYPE>(FXCollections.observableArrayList(ROI_TYPE.values()));
    comboType.setMaxWidth(Double.MAX_VALUE);
    comboType.getSelectionModel().select(ROI_TYPE.RECTANGLE);
    PaneTools.addGridRow(pane, row++, 0, "Type of ROI to create", createLabelFor(comboType, "Type"), comboType, comboType);
    var comboClassification = new ComboBox<>(qupath.getAvailablePathClasses());
    comboClassification.setMaxWidth(Double.MAX_VALUE);
    comboClassification.setCellFactory(o -> {
        return new ClassificationCell();
    });
    // comboClassification.cell;
    PaneTools.addGridRow(pane, row++, 0, "Classification for the annotation (may be empty if annotation should be unclassified)", createLabelFor(comboClassification, "Classification"), comboClassification, comboClassification);
    var tfX = new TextField("");
    var tfY = new TextField("");
    var tfWidth = new TextField("1000");
    var tfHeight = new TextField("1000");
    tfX.setPrefColumnCount(10);
    tfY.setPrefColumnCount(10);
    tfWidth.setPrefColumnCount(10);
    tfHeight.setPrefColumnCount(10);
    PaneTools.addGridRow(pane, row++, 0, "X-coordinate of top left of annotation bounding box (if missing or < 0, annotation will be centered in current viewer)", createLabelFor(tfX, "X origin"), tfX, createBoundLabel(units));
    PaneTools.addGridRow(pane, row++, 0, "Y-coordinate of top left of annotation bounding box (if missing or < 0, annotation will be centered in current viewer)", createLabelFor(tfY, "Y origin"), tfY, createBoundLabel(units));
    PaneTools.addGridRow(pane, row++, 0, "Width of annotation bounding box (must be > 0)", createLabelFor(tfWidth, "Width"), tfWidth, createBoundLabel(units));
    PaneTools.addGridRow(pane, row++, 0, "Height of annotation bounding box (must be > 0)", createLabelFor(tfHeight, "Height"), tfHeight, createBoundLabel(units));
    cbMicrons.setMaxWidth(Double.MAX_VALUE);
    PaneTools.addGridRow(pane, row++, 0, "Specify coordinates in " + GeneralTools.micrometerSymbol() + " - pixel calibration information must be available", cbMicrons, cbMicrons, cbMicrons);
    var cbLock = new CheckBox("Set locked");
    cbLock.setMaxWidth(Double.MAX_VALUE);
    PaneTools.addGridRow(pane, row++, 0, "Set annotation as locked, so that it can't be immediately edited", cbLock, cbLock, cbLock);
    var tfName = new TextField("");
    PaneTools.addGridRow(pane, row++, 0, "Name of annotation (can be empty)", createLabelFor(tfName, "Name"), tfName, tfName);
    var btnAdd = new Button("Add annotation");
    btnAdd.setOnAction(e -> {
        var viewer = qupath.getViewer();
        var imageData = viewer == null ? null : viewer.getImageData();
        if (imageData == null) {
            Dialogs.showNoImageError("Create annotation");
            return;
        }
        var server = imageData.getServer();
        var hierarchy = imageData.getHierarchy();
        double xScale = 1;
        double yScale = 1;
        PixelCalibration cal = server.getPixelCalibration();
        if (cbMicrons.isSelected()) {
            if (!cal.hasPixelSizeMicrons()) {
                Dialogs.showErrorMessage("Create annotation", "No pixel size information available! Try again using pixel units.");
                return;
            }
            xScale = 1.0 / cal.getPixelWidthMicrons();
            yScale = 1.0 / cal.getPixelHeightMicrons();
        }
        var xOrig = tryToParse(tfX.getText());
        var yOrig = tryToParse(tfY.getText());
        var width = tryToParse(tfWidth.getText());
        var height = tryToParse(tfHeight.getText());
        if (width == null || width.doubleValue() <= 0 || height == null || height.doubleValue() <= 0) {
            Dialogs.showErrorMessage("Create annotation", "Width and height must be specified, and > 0!");
            return;
        }
        double w = width.doubleValue() * xScale;
        double h = height.doubleValue() * yScale;
        // It helps to start at integer pixels, since otherwise the width can be surprising when exporting regions
        // (since when requesting ROIs, Math.ceil is currently applied to ensure that the full ROI is included).
        double x;
        if (xOrig == null || xOrig.doubleValue() < 0)
            x = (int) Math.max(0, viewer.getCenterPixelX() - w / 2.0);
        else
            x = xOrig.doubleValue() * xScale;
        double y;
        if (yOrig == null || yOrig.doubleValue() < 0)
            y = (int) Math.max(viewer.getCenterPixelY() - h / 2.0, 0);
        else
            y = yOrig.doubleValue() * yScale;
        if (x + w > server.getWidth() || y + h > server.getHeight()) {
            Dialogs.showErrorMessage("Create annotation", "Specified annotation is too large for the image bounds!");
            return;
        }
        int z = viewer.getZPosition();
        int t = viewer.getTPosition();
        ROI roi = null;
        switch(comboType.getSelectionModel().getSelectedItem()) {
            case ELLIPSE:
                roi = ROIs.createEllipseROI(x, y, w, h, ImagePlane.getPlane(z, t));
                break;
            case RECTANGLE:
                roi = ROIs.createRectangleROI(x, y, w, h, ImagePlane.getPlane(z, t));
                break;
            default:
                Dialogs.showErrorMessage("Create annotation", "No ROI type selected!");
                return;
        }
        var pathClass = comboClassification.getSelectionModel().getSelectedItem();
        if (pathClass != null && !pathClass.isValid())
            pathClass = null;
        var annotation = PathObjects.createAnnotationObject(roi, pathClass);
        // Set name, if necessary
        var name = tfName.getText();
        if (name != null && !name.isEmpty())
            annotation.setName(name);
        if (cbLock.isSelected())
            ((PathAnnotationObject) annotation).setLocked(true);
        hierarchy.addPathObject(annotation);
    });
    btnAdd.setMaxWidth(Double.MAX_VALUE);
    PaneTools.addGridRow(pane, row++, 0, "Create annotation with specified options & add to object hierarchy", btnAdd, btnAdd, btnAdd);
    PaneTools.setFillWidth(Boolean.TRUE, tfX, tfY, tfWidth, tfHeight, btnAdd, comboType);
    PaneTools.setHGrowPriority(Priority.ALWAYS, tfX, tfY, tfWidth, tfHeight, btnAdd, comboType);
    pane.setHgap(5);
    pane.setVgap(5);
    pane.setPadding(new Insets(10));
}
Also used : GridPane(javafx.scene.layout.GridPane) Insets(javafx.geometry.Insets) Button(javafx.scene.control.Button) CheckBox(javafx.scene.control.CheckBox) ComboBox(javafx.scene.control.ComboBox) TextField(javafx.scene.control.TextField) PixelCalibration(qupath.lib.images.servers.PixelCalibration) ROI(qupath.lib.roi.interfaces.ROI)

Example 7 with ROI

use of qupath.lib.roi.interfaces.ROI 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 8 with ROI

use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.

the class TMAGridView method initializeData.

private void initializeData(ImageData<BufferedImage> imageData) {
    if (this.imageData != imageData) {
        if (this.imageData != null)
            this.imageData.getHierarchy().removePathObjectListener(this);
        this.imageData = imageData;
        if (imageData != null) {
            imageData.getHierarchy().addPathObjectListener(this);
        }
    }
    if (imageData == null || imageData.getHierarchy().getTMAGrid() == null) {
        model.setImageData(null, Collections.emptyList());
        grid.getItems().clear();
        return;
    }
    // Request all core thumbnails now
    List<TMACoreObject> cores = imageData.getHierarchy().getTMAGrid().getTMACoreList();
    ImageServer<BufferedImage> server = imageData.getServer();
    CountDownLatch latch = new CountDownLatch(cores.size());
    for (TMACoreObject core : cores) {
        ROI roi = core.getROI();
        if (roi != null) {
            qupath.submitShortTask(() -> {
                RegionRequest request = createRegionRequest(core);
                if (cache.containsKey(request)) {
                    latch.countDown();
                    return;
                }
                BufferedImage img;
                try {
                    img = server.readBufferedImage(request);
                } catch (IOException e) {
                    logger.debug("Unable to get tile for " + request, e);
                    latch.countDown();
                    return;
                }
                Image imageNew = SwingFXUtils.toFXImage(img, null);
                if (imageNew != null) {
                    cache.put(request, imageNew);
                // Platform.runLater(() -> updateGridDisplay());
                }
                latch.countDown();
            });
        } else
            latch.countDown();
    }
    long startTime = System.currentTimeMillis();
    try {
        latch.await(10, TimeUnit.SECONDS);
    } catch (InterruptedException e1) {
        if (latch.getCount() > 0)
            logger.warn("Loaded {} cores in 10 seconds", cores.size() - latch.getCount());
    }
    logger.info("Countdown complete in {} seconds", (System.currentTimeMillis() - startTime) / 1000.0);
    model.setImageData(imageData, cores);
    backingList.setAll(cores);
    String m = measurement.getValue();
    sortCores(backingList, model, m, descending.get());
    filteredList.setPredicate(p -> {
        return !(p.isMissing() || Double.isNaN(model.getNumericValue(p, m)));
    });
    grid.getItems().setAll(filteredList);
}
Also used : TMACoreObject(qupath.lib.objects.TMACoreObject) IOException(java.io.IOException) CountDownLatch(java.util.concurrent.CountDownLatch) BufferedImage(java.awt.image.BufferedImage) Image(javafx.scene.image.Image) ROI(qupath.lib.roi.interfaces.ROI) RegionRequest(qupath.lib.regions.RegionRequest) BufferedImage(java.awt.image.BufferedImage)

Example 9 with ROI

use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.

the class EstimateStainVectorsCommand method promptToEstimateStainVectors.

public static void promptToEstimateStainVectors(ImageData<BufferedImage> imageData) {
    if (imageData == null) {
        Dialogs.showNoImageError(TITLE);
        return;
    }
    if (imageData == null || !imageData.isBrightfield() || imageData.getServer() == null || !imageData.getServer().isRGB()) {
        Dialogs.showErrorMessage(TITLE, "No brightfield, RGB image selected!");
        return;
    }
    ColorDeconvolutionStains stains = imageData.getColorDeconvolutionStains();
    if (stains == null || !stains.getStain(3).isResidual()) {
        Dialogs.showErrorMessage(TITLE, "Sorry, stain editing is only possible for brightfield, RGB images with 2 stains");
        return;
    }
    PathObject pathObject = imageData.getHierarchy().getSelectionModel().getSelectedObject();
    ROI roi = pathObject == null ? null : pathObject.getROI();
    if (roi == null)
        roi = ROIs.createRectangleROI(0, 0, imageData.getServer().getWidth(), imageData.getServer().getHeight(), ImagePlane.getDefaultPlane());
    double downsample = Math.max(1, Math.sqrt((roi.getBoundsWidth() * roi.getBoundsHeight()) / MAX_PIXELS));
    RegionRequest request = RegionRequest.createInstance(imageData.getServerPath(), downsample, roi);
    BufferedImage img = null;
    try {
        img = imageData.getServer().readBufferedImage(request);
    } catch (IOException e) {
        Dialogs.showErrorMessage("Estimate stain vectors", e);
        logger.error("Unable to obtain pixels for " + request.toString(), e);
    }
    // Apply small amount of smoothing to reduce compression artefacts
    img = EstimateStainVectors.smoothImage(img);
    // Check modes for background
    int[] rgb = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth());
    int[] rgbMode = EstimateStainVectors.getModeRGB(rgb);
    int rMax = rgbMode[0];
    int gMax = rgbMode[1];
    int bMax = rgbMode[2];
    // Check if the background values may need to be changed
    if (rMax != stains.getMaxRed() || gMax != stains.getMaxGreen() || bMax != stains.getMaxBlue()) {
        DialogButton response = Dialogs.showYesNoCancelDialog(TITLE, String.format("Modal RGB values %d, %d, %d do not match current background values - do you want to use the modal values?", rMax, gMax, bMax));
        if (response == DialogButton.CANCEL)
            return;
        else if (response == DialogButton.YES) {
            stains = stains.changeMaxValues(rMax, gMax, bMax);
            imageData.setColorDeconvolutionStains(stains);
        }
    }
    ColorDeconvolutionStains stainsUpdated = null;
    logger.info("Requesting region for stain vector editing: ", request);
    try {
        stainsUpdated = showStainEditor(img, stains);
    } catch (Exception e) {
        Dialogs.showErrorMessage(TITLE, "Error with stain estimation: " + e.getLocalizedMessage());
        logger.error("{}", e.getLocalizedMessage(), e);
        // JOptionPane.showMessageDialog(qupath.getFrame(), "Error with stain estimation: " + e.getLocalizedMessage(), "Estimate stain vectors", JOptionPane.ERROR_MESSAGE, null);
        return;
    }
    if (!stains.equals(stainsUpdated)) {
        String suggestedName;
        String collectiveNameBefore = stainsUpdated.getName();
        if (collectiveNameBefore.endsWith("default"))
            suggestedName = collectiveNameBefore.substring(0, collectiveNameBefore.lastIndexOf("default")) + "estimated";
        else
            suggestedName = collectiveNameBefore;
        String newName = Dialogs.showInputDialog(TITLE, "Set name for stain vectors", suggestedName);
        if (newName == null)
            return;
        if (!newName.isBlank())
            stainsUpdated = stainsUpdated.changeName(newName);
        imageData.setColorDeconvolutionStains(stainsUpdated);
    }
}
Also used : DialogButton(qupath.lib.gui.dialogs.Dialogs.DialogButton) PathObject(qupath.lib.objects.PathObject) IOException(java.io.IOException) ROI(qupath.lib.roi.interfaces.ROI) RegionRequest(qupath.lib.regions.RegionRequest) BufferedImage(java.awt.image.BufferedImage) IOException(java.io.IOException) ColorDeconvolutionStains(qupath.lib.color.ColorDeconvolutionStains)

Example 10 with ROI

use of qupath.lib.roi.interfaces.ROI in project qupath by qupath.

the class AbstractTileableDetectionPlugin method addRunnableTasks.

/**
 * Intercepts the 'standard' addRunnableTasks to (if necessary) insert ParallelTileObjects along the way,
 * thereby breaking an excessively-large parentObject into more manageable pieces.
 * <p>
 * TODO: Avoid hard-coding what is considered a 'manageable size' or a preferred size for parallel tiles.
 */
@Override
protected void addRunnableTasks(ImageData<T> imageData, PathObject parentObject, List<Runnable> tasks) {
    if (imageData == null)
        return;
    ParameterList params = getParameterList(imageData);
    // Determine appropriate sizes
    // Note, for v0.1.2 and earlier the downsample was restricted to be a power of 2
    double downsampleFactor = ServerTools.getDownsampleFactor(imageData.getServer(), getPreferredPixelSizeMicrons(imageData, params));
    int preferred = (int) (PREFERRED_TILE_SIZE * downsampleFactor);
    int max = (int) (MAX_TILE_SIZE * downsampleFactor);
    ImmutableDimension sizePreferred = ImmutableDimension.getInstance(preferred, preferred);
    ImmutableDimension sizeMax = ImmutableDimension.getInstance(max, max);
    // parentObject.clearPathObjects();
    // Extract (or create) suitable ROI
    ROI parentROI = parentObject.getROI();
    if (parentROI == null)
        parentROI = ROIs.createRectangleROI(0, 0, imageData.getServer().getWidth(), imageData.getServer().getHeight(), ImagePlane.getDefaultPlane());
    // Make tiles
    Collection<? extends ROI> pathROIs = RoiTools.computeTiledROIs(parentROI, sizePreferred, sizeMax, false, getTileOverlap(imageData, params));
    // No tasks to complete
    if (pathROIs.isEmpty())
        return;
    // // Exactly one task to complete
    // if (pathROIs.size() == 1 && pathROIs.iterator().next() == parentObject.getROI()) {
    // tasks.add(DetectionPluginTools.createRunnableTask(createDetector(imageData, params), getParameterList(imageData), imageData, parentObject));
    // return;
    // }
    ParallelDetectionTileManager manager = new ParallelDetectionTileManager(parentObject);
    List<ParallelTileObject> tileList = new ArrayList<>();
    AtomicInteger countdown = new AtomicInteger(pathROIs.size());
    for (ROI pathROI : pathROIs) {
        ParallelTileObject tile = new ParallelTileObject(manager, pathROI, imageData.getHierarchy(), countdown);
        parentObject.addPathObject(tile);
        for (ParallelTileObject tileTemp : tileList) {
            if (tileTemp.suggestNeighbor(tile))
                tile.suggestNeighbor(tileTemp);
        }
        tileList.add(tile);
        tasks.add(DetectionPluginTools.createRunnableTask(createDetector(imageData, params), params, imageData, tile));
    }
    manager.setTiles(tileList);
    imageData.getHierarchy().fireHierarchyChangedEvent(this);
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ArrayList(java.util.ArrayList) ParameterList(qupath.lib.plugins.parameters.ParameterList) ImmutableDimension(qupath.lib.geom.ImmutableDimension) ROI(qupath.lib.roi.interfaces.ROI)

Aggregations

ROI (qupath.lib.roi.interfaces.ROI)87 PathObject (qupath.lib.objects.PathObject)61 ArrayList (java.util.ArrayList)31 BufferedImage (java.awt.image.BufferedImage)24 PathObjectHierarchy (qupath.lib.objects.hierarchy.PathObjectHierarchy)24 IOException (java.io.IOException)20 RegionRequest (qupath.lib.regions.RegionRequest)19 List (java.util.List)17 Collectors (java.util.stream.Collectors)17 RectangleROI (qupath.lib.roi.RectangleROI)17 Logger (org.slf4j.Logger)16 LoggerFactory (org.slf4j.LoggerFactory)16 PolygonROI (qupath.lib.roi.PolygonROI)16 PathAnnotationObject (qupath.lib.objects.PathAnnotationObject)15 Point2D (java.awt.geom.Point2D)14 Collection (java.util.Collection)14 Collections (java.util.Collections)14 Geometry (org.locationtech.jts.geom.Geometry)14 PathClass (qupath.lib.objects.classes.PathClass)14 ImagePlane (qupath.lib.regions.ImagePlane)13