Search in sources :

Example 6 with RectangleROI

use of qupath.lib.roi.RectangleROI in project qupath by qupath.

the class QuPathViewer method paintViewer.

protected void paintViewer(Graphics g, int w, int h) {
    ImageServer<BufferedImage> server = getServer();
    if (server == null) {
        g.setColor(background);
        g.fillRect(0, 0, w, h);
        updateRepaintTimestamp();
        return;
    }
    // // Get dimensions
    // int w = getWidth();
    // int h = getHeight();
    Rectangle clip = g.getClipBounds();
    boolean clipFull;
    if (clip == null) {
        clip = new Rectangle(0, 0, w, h);
        g.setClip(0, 0, w, h);
        clipFull = true;
    } else
        clipFull = clip.x == 0 && clip.y == 0 && clip.width == w && clip.height == h;
    // Ensure we have a sufficiently-large buffer
    if (imgBuffer == null || imgBuffer.getWidth() != w || imgBuffer.getHeight() != h) {
        // Create buffered images & buffers for RGB pixel values
        imgBuffer = createBufferedImage(w, h);
        imgBuffer.setAccelerationPriority(1f);
        logger.trace("New buffered image created: {}", imgBuffer);
        // imgVolatile = createVolatileImage(w, h);
        imageUpdated = true;
        // If the size changed, ensure the AffineTransform is up-to-date
        updateAffineTransform();
    }
    // Get the displayed region
    Shape shapeRegion = getDisplayedRegionShape();
    // The visible shape must have changed if there wasn't one previously...
    // Otherwise check if it has changed & update accordingly
    // This will be used to notify listeners soon
    boolean shapeChanged = lastVisibleShape == null || !lastVisibleShape.equals(shapeRegion);
    long t1 = System.currentTimeMillis();
    // Only repaint the image if this is requested, otherwise only overlays need to be repainted
    if (imageUpdated || locationUpdated) {
        // || imgVolatile.contentsLost()) {
        // Set flags that image no longer requiring an update
        // By setting them early, they might still be reset during this run... in which case we don't want to thwart the re-run
        imageUpdated = false;
        locationUpdated = false;
        // updateBufferedImage(imgVolatile, shapeRegion, w, h);
        updateBufferedImage(imgBuffer, shapeRegion, w, h);
    }
    // if (imageUpdated || locationUpdated) {
    // updateBufferedImage(imgVolatile, shapeRegion, w, h);
    // //			updateBufferedImage(imgBuffer, shapeRegion, w, h);
    // //			logger.info("INITIAL Image drawing time: " + (System.currentTimeMillis() - t1));
    // imgVolatile.createGraphics().drawImage(imgBuffer, 0, 0, this);
    // }
    // while (imgVolatile.contentsLost()) {
    // imgVolatile.createGraphics().drawImage(imgBuffer, 0, 0, this);
    // }
    // Store the last shape visible
    lastVisibleShape = shapeRegion;
    // Draw the image from the buffer
    // The call to super.paintComponent is delayed until here to try to stop occasional flickering on Apple's Java 6
    g.setColor(background);
    if (clipFull)
        paintFinalImage(g, imgBuffer, this);
    else
        // g2d.drawImage(imgBuffer, 0, 0, getWidth(), getHeight(), this);
        g.drawImage(imgBuffer, clip.x, clip.y, clip.x + clip.width, clip.y + clip.height, clip.x, clip.y, clip.x + clip.width, clip.y + clip.height, null);
    if (logger.isTraceEnabled()) {
        long t2 = System.currentTimeMillis();
        logger.trace("Final image drawing time: {}", (t2 - t1));
    }
    // Really useful only for debugging graphics
    if (!(g instanceof Graphics2D)) {
        imageUpdated = false;
        // Notify any listeners of shape changes
        if (shapeChanged)
            fireVisibleRegionChangedEvent(lastVisibleShape);
        return;
    }
    double downsample = getDownsampleFactor();
    float opacity = overlayOptions.getOpacity();
    Graphics2D g2d = (Graphics2D) g.create();
    // Apply required transform to the graphics object (rotation, scaling, shifting...)
    g2d.transform(transform);
    Composite previousComposite = g2d.getComposite();
    boolean paintCompletely = thumbnailIsFullImage || !doFasterRepaint;
    // var regionBounds = AwtTools.getImageRegion(clip, getZPosition(), getTPosition());
    if (opacity > 0 || PathPrefs.alwaysPaintSelectedObjectsProperty().get()) {
        if (opacity < 1) {
            AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity);
            g2d.setComposite(composite);
        }
        Color color = getSuggestedOverlayColor();
        // Paint the overlay layers
        var imageData = this.imageDataProperty.get();
        for (PathOverlay overlay : allOverlayLayers.toArray(PathOverlay[]::new)) {
            logger.trace("Painting overlay: {}", overlay);
            if (overlay instanceof AbstractOverlay)
                ((AbstractOverlay) overlay).setPreferredOverlayColor(color);
            // overlay.paintOverlay(g2d, regionBounds, downsample, null, paintCompletely);
            overlay.paintOverlay(g2d, getServerBounds(), downsample, imageData, paintCompletely);
        }
    // if (hierarchyOverlay != null) {
    // hierarchyOverlay.setPreferredOverlayColor(color);
    // hierarchyOverlay.paintOverlay(g2d, getServerBounds(), downsampleFactor, null, paintCompletely);
    // }
    }
    // Paint the selected object
    PathObjectHierarchy hierarchy = getHierarchy();
    PathObject mainSelectedObject = getSelectedObject();
    Rectangle2D boundsRect = null;
    boolean useSelectedColor = PathPrefs.useSelectedColorProperty().get();
    boolean paintSelectedBounds = PathPrefs.paintSelectedBoundsProperty().get();
    for (PathObject selectedObject : hierarchy.getSelectionModel().getSelectedObjects().toArray(new PathObject[0])) {
        // TODO: Simplify this...
        if (selectedObject != null && selectedObject.hasROI() && selectedObject.getROI().getZ() == getZPosition() && selectedObject.getROI().getT() == getTPosition()) {
            if (!selectedObject.isDetection()) {
                // Ensure a selected ROI can be seen clearly
                if (previousComposite != null)
                    g2d.setComposite(previousComposite);
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            }
            Rectangle boundsDisplayed = shapeRegion.getBounds();
            ROI pathROI = selectedObject.getROI();
            // if ((PathPrefs.getPaintSelectedBounds() || (selectedObject.isDetection() && !PathPrefs.getUseSelectedColor())) && !(pathROI instanceof RectangleROI)) {
            if (pathROI != null && (paintSelectedBounds || (!useSelectedColor)) && !(pathROI instanceof RectangleROI) && !pathROI.isEmpty()) {
                Shape boundsShape = null;
                if (pathROI.isPoint()) {
                    var hull = pathROI.getConvexHull();
                    if (hull != null)
                        boundsShape = hull.getShape();
                }
                if (boundsShape == null) {
                    boundsRect = AwtTools.getBounds2D(pathROI, boundsRect);
                    boundsShape = boundsRect;
                }
                // Tried to match to pixel boundaries... but resulted in too much jiggling
                // boundsShape.setFrame(
                // Math.round(boundsShape.getX()/downsampleFactor)*downsampleFactor-downsampleFactor,
                // Math.round(boundsShape.getY()/downsampleFactor)*downsampleFactor-downsampleFactor,
                // Math.round(boundsShape.getWidth()/downsampleFactor)*downsampleFactor+2*downsampleFactor,
                // Math.round(boundsShape.getHeight()/downsampleFactor)*downsampleFactor+2*downsampleFactor);
                // boundsShape.setFrame(boundsShape.getX()-downsampleFactor, boundsShape.getY()-downsampleFactor, boundsShape.getWidth()+2*downsampleFactor, boundsShape.getHeight()+2*downsampleFactor);
                PathHierarchyPaintingHelper.paintShape(boundsShape, g2d, getSuggestedOverlayColor(), PathHierarchyPaintingHelper.getCachedStroke(Math.max(downsample, 1) * 2), null);
            // boundsShape.setFrame(boundsShape.getX()+downsampleFactor, boundsShape.getY()-downsampleFactor, boundsShape.getWidth(), boundsShape.getHeight());
            // PathHierarchyPaintingHelper.paintShape(boundsShape, g2d, new Color(1f, 1f, 1f, 0.75f), PathHierarchyPaintingHelper.getCachedStroke(Math.max(downsampleFactor, 1)*2), null, downsampleFactor);
            }
            // in a cached way
            if ((selectedObject.isDetection() && PathPrefs.useSelectedColorProperty().get()) || !PathObjectTools.hierarchyContainsObject(hierarchy, selectedObject))
                PathHierarchyPaintingHelper.paintObject(selectedObject, false, g2d, boundsDisplayed, overlayOptions, getHierarchy().getSelectionModel(), downsample);
            // Paint ROI handles, if required
            if (selectedObject == mainSelectedObject && roiEditor.hasROI()) {
                Stroke strokeThick = PathHierarchyPaintingHelper.getCachedStroke(PathPrefs.annotationStrokeThicknessProperty().get() * downsample);
                Color color = useSelectedColor ? ColorToolsAwt.getCachedColor(PathPrefs.colorSelectedObjectProperty().get()) : null;
                if (color == null)
                    color = ColorToolsAwt.getCachedColor(ColorToolsFX.getDisplayedColorARGB(selectedObject));
                g2d.setStroke(strokeThick);
                // Draw ROI handles using adaptive size
                double maxHandleSize = getMaxROIHandleSize();
                double minHandleSize = downsample;
                PathHierarchyPaintingHelper.paintHandles(roiEditor, g2d, minHandleSize, maxHandleSize, color, ColorToolsAwt.getTranslucentColor(color));
            }
        }
    }
    // Notify any listeners of shape changes
    if (shapeChanged)
        fireVisibleRegionChangedEvent(lastVisibleShape);
    updateRepaintTimestamp();
}
Also used : AbstractOverlay(qupath.lib.gui.viewer.overlays.AbstractOverlay) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) Stroke(java.awt.Stroke) Shape(java.awt.Shape) AlphaComposite(java.awt.AlphaComposite) Composite(java.awt.Composite) AlphaComposite(java.awt.AlphaComposite) Color(java.awt.Color) Rectangle(java.awt.Rectangle) Rectangle2D(java.awt.geom.Rectangle2D) RectangleROI(qupath.lib.roi.RectangleROI) ROI(qupath.lib.roi.interfaces.ROI) BufferedImage(java.awt.image.BufferedImage) Graphics2D(java.awt.Graphics2D) PathObject(qupath.lib.objects.PathObject) RectangleROI(qupath.lib.roi.RectangleROI) PathOverlay(qupath.lib.gui.viewer.overlays.PathOverlay)

