Search in sources :

Example 21 with RegionRequest

use of qupath.lib.regions.RegionRequest in project qupath by qupath.

the class ServerTools method getPaddedRequest.

/**
 * Get a raster, padded by the specified amount, to the left, right, above and below.
 * <p>
 * Note that the padding is defined in terms of the <i>destination</i> pixels.
 * <p>
 * In other words, a specified padding of 5 should actually result in 20 pixels being added in each dimension
 * if the {@code request.getDownsample() == 4}.
 *
 * @param server
 * @param request
 * @param padding
 * @return
 * @throws IOException
 */
public static BufferedImage getPaddedRequest(ImageServer<BufferedImage> server, RegionRequest request, Padding padding) throws IOException {
    // If we don't have any padding, just return directly
    if (padding.isEmpty())
        return server.readBufferedImage(request);
    // Get the expected bounds
    double downsample = request.getDownsample();
    int x = (int) Math.round(request.getX() - padding.getX1() * downsample);
    int y = (int) Math.round(request.getY() - padding.getY1() * downsample);
    int x2 = (int) Math.round((request.getX() + request.getWidth()) + padding.getX2() * downsample);
    int y2 = (int) Math.round((request.getY() + request.getHeight()) + padding.getY2() * downsample);
    // If we're out of range, we'll need to work a bit harder
    int padLeft = 0, padRight = 0, padUp = 0, padDown = 0;
    boolean outOfRange = false;
    if (x < 0) {
        padLeft = (int) Math.round(-x / downsample);
        x = 0;
        outOfRange = true;
    }
    if (y < 0) {
        padUp = (int) Math.round(-y / downsample);
        y = 0;
        outOfRange = true;
    }
    if (x2 > server.getWidth()) {
        padRight = (int) Math.round((x2 - server.getWidth()) / downsample);
        x2 = server.getWidth();
        outOfRange = true;
    }
    if (y2 > server.getHeight()) {
        padDown = (int) Math.round((y2 - server.getHeight()) / downsample);
        y2 = server.getHeight();
        outOfRange = true;
    }
    // If everything is within range, this should be relatively straightforward
    RegionRequest request2 = RegionRequest.createInstance(request.getPath(), downsample, x, y, x2 - x, y2 - y, request.getZ(), request.getT());
    BufferedImage img = server.readBufferedImage(request2);
    if (outOfRange) {
        WritableRaster raster = img.getRaster();
        WritableRaster rasterPadded = raster.createCompatibleWritableRaster(raster.getWidth() + padLeft + padRight, raster.getHeight() + padUp + padDown);
        rasterPadded.setRect(padLeft, padUp, raster);
        // Add padding above
        if (padUp > 0) {
            WritableRaster row = raster.createWritableChild(0, 0, raster.getWidth(), 1, 0, 0, null);
            for (int r = 0; r < padUp; r++) rasterPadded.setRect(padLeft, r, row);
        }
        // Add padding below
        if (padDown > 0) {
            WritableRaster row = raster.createWritableChild(0, raster.getHeight() - 1, raster.getWidth(), 1, 0, 0, null);
            for (int r = padUp + raster.getHeight(); r < rasterPadded.getHeight(); r++) rasterPadded.setRect(padLeft, r, row);
        }
        // Add padding to the left
        if (padLeft > 0) {
            WritableRaster col = rasterPadded.createWritableChild(padLeft, 0, 1, rasterPadded.getHeight(), 0, 0, null);
            for (int c = 0; c < padLeft; c++) rasterPadded.setRect(c, 0, col);
        }
        // Add padding to the right
        if (padRight > 0) {
            WritableRaster col = rasterPadded.createWritableChild(rasterPadded.getWidth() - padRight - 1, 0, 1, rasterPadded.getHeight(), 0, 0, null);
            for (int c = padLeft + raster.getWidth(); c < rasterPadded.getWidth(); c++) rasterPadded.setRect(c, 0, col);
        }
        // TODO: The padding seems to work - but something to be cautious with...
        img = new BufferedImage(img.getColorModel(), rasterPadded, img.isAlphaPremultiplied(), null);
    }
    return img;
}
Also used : WritableRaster(java.awt.image.WritableRaster) RegionRequest(qupath.lib.regions.RegionRequest) BufferedImage(java.awt.image.BufferedImage)

Example 22 with RegionRequest

use of qupath.lib.regions.RegionRequest in project qupath by qupath.

the class SparseImageServer method readTile.

@Override
protected BufferedImage readTile(final TileRequest tileRequest) throws IOException {
    WritableRaster raster = null;
    for (ImageRegion subRegion : manager.getRegions()) {
        if (subRegion.getZ() != tileRequest.getZ() + originZ || subRegion.getT() != tileRequest.getT() + originT)
            continue;
        double downsample = tileRequest.getRegionRequest().getDownsample();
        if (subRegion.intersects(tileRequest.getImageX() + originX, tileRequest.getImageY() + originY, tileRequest.getImageWidth(), tileRequest.getImageHeight())) {
            // If we overlap, request the overlapping portion
            ImageServer<BufferedImage> serverTemp = manager.getServer(subRegion, downsample);
            // Get image coordinates for bounding box of valid region
            int x1 = Math.max(tileRequest.getImageX() + originX, subRegion.getX());
            int y1 = Math.max(tileRequest.getImageY() + originY, subRegion.getY());
            int x2 = Math.min(tileRequest.getImageX() + originX + tileRequest.getImageWidth(), subRegion.getX() + subRegion.getWidth());
            int y2 = Math.min(tileRequest.getImageY() + originY + tileRequest.getImageHeight(), subRegion.getY() + subRegion.getHeight());
            // Determine request coordinates
            // TODO: Test whether sparse images with pyramidal regions work, or images stored as single planes at pre-specified downsamples
            int xr = x1 - subRegion.getX();
            int yr = y1 - subRegion.getY();
            int xr2 = x2 - subRegion.getX();
            int yr2 = y2 - subRegion.getY();
            double requestDownsample = downsample;
            // if (requestDownsample > 1 && serverTemp.nResolutions() == 1) {
            // requestDownsample = serverTemp.getDownsampleForResolution(0);
            // double scale = requestDownsample / downsample;
            // xr = (int)Math.round(xr * scale);
            // yr = (int)Math.round(yr * scale);
            // xr2 = (int)Math.round(xr2 * scale);
            // yr2 = (int)Math.round(yr2 * scale);
            // System.err.println(downsample + ", " + scale + ": " + serverTemp.getPath());
            // }
            RegionRequest requestTemp = RegionRequest.createInstance(serverTemp.getPath(), requestDownsample, xr, yr, xr2 - xr, yr2 - yr, tileRequest.getZ() + originZ, tileRequest.getT() + originT);
            BufferedImage imgTemp = null;
            synchronized (serverTemp) {
                imgTemp = serverTemp.readBufferedImage(requestTemp);
            }
            if (imgTemp == null)
                continue;
            // If we don't have an output image yet, create a compatible one
            if (raster == null) {
                raster = imgTemp.getRaster().createCompatibleWritableRaster(tileRequest.getTileWidth(), tileRequest.getTileHeight());
            }
            int x = (int) Math.round((x1 - tileRequest.getImageX() - originX) / downsample);
            int y = (int) Math.round((y1 - tileRequest.getImageY() - originY) / downsample);
            int w = Math.min(imgTemp.getWidth(), raster.getWidth() - x);
            int h = Math.min(imgTemp.getHeight(), raster.getHeight() - y);
            raster.setDataElements(x, y, w, h, imgTemp.getRaster().getDataElements(0, 0, w, h, null));
        }
    }
    // reusing an existing raster where possible to reduce memory requirements.
    if (raster == null) {
        return getEmptyTile(tileRequest.getTileWidth(), tileRequest.getTileHeight(), true);
    }
    // System.err.println(String.format("%.2f - %.2f", (double)tileRequest.getImageHeight()/raster.getHeight(), tileRequest.getDownsample()));
    return new BufferedImage(colorModel, raster, false, null);
}
Also used : WritableRaster(java.awt.image.WritableRaster) ImageRegion(qupath.lib.regions.ImageRegion) RegionRequest(qupath.lib.regions.RegionRequest) BufferedImage(java.awt.image.BufferedImage)

Example 23 with RegionRequest

use of qupath.lib.regions.RegionRequest in project qupath by qupath.

the class CroppedImageServer method readBufferedImage.

@Override
public BufferedImage readBufferedImage(final RegionRequest request) throws IOException {
    RegionRequest request2 = RegionRequest.createInstance(request.getPath(), request.getDownsample(), request.getX() + region.getX(), request.getY() + region.getY(), request.getWidth(), request.getHeight(), request.getZ(), request.getT());
    BufferedImage img = getWrappedServer().readBufferedImage(request2);
    // TODO: Mask as ellipse, if necessary?
    return img;
}
Also used : RegionRequest(qupath.lib.regions.RegionRequest) BufferedImage(java.awt.image.BufferedImage)

Example 24 with RegionRequest

use of qupath.lib.regions.RegionRequest 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 25 with RegionRequest

use of qupath.lib.regions.RegionRequest in project qupath by qupath.

the class TestBioFormatsImageServer method testProject.

void testProject(Project<BufferedImage> project) {
    // We're not really testing Bio-Formats... and the messages can get in the way
    DebugTools.enableIJLogging(false);
    DebugTools.setRootLevel("error");
    List<ProjectImageEntry<BufferedImage>> entries = project.getImageList();
    System.out.println("Testing project with " + entries.size() + " entries: " + Project.getNameFromURI(project.getURI()));
    for (ProjectImageEntry<BufferedImage> entry : entries) {
        // String serverPath = entry.getServerPath();
        // System.out.println("Opening: " + serverPath);
        // String pathFile = BioFormatsImageServer.splitFilePathAndSeriesName(serverPath)[0];
        // if (!new File(pathFile).exists()) {
        // System.err.println("File does not exist for server path " + serverPath + " - will skip");
        // }
        BioFormatsImageServer server = null;
        BufferedImage img = null;
        BufferedImage imgThumbnail = null;
        ImagePlus imp = null;
        int tileSize = 256;
        int z = 0;
        int t = 0;
        try {
            // Create the server
            server = (BioFormatsImageServer) entry.getServerBuilder().build();
            // server = (BioFormatsImageServer)ImageServerProvider.buildServer(serverPath, BufferedImage.class, "--classname", BioFormatsServerBuilder.class.getName());
            // Read a thumbnail
            imgThumbnail = server.getDefaultThumbnail(server.nZSlices() / 2, 0);
            // Read from the center of the image
            int w = server.getWidth() < tileSize ? server.getWidth() : tileSize;
            int h = server.getHeight() < tileSize ? server.getHeight() : tileSize;
            z = (int) (server.nZSlices() / 2);
            t = (int) (server.nTimepoints() / 2);
            RegionRequest request = RegionRequest.createInstance(server.getPath(), 1, (server.getWidth() - w) / 2, (server.getHeight() - h) / 2, w, h, z, t);
            img = server.readBufferedImage(request);
            // (Skip if we have multiple series, as the setFlattenedResolutions() status can cause confusion)
            if (server.getPreferredDownsamples().length == 1 || !server.containsSubImages()) {
                ImporterOptions options = new ImporterOptions();
                int series = server.getSeries();
                options.setId(server.getFile().getAbsolutePath());
                options.setOpenAllSeries(false);
                options.setSeriesOn(series, true);
                options.setCrop(true);
                options.setCropRegion(server.getSeries(), new Region(request.getX(), request.getY(), request.getWidth(), request.getHeight()));
                try {
                    ImagePlus[] imps = BF.openImagePlus(options);
                    assert imps.length == 1;
                    imp = imps[0];
                } catch (Exception e) {
                    logger.warn("Unable to open with ImageJ: " + server, e);
                }
            } else {
                logger.warn("Multiple multi-resolution series in file - skipping ImageJ check");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // Check if we got a server at all
        assertNotNull(server);
        // Check if we got an image
        assertNotNull(img);
        // Get the thumbnail
        assertNotNull(imgThumbnail);
        // Check channel numbers
        assertEquals(img.getRaster().getNumBands(), server.nChannels());
        assertEquals(imgThumbnail.getRaster().getNumBands(), server.nChannels());
        // Check pixel sizes
        if (imp != null) {
            PixelCalibration cal = server.getPixelCalibration();
            if ("micron".equals(imp.getCalibration().getXUnit()))
                assertEquals(imp.getCalibration().pixelWidth, cal.getPixelWidthMicrons(), 0.00001);
            else
                assertTrue(Double.isNaN(cal.getPixelWidthMicrons()));
            if ("micron".equals(imp.getCalibration().getXUnit()))
                assertEquals(imp.getCalibration().pixelHeight, cal.getPixelHeightMicrons(), 0.00001);
            else
                assertTrue(Double.isNaN(cal.getPixelHeightMicrons()));
            // Check z-slices, if appropriate
            if (server.nZSlices() > 1) {
                if ("micron".equals(imp.getCalibration().getZUnit()))
                    assertEquals(imp.getCalibration().pixelDepth, cal.getZSpacingMicrons(), 0.00001);
                else
                    assertTrue(Double.isNaN(cal.getZSpacingMicrons()));
            }
            // Check dimensions by comparison with ImageJ
            assertEquals(img.getWidth(), imp.getWidth());
            assertEquals(img.getHeight(), imp.getHeight());
            assertEquals(server.nChannels(), imp.getNChannels());
            assertEquals(server.nTimepoints(), imp.getNFrames());
            assertEquals(server.nZSlices(), imp.getNSlices());
            // Check actual pixel values
            float[] samples = null;
            float[] samplesIJ = null;
            for (int c = 0; c < server.nChannels(); c++) {
                samples = img.getRaster().getSamples(0, 0, img.getWidth(), img.getHeight(), c, samples);
                imp.setPosition(c + 1, z + 1, t + 1);
                samplesIJ = (float[]) imp.getProcessor().convertToFloatProcessor().getPixels();
                // I am having some trouble comparing the full array with Java 10... trouble appears on IJ side..?
                assertEquals(samples[0], samplesIJ[0], (float) 0.00001);
            // assertArrayEquals(samples, samplesIJ, (float)0.00001);
            }
        }
        printSummary(server);
    }
}
Also used : PixelCalibration(qupath.lib.images.servers.PixelCalibration) ImagePlus(ij.ImagePlus) BufferedImage(java.awt.image.BufferedImage) ImporterOptions(loci.plugins.in.ImporterOptions) Region(loci.common.Region) ProjectImageEntry(qupath.lib.projects.ProjectImageEntry) RegionRequest(qupath.lib.regions.RegionRequest)

Aggregations

RegionRequest (qupath.lib.regions.RegionRequest)37 BufferedImage (java.awt.image.BufferedImage)29 IOException (java.io.IOException)18 ROI (qupath.lib.roi.interfaces.ROI)15 ArrayList (java.util.ArrayList)13 PathObject (qupath.lib.objects.PathObject)10 List (java.util.List)9 Collection (java.util.Collection)8 Collectors (java.util.stream.Collectors)8 PixelCalibration (qupath.lib.images.servers.PixelCalibration)8 Collections (java.util.Collections)7 TMACoreObject (qupath.lib.objects.TMACoreObject)7 Graphics2D (java.awt.Graphics2D)6 Logger (org.slf4j.Logger)6 LoggerFactory (org.slf4j.LoggerFactory)6 ImageData (qupath.lib.images.ImageData)6 ImageServer (qupath.lib.images.servers.ImageServer)6 PathObjectTools (qupath.lib.objects.PathObjectTools)6 LinkedHashMap (java.util.LinkedHashMap)5 Map (java.util.Map)5