Search in sources :

Example 66 with ROI

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

the class IJTools method convertToPathObject.

/**
 * Create a {@link PathObject} for a specific ImageJ Roi.
 * This method has been deprecated, since its signature was misleading (the server was not used).
 *
 * @param imp
 * @param server
 * @param roi
 * @param downsampleFactor
 * @param creator
 * @param plane
 * @return
 * @deprecated use instead {@link #convertToPathObject(Roi, double, double, double, Function, ImagePlane)}
 */
@Deprecated
public static PathObject convertToPathObject(ImagePlus imp, ImageServer<?> server, Roi roi, double downsampleFactor, Function<ROI, PathObject> creator, ImagePlane plane) {
    Calibration cal = imp == null ? null : imp.getCalibration();
    if (plane == null)
        plane = getImagePlane(roi, imp);
    ROI pathROI = IJTools.convertToROI(roi, cal, downsampleFactor, plane);
    if (pathROI == null)
        return null;
    PathObject pathObject = creator.apply(pathROI);
    calibrateObject(pathObject, roi);
    return pathObject;
}
Also used : PathObject(qupath.lib.objects.PathObject) Calibration(ij.measure.Calibration) PixelCalibration(qupath.lib.images.servers.PixelCalibration) EllipseROI(qupath.lib.roi.EllipseROI) PointsROI(qupath.lib.roi.PointsROI) PolygonROI(qupath.lib.roi.PolygonROI) RectangleROI(qupath.lib.roi.RectangleROI) LineROI(qupath.lib.roi.LineROI) PolylineROI(qupath.lib.roi.PolylineROI) ROI(qupath.lib.roi.interfaces.ROI)

Example 67 with ROI

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

the class TestRoiTools method testTilingPerformance.

/**
 * Test tiling for a complex (mult)ipolygon.
 */
@Test
public void testTilingPerformance() {
    ROI roiMain = null;
    try (var reader = new InputStreamReader(this.getClass().getResourceAsStream("/data/polygon.geojson"))) {
        roiMain = GsonTools.getInstance().fromJson(reader, ROI.class);
    } catch (IOException e1) {
        logger.warn("Unable to read polygon! Will try to generate one instead.");
        var geometry = createRandomPolygon(100, GeometryTools.getDefaultFactory(), 10000, 10, 10000, 10000);
        roiMain = GeometryTools.geometryToROI(geometry, ImagePlane.getDefaultPlane());
    }
    // Repeat for filled & unfilled ROIs - and use filled twice for some 'warm-up' time useful if looking at performance
    var roiFilled = RoiTools.fillHoles(roiMain);
    var rois = Arrays.asList(roiFilled, roiFilled, roiMain);
    for (var roi : rois) {
        int overlap = 10;
        var dim = ImmutableDimension.getInstance(512, 400);
        var dimMax = ImmutableDimension.getInstance(1000, 1024);
        long startTime = System.currentTimeMillis();
        var tiles = RoiTools.computeTiledROIs(roi, dim, dimMax, false, overlap);
        long middleTime = System.currentTimeMillis();
        var tilesLegacy = RoiTools.computeTiledROIsLegacy(roi, dim, dimMax, false, overlap);
        long endTime = System.currentTimeMillis();
        long legacyTime = endTime - middleTime;
        long newTime = middleTime - startTime;
        // Note that this requires some warning up (i.e. running once isn't very representative)
        logger.trace("Legacy tiling time: {}, Current tiling time: {}", legacyTime, newTime);
        // Should have the same number of tile ROIs
        assertEquals(tiles.size(), tilesLegacy.size());
        // Should be on the same plane
        assertTrue(tiles.stream().allMatch(r -> r.getImagePlane().equals(ImagePlane.getDefaultPlane())));
        // Get normalized geometries
        var tilesGeometry = tiles.stream().map(r -> r.getGeometry()).collect(Collectors.toList());
        tilesGeometry.stream().forEach(g -> g.normalize());
        var tilesLegacyGeometry = tiles.stream().map(r -> r.getGeometry()).collect(Collectors.toList());
        tilesLegacyGeometry.stream().forEach(g -> g.normalize());
        assertEquals(tilesGeometry, tilesLegacyGeometry);
    }
}
Also used : Arrays(java.util.Arrays) GeometryFactory(org.locationtech.jts.geom.GeometryFactory) Logger(org.slf4j.Logger) CombineOp(qupath.lib.roi.RoiTools.CombineOp) GsonTools(qupath.lib.io.GsonTools) LoggerFactory(org.slf4j.LoggerFactory) Coordinate(org.locationtech.jts.geom.Coordinate) IOException(java.io.IOException) Random(java.util.Random) AffineTransform(java.awt.geom.AffineTransform) InputStreamReader(java.io.InputStreamReader) Collectors(java.util.stream.Collectors) ArrayList(java.util.ArrayList) Test(org.junit.jupiter.api.Test) ROI(qupath.lib.roi.interfaces.ROI) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) ImagePlane(qupath.lib.regions.ImagePlane) Geometry(org.locationtech.jts.geom.Geometry) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) ImmutableDimension(qupath.lib.geom.ImmutableDimension) AffineTransformation(org.locationtech.jts.geom.util.AffineTransformation) InputStreamReader(java.io.InputStreamReader) IOException(java.io.IOException) ROI(qupath.lib.roi.interfaces.ROI) Test(org.junit.jupiter.api.Test)

Example 68 with ROI

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

Example 69 with ROI

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

the class TestROIs method testAreas.

/**
 * Compare areas as returned from ROIs and after converting to JTS Geometry objects.
 */
@Test
public void testAreas() {
    double delta = 0.01;
    // Because of Geometry precision reduction, sometimes a larger delta is needed (still < 1 pixel)
    double deltaLarge = 0.5;
    // Sample pixel sizes
    double pixelWidth = 0.5;
    double pixelHeight = 0.75;
    ROI rectangle = ROIs.createRectangleROI(0, 0, 1000, 1000, ImagePlane.getDefaultPlane());
    double targetAreaRectangle = 1000.0 * 1000.0;
    assertEquals(rectangle.getArea(), targetAreaRectangle, delta);
    checkROIMeasurements(rectangle, 1, 1, delta);
    checkROIMeasurements(rectangle, pixelWidth, pixelHeight, delta);
    assertTrue(rectangle.getGeometry().isValid());
    ROI ellipse = ROIs.createEllipseROI(50, 00, 500, 300, ImagePlane.getDefaultPlane());
    double targetAreaEllipse = Math.PI * 250 * 150;
    assertEquals(targetAreaEllipse, ellipse.getArea(), delta);
    // Flattening the path results in a more substantial area difference
    assertTrue(Math.abs(targetAreaEllipse - ellipse.getGeometry().getArea()) / targetAreaEllipse < 0.01);
    checkROIMeasurements(ellipse, 1, 1, targetAreaEllipse / 100.0);
    checkROIMeasurements(ellipse, pixelWidth, pixelHeight, targetAreaEllipse / 100.0);
    assertTrue(ellipse.getGeometry().isValid());
    // ROIs with holes can be troublesome, JTS may consider holes as 'positive' regions
    ROI areaSubtracted = RoiTools.combineROIs(rectangle, ellipse, CombineOp.SUBTRACT);
    assertEquals(areaSubtracted.getArea(), areaSubtracted.getGeometry().getArea(), delta);
    assertNotEquals(areaSubtracted.getArea(), rectangle.getArea());
    checkROIMeasurements(areaSubtracted, 1, 1, delta);
    checkROIMeasurements(areaSubtracted, pixelWidth, pixelHeight, delta);
    assertTrue(areaSubtracted.getGeometry().isValid());
    ROI areaAdded = RoiTools.combineROIs(rectangle, ellipse, CombineOp.ADD);
    assertEquals(areaAdded.getArea(), areaAdded.getGeometry().getArea(), delta);
    assertEquals(rectangle.getArea(), areaAdded.getArea(), delta);
    checkROIMeasurements(areaAdded, 1, 1, delta);
    checkROIMeasurements(areaAdded, pixelWidth, pixelHeight, delta);
    assertTrue(areaAdded.getGeometry().isValid());
    File fileHierarchy = new File("src/test/resources/data/test-objects.hierarchy");
    try (InputStream stream = Files.newInputStream(fileHierarchy.toPath())) {
        PathObjectHierarchy hierarchy = (PathObjectHierarchy) new ObjectInputStream(stream).readObject();
        List<ROI> rois = hierarchy.getFlattenedObjectList(null).stream().filter(p -> p.hasROI()).map(p -> p.getROI()).collect(Collectors.toList());
        assertNotEquals(0L, rois.size());
        for (ROI roi : rois) {
            Geometry geom = roi.getGeometry();
            assertEquals(roi.isEmpty(), geom.isEmpty());
            assertTrue(geom.isValid());
            if (roi.isArea()) {
                assertEquals(roi.isEmpty(), geom.isEmpty());
                if (roi instanceof EllipseROI) {
                    assertTrue(Math.abs(roi.getArea() - geom.getArea()) / roi.getArea() < 0.01);
                } else
                    assertEquals(roi.getArea(), geom.getArea(), deltaLarge);
            } else if (roi.isLine()) {
                assertEquals(roi.getLength(), geom.getLength(), delta);
            } else if (roi.isPoint()) {
                assertEquals(roi.getNumPoints(), geom.getNumPoints(), delta);
            }
            assertEquals(roi.getCentroidX(), geom.getCentroid().getX(), delta);
            assertEquals(roi.getCentroidY(), geom.getCentroid().getY(), delta);
            checkROIMeasurements(areaAdded, 1, 1, delta);
            checkROIMeasurements(areaAdded, pixelWidth, pixelHeight, delta);
            for (var split : RoiTools.splitROI(roi)) {
                checkROIMeasurements(split, 1, 1, deltaLarge);
                checkROIMeasurements(split, pixelWidth, pixelHeight, deltaLarge);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        fail(e.getLocalizedMessage());
    }
}
Also used : CombineOp(qupath.lib.roi.RoiTools.CombineOp) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Files(java.nio.file.Files) ObjectInputStream(java.io.ObjectInputStream) IOException(java.io.IOException) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) Collectors(java.util.stream.Collectors) File(java.io.File) Test(org.junit.jupiter.api.Test) ROI(qupath.lib.roi.interfaces.ROI) List(java.util.List) Point2(qupath.lib.geom.Point2) ByteArrayInputStream(java.io.ByteArrayInputStream) Assertions(org.junit.jupiter.api.Assertions) ImagePlane(qupath.lib.regions.ImagePlane) Geometry(org.locationtech.jts.geom.Geometry) ObjectOutputStream(java.io.ObjectOutputStream) InputStream(java.io.InputStream) Geometry(org.locationtech.jts.geom.Geometry) PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) ObjectInputStream(java.io.ObjectInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) ROI(qupath.lib.roi.interfaces.ROI) File(java.io.File) IOException(java.io.IOException) ObjectInputStream(java.io.ObjectInputStream) Test(org.junit.jupiter.api.Test)

Example 70 with ROI

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

the class ViewTrackerPlayback method setViewerForFrame.

static void setViewerForFrame(final QuPathViewer viewer, final ViewRecordingFrame frame) {
    // Resize the viewer (if necessary)
    resizeViewer(viewer, frame.getSize());
    // Set downsample
    viewer.setDownsampleFactor(frame.getDownsampleFactor());
    // Set location
    Rectangle imageBounds = frame.getImageBounds();
    viewer.setCenterPixelLocation(imageBounds.x + imageBounds.width * .5, imageBounds.y + imageBounds.height * .5);
    // Set rotation
    viewer.setRotation(frame.getRotation());
    if (frame.hasEyePosition()) {
        Point2D p2d = frame.getEyePosition();
        ROI point = ROIs.createPointsROI(p2d.getX(), p2d.getY(), ImagePlane.getDefaultPlane());
        // //			if (Boolean.TRUE.equals(frame.isEyeFixated()))
        // point.setPointRadius(viewer.getDownsampleFactor() * 10); // This was only removed because setPointRadius was removed!
        // //			else
        // //				point.setPointRadius(viewer.getDownsampleFactor() * 8);
        PathObject pathObject = PathObjects.createAnnotationObject(point);
        pathObject.setName("Eye tracking position");
        viewer.setSelectedObject(pathObject);
        logger.debug("Eye position: " + p2d);
    }
    if (frame.hasZOrT()) {
        viewer.setZPosition(frame.getZ());
        viewer.setTPosition(frame.getT());
    }
}
Also used : PathObject(qupath.lib.objects.PathObject) Point2D(java.awt.geom.Point2D) Rectangle(java.awt.Rectangle) 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