Example 7 with RectangleROI

use of qupath.lib.roi.RectangleROI in project qupath by qupath.

the class Commands method createFullImageAnnotation.

/**
 * Create a full image annotation for the image in the specified viewer.
 * The z and t positions of the viewer will be used.
 * @param viewer the viewer containing the image to be processed
 */
public static void createFullImageAnnotation(QuPathViewer viewer) {
    if (viewer == null)
        return;
    ImageData<?> imageData = viewer.getImageData();
    if (imageData == null)
        return;
    PathObjectHierarchy hierarchy = imageData.getHierarchy();
    // Check if we already have a comparable annotation
    int z = viewer.getZPosition();
    int t = viewer.getTPosition();
    ImageRegion bounds = viewer.getServerBounds();
    ROI roi = ROIs.createRectangleROI(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), ImagePlane.getPlane(z, t));
    for (PathObject pathObject : hierarchy.getAnnotationObjects()) {
        ROI r2 = pathObject.getROI();
        if (r2 instanceof RectangleROI && roi.getBoundsX() == r2.getBoundsX() && roi.getBoundsY() == r2.getBoundsY() && roi.getBoundsWidth() == r2.getBoundsWidth() && roi.getBoundsHeight() == r2.getBoundsHeight() && roi.getImagePlane().equals(r2.getImagePlane())) {
            logger.info("Full image annotation already exists! {}", pathObject);
            viewer.setSelectedObject(pathObject);
            return;
        }
    }
    PathObject pathObject = PathObjects.createAnnotationObject(roi);
    hierarchy.addPathObject(pathObject);
    viewer.setSelectedObject(pathObject);
    // Log in the history
    if (z == 0 && t == 0)
        imageData.getHistoryWorkflow().addStep(new DefaultScriptableWorkflowStep("Create full image annotation", "createSelectAllObject(true);"));
    else
        imageData.getHistoryWorkflow().addStep(new DefaultScriptableWorkflowStep("Create full image annotation", String.format("createSelectAllObject(true, %d, %d);", z, t)));
}
Also used : DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) PathObject(qupath.lib.objects.PathObject) RectangleROI(qupath.lib.roi.RectangleROI) ImageRegion(qupath.lib.regions.ImageRegion) RectangleROI(qupath.lib.roi.RectangleROI) ROI(qupath.lib.roi.interfaces.ROI) PolygonROI(qupath.lib.roi.PolygonROI)

Example 8 with RectangleROI

use of qupath.lib.roi.RectangleROI in project qupath by qupath.

the class ImageJMacroRunner method runMacro.

static void runMacro(final ParameterList params, final ImageData<BufferedImage> imageData, final ImageDisplay imageDisplay, final PathObject pathObject, final String macroText) {
    // Don't try if interrupted
    if (Thread.currentThread().isInterrupted()) {
        logger.warn("Skipping macro for {} - thread interrupted", pathObject);
        return;
    }
    PathImage<ImagePlus> pathImage;
    // Extract parameters
    double downsampleFactor = params.getDoubleParameterValue("downsampleFactor");
    boolean sendROI = params.getBooleanParameterValue("sendROI");
    boolean sendOverlay = params.getBooleanParameterValue("sendOverlay");
    ROI pathROI = pathObject.getROI();
    ImageDisplay imageDisplay2 = params.containsKey("useTransform") && Boolean.TRUE.equals(params.getBooleanParameterValue("useTransform")) ? imageDisplay : null;
    ImageServer<BufferedImage> server = imageDisplay2 == null || imageDisplay2.availableChannels().isEmpty() ? imageData.getServer() : ChannelDisplayTransformServer.createColorTransformServer(imageData.getServer(), imageDisplay.availableChannels());
    RegionRequest region = RegionRequest.createInstance(imageData.getServer().getPath(), downsampleFactor, pathROI);
    // Check the size of the region to extract - abort if it is too large of if ther isn't enough RAM
    try {
        IJTools.isMemorySufficient(region, imageData);
    } catch (Exception e1) {
        Dialogs.showErrorMessage("ImageJ macro error", e1.getMessage());
        return;
    }
    try {
        if (sendOverlay)
            pathImage = IJExtension.extractROIWithOverlay(server, pathObject, imageData.getHierarchy(), region, sendROI, null);
        else
            pathImage = IJExtension.extractROI(server, pathObject, region, sendROI);
    } catch (IOException e) {
        logger.error("Unable to extract image region " + region, e);
        return;
    }
    // IJHelpers.getImageJInstance();
    // ImageJ ij = IJHelpers.getImageJInstance();
    // if (ij != null && WindowManager.getIDList() == null)
    // ij.setVisible(false);
    // Determine a sensible argument to pass
    String argument;
    if (pathObject instanceof TMACoreObject || !pathObject.hasROI())
        argument = pathObject.getDisplayedName();
    else
        argument = String.format("Region (%d, %d, %d, %d)", region.getX(), region.getY(), region.getWidth(), region.getHeight());
    // Check if we have an image already - if so, we need to be more cautious so we don't accidentally use it...
    // boolean hasImage = WindowManager.getCurrentImage() != null;
    // Actually run the macro
    final ImagePlus imp = pathImage.getImage();
    imp.setProperty("QuPath region", argument);
    WindowManager.setTempCurrentImage(imp);
    // Ensure we've requested an instance, since this also loads any required extra plugins
    IJExtension.getImageJInstance();
    // TODO: Pay attention to how threading should be done... I think Swing EDT ok?
    try {
        // SwingUtilities.invokeAndWait(() -> {
        boolean cancelled = false;
        ImagePlus impResult = null;
        try {
            IJ.redirectErrorMessages();
            Interpreter interpreter = new Interpreter();
            impResult = interpreter.runBatchMacro(macroText, imp);
            // If we had an error, return
            if (interpreter.wasError()) {
                Thread.currentThread().interrupt();
                return;
            }
            // Get the resulting image, if available
            if (impResult == null)
                impResult = WindowManager.getCurrentImage();
        } catch (RuntimeException e) {
            logger.error(e.getLocalizedMessage());
            // DisplayHelpers.showErrorMessage("ImageJ macro error", e.getLocalizedMessage());
            Thread.currentThread().interrupt();
            cancelled = true;
        } finally {
            // IJ.runMacro(macroText, argument);
            WindowManager.setTempCurrentImage(null);
        // IJ.run("Close all");
        }
        if (cancelled)
            return;
        // Get the current image when the macro has finished - which may or may not be the same as the original
        if (impResult == null)
            impResult = imp;
        boolean changes = false;
        if (params.getBooleanParameterValue("clearObjects") && pathObject.hasChildren()) {
            pathObject.clearPathObjects();
            changes = true;
        }
        if (params.getBooleanParameterValue("getROI") && impResult.getRoi() != null) {
            Roi roi = impResult.getRoi();
            Calibration cal = impResult.getCalibration();
            PathObject pathObjectNew = roi == null ? null : IJTools.convertToAnnotation(roi, cal.xOrigin, cal.yOrigin, downsampleFactor, region.getPlane());
            if (pathObjectNew != null) {
                // If necessary, trim any returned annotation
                if (pathROI != null && !(pathROI instanceof RectangleROI) && pathObjectNew.isAnnotation() && RoiTools.isShapeROI(pathROI) && RoiTools.isShapeROI(pathObjectNew.getROI())) {
                    ROI roiNew = RoiTools.combineROIs(pathROI, pathObjectNew.getROI(), CombineOp.INTERSECT);
                    ((PathAnnotationObject) pathObjectNew).setROI(roiNew);
                }
                // Only add if we have something
                if (pathObjectNew.getROI() instanceof LineROI || !pathObjectNew.getROI().isEmpty()) {
                    pathObject.addPathObject(pathObjectNew);
                    // imageData.getHierarchy().addPathObject(IJHelpers.convertToPathObject(imp, imageData.getServer(), imp.getRoi(), downsampleFactor, false), true);
                    changes = true;
                }
            }
        }
        boolean exportAsDetection = ((String) params.getChoiceParameterValue("getOverlayAs")).equals("Detections") ? true : false;
        if (params.getBooleanParameterValue("getOverlay") && impResult.getOverlay() != null) {
            var overlay = impResult.getOverlay();
            List<PathObject> childObjects = QuPath_Send_Overlay_to_QuPath.createObjectsFromROIs(imp, Arrays.asList(overlay.toArray()), downsampleFactor, exportAsDetection, true, region.getPlane());
            if (!childObjects.isEmpty()) {
                pathObject.addPathObjects(childObjects);
                changes = true;
            }
        // for (Roi roi : impResult.getOverlay().toArray()) {
        // pathObject.addPathObject(IJTools.convertToPathObject(imp, imageData.getServer(), roi, downsampleFactor, true));
        // changes = true;
        // }
        }
        if (changes) {
            Platform.runLater(() -> imageData.getHierarchy().fireHierarchyChangedEvent(null));
        }
    // });
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
Also used : Interpreter(ij.macro.Interpreter) TMACoreObject(qupath.lib.objects.TMACoreObject) IOException(java.io.IOException) Calibration(ij.measure.Calibration) ImagePlus(ij.ImagePlus) RectangleROI(qupath.lib.roi.RectangleROI) LineROI(qupath.lib.roi.LineROI) ROI(qupath.lib.roi.interfaces.ROI) Roi(ij.gui.Roi) BufferedImage(java.awt.image.BufferedImage) InvocationTargetException(java.lang.reflect.InvocationTargetException) IOException(java.io.IOException) PathAnnotationObject(qupath.lib.objects.PathAnnotationObject) PathObject(qupath.lib.objects.PathObject) RectangleROI(qupath.lib.roi.RectangleROI) LineROI(qupath.lib.roi.LineROI) RegionRequest(qupath.lib.regions.RegionRequest) ImageDisplay(qupath.lib.display.ImageDisplay)

Aggregations

RectangleROI (qupath.lib.roi.RectangleROI)8 PathObject (qupath.lib.objects.PathObject)4 ROI (qupath.lib.roi.interfaces.ROI)4 BufferedImage (java.awt.image.BufferedImage)3 IOException (java.io.IOException)3 LineROI (qupath.lib.roi.LineROI)3 Shape (java.awt.Shape)2 AffineTransform (java.awt.geom.AffineTransform)2 PathObjectHierarchy (qupath.lib.objects.hierarchy.PathObjectHierarchy)2 RegionRequest (qupath.lib.regions.RegionRequest)2 EllipseROI (qupath.lib.roi.EllipseROI)2 PolygonROI (qupath.lib.roi.PolygonROI)2 CompositeImage (ij.CompositeImage)1 ImagePlus (ij.ImagePlus)1 Roi (ij.gui.Roi)1 ShapeRoi (ij.gui.ShapeRoi)1 Interpreter (ij.macro.Interpreter)1 Calibration (ij.measure.Calibration)1 AlphaComposite (java.awt.AlphaComposite)1 Color (java.awt.Color)1