Search in sources :

Example 16 with MeasurementList

use of qupath.lib.measurements.MeasurementList in project qupath by qupath.

the class DelaunayTriangulation method addNodeMeasurements.

/**
 * Add Delaunay measurements to each pathObject.
 */
public void addNodeMeasurements() {
    if (nodeMap == null)
        return;
    // If 0, no averaging is performed
    // If 1, the averages of each object's measurements & those of its immediate neighbors are added
    // If 2, the neighbors of the neighbors are included as well
    // If 3, the neighbors or the neighbors of the neighbors are included... and so on...
    int averagingSeparation = 0;
    String[] measurementNames = new String[0];
    double[] averagedMeasurements = new double[0];
    Set<PathObject> neighborSet = new HashSet<>();
    for (Entry<PathObject, DelaunayNode> entry : nodeMap.entrySet()) {
        MeasurementList measurementList = entry.getKey().getMeasurementList();
        DelaunayNode node = entry.getValue();
        // Create a set of neighbors
        if (averagingSeparation > 0) {
            neighborSet.clear();
            node.addNeighborsToSet(neighborSet, averagingSeparation);
            // Get the smoothed measurements now, since access is likely to be much faster we start modifying it
            measurementNames = measurementList.getMeasurementNames().toArray(measurementNames);
            if (averagedMeasurements.length < measurementNames.length)
                averagedMeasurements = new double[measurementNames.length];
            for (int i = 0; i < measurementNames.length; i++) {
                String name = measurementNames[i];
                if (name == null || name.startsWith("Delaunay"))
                    continue;
                double sum = 0;
                int n = 0;
                for (PathObject tempObject : neighborSet) {
                    double value = tempObject.getMeasurementList().getMeasurementValue(name);
                    if (Double.isNaN(value))
                        continue;
                    sum += value;
                    n++;
                }
                averagedMeasurements[i] = n > 0 ? sum / n : Double.NaN;
            }
        }
        // TODO: PUT MEASUREMENTS IN UNITS OTHER THAN PIXELS????
        measurementList.putMeasurement("Delaunay: Num neighbors", node.nNeighbors());
        measurementList.putMeasurement("Delaunay: Mean distance", node.meanDistance());
        measurementList.putMeasurement("Delaunay: Median distance", node.medianDistance());
        measurementList.putMeasurement("Delaunay: Max distance", node.maxDistance());
        measurementList.putMeasurement("Delaunay: Min distance", node.minDistance());
        // measurementList.putMeasurement("Delaunay: Displacement sum mag", node.magDisplacementSum());
        measurementList.putMeasurement("Delaunay: Mean triangle area", node.getMeanTriangleArea());
        measurementList.putMeasurement("Delaunay: Max triangle area", node.getMaxTriangleArea());
        // Put in averaged measurements using immediate neighbours
        if (averagingSeparation > 0) {
            for (int i = 0; i < measurementNames.length; i++) {
                String name = measurementNames[i];
                if (name == null || name.startsWith("Delaunay"))
                    continue;
                measurementList.putMeasurement("Delaunay averaged (" + averagingSeparation + "): " + name, averagedMeasurements[i]);
            }
        }
        measurementList.close();
    }
}
Also used : PathObject(qupath.lib.objects.PathObject) MeasurementList(qupath.lib.measurements.MeasurementList) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 17 with MeasurementList

use of qupath.lib.measurements.MeasurementList in project qupath by qupath.

the class PathObjectTools method transformObject.

/**
 * Create a(n optionally) transformed version of a {@link PathObject}.
 * <p>
 * Note: only detections (including tiles and cells) and annotations are fully supported by this method.
 * Root objects are duplicated.
 * TMA core objects are transformed only if the resulting transform creates an ellipse ROI, since this is
 * currently the only ROI type supported for a TMA core (this behavior may change).
 * Any other object types result in an {@link UnsupportedOperationException} being thrown.
 *
 * @param pathObject the object to transform; this will be unchanged
 * @param transform optional affine transform; if {@code null}, this effectively acts to duplicate the object
 * @param copyMeasurements if true, the measurement list of the new object will be populated with the measurements of pathObject
 *
 * @return a duplicate of pathObject, with affine transform applied to the object's ROI(s) if required
 */
public static PathObject transformObject(PathObject pathObject, AffineTransform transform, boolean copyMeasurements) {
    ROI roi = maybeTransformROI(pathObject.getROI(), transform);
    PathClass pathClass = pathObject.getPathClass();
    PathObject newObject;
    if (pathObject instanceof PathCellObject) {
        ROI roiNucleus = maybeTransformROI(((PathCellObject) pathObject).getNucleusROI(), transform);
        newObject = PathObjects.createCellObject(roi, roiNucleus, pathClass, null);
    } else if (pathObject instanceof PathTileObject) {
        newObject = PathObjects.createTileObject(roi, pathClass, null);
    } else if (pathObject instanceof PathDetectionObject) {
        newObject = PathObjects.createDetectionObject(roi, pathClass, null);
    } else if (pathObject instanceof PathAnnotationObject) {
        newObject = PathObjects.createAnnotationObject(roi, pathClass, null);
    } else if (pathObject instanceof PathRootObject) {
        newObject = new PathRootObject();
    } else if (pathObject instanceof TMACoreObject && roi instanceof EllipseROI) {
        var core = (TMACoreObject) pathObject;
        newObject = PathObjects.createTMACoreObject(roi.getBoundsX(), roi.getBoundsY(), roi.getBoundsWidth(), roi.getBoundsHeight(), core.isMissing());
    } else
        throw new UnsupportedOperationException("Unable to transform object " + pathObject);
    if (copyMeasurements && !pathObject.getMeasurementList().isEmpty()) {
        MeasurementList measurements = pathObject.getMeasurementList();
        for (int i = 0; i < measurements.size(); i++) {
            String name = measurements.getMeasurementName(i);
            double value = measurements.getMeasurementValue(i);
            newObject.getMeasurementList().addMeasurement(name, value);
        }
        newObject.getMeasurementList().close();
    }
    return newObject;
}
Also used : MeasurementList(qupath.lib.measurements.MeasurementList) EllipseROI(qupath.lib.roi.EllipseROI) PointsROI(qupath.lib.roi.PointsROI) LineROI(qupath.lib.roi.LineROI) ROI(qupath.lib.roi.interfaces.ROI) PathClass(qupath.lib.objects.classes.PathClass) EllipseROI(qupath.lib.roi.EllipseROI)

Example 18 with MeasurementList

use of qupath.lib.measurements.MeasurementList in project qupath by qupath.

the class HaralickFeaturesPlugin method processObject.

static boolean processObject(final PathObject pathObject, final ParameterList params, final ImageServer<BufferedImage> server, final ColorDeconvolutionStains stains) throws IOException {
    String stainsName = (String) params.getChoiceParameterValue("stainChoice");
    double mag = params.getDoubleParameterValue("magnification");
    int d = params.getIntParameterValue("haralickDistance");
    int nBins = params.getIntParameterValue("haralickBins");
    boolean includeStats = params.getBooleanParameterValue("includeStats");
    boolean doCircular = params.getBooleanParameterValue("doCircular");
    double downsample;
    boolean hasMagnification = !Double.isNaN(server.getMetadata().getMagnification());
    PixelCalibration cal = server.getPixelCalibration();
    if (hasMagnification)
        downsample = server.getMetadata().getMagnification() / mag;
    else if (cal.hasPixelSizeMicrons()) {
        downsample = params.getDoubleParameterValue("pixelSizeMicrons") / cal.getAveragedPixelSizeMicrons();
    } else
        downsample = params.getDoubleParameterValue("downsample");
    // double downsample = server.getMagnification() / mag;
    // Try to get ROI
    ROI pathROI = null;
    if (pathObject instanceof PathCellObject && Boolean.TRUE.equals(params.getBooleanParameterValue("useNucleusROIs")))
        pathROI = ((PathCellObject) pathObject).getNucleusROI();
    else
        pathROI = pathObject.getROI();
    if (pathROI == null)
        return false;
    // Get bounds
    ImmutableDimension size = getPreferredTileSizePixels(server, params);
    RegionRequest region;
    boolean createMaskROI = false;
    if (size.getWidth() <= 0 || size.getHeight() <= 0) {
        region = RegionRequest.createInstance(server.getPath(), downsample, pathObject.getROI());
        createMaskROI = true;
        doCircular = false;
    } else if (size.getWidth() / downsample < 1 || size.getHeight() / downsample < 1)
        // Positive size, but insufficient to make measurements
        return false;
    else {
        // RegionRequest region = RegionRequest.createInstance(server.getPath(), downsample, (int)(pathROI.getCentroidX() + .5) - size.width/2, (int)(pathROI.getCentroidY() + .5) - size.height/2, size.width, size.height, pathROI.getT(), pathROI.getZ());
        // Try to align with pixel boundaries according to the downsample being used - otherwise, interpolation can cause some strange, pattern artefacts
        int xStart = (int) ((int) (pathROI.getCentroidX() / downsample + .5) * downsample) - size.width / 2;
        int yStart = (int) ((int) (pathROI.getCentroidY() / downsample + .5) * downsample) - size.height / 2;
        int width = Math.min(server.getWidth(), xStart + size.width) - xStart;
        int height = Math.min(server.getHeight(), yStart + size.height) - yStart;
        region = RegionRequest.createInstance(server.getPath(), downsample, xStart, yStart, width, height, pathROI.getT(), pathROI.getZ());
    }
    // Check image large enough to do *anything* of value
    if (region.getWidth() / downsample < 3 || region.getHeight() / downsample < 3)
        return false;
    // System.out.println(bounds);
    // System.out.println("Size: " + size);
    BufferedImage img = server.readBufferedImage(region);
    if (img == null) {
        logger.error("Could not read image - unable to compute Haralick features for {}", pathObject);
        return false;
    }
    // Create mask ROI if necessary
    byte[] maskBytes = null;
    if (createMaskROI) {
        ROI roi = pathObject.getROI();
        // if (pathObject instanceof PathCellObject && ((PathCellObject)pathObject).getNucleusROI() != null)
        // roi = ((PathCellObject)pathObject).getNucleusROI();
        BufferedImage imgMask = BufferedImageTools.createROIMask(img.getWidth(), img.getHeight(), roi, region);
        maskBytes = ((DataBufferByte) imgMask.getRaster().getDataBuffer()).getData();
    }
    double minValue = Double.NaN;
    double maxValue = Double.NaN;
    // Get a buffer containing the image pixels
    int w = img.getWidth();
    int h = img.getHeight();
    int[] buf = img.getRGB(0, 0, w, h, null, 0, w);
    // Create a color transformer to get the images we need
    float[] pixels = new float[buf.length];
    SimpleModifiableImage pxImg = SimpleImages.createFloatImage(pixels, w, h);
    MeasurementList measurementList = pathObject.getMeasurementList();
    String postfix = maskBytes == null ? " (" + getDiameterString(server, params) + ")" : "";
    if (stainsName.equals("H-DAB")) {
        minValue = 0;
        maxValue = 2.0;
        processTransformedImage(pxImg, buf, pixels, measurementList, "Hematoxylin" + postfix, ColorTransformer.ColorTransformMethod.Hematoxylin_H_DAB, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "DAB" + postfix, ColorTransformer.ColorTransformMethod.DAB_H_DAB, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
    } else if (stainsName.equals("H&E")) {
        minValue = 0;
        maxValue = 2;
        processTransformedImage(pxImg, buf, pixels, measurementList, "Hematoxylin" + postfix, ColorTransformer.ColorTransformMethod.Hematoxylin_H_E, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "Eosin" + postfix, ColorTransformer.ColorTransformMethod.Eosin_H_E, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
    } else if (stainsName.equals("H-DAB (8-bit)")) {
        minValue = 0;
        maxValue = 255;
        processTransformedImage(pxImg, buf, pixels, measurementList, "Hematoxylin 8-bit" + postfix, ColorTransformer.ColorTransformMethod.Hematoxylin_H_DAB_8_bit, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "DAB 8-bit" + postfix, ColorTransformer.ColorTransformMethod.DAB_H_DAB_8_bit, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
    } else if (stainsName.equals("H&E (8-bit)")) {
        minValue = 0;
        maxValue = 255;
        processTransformedImage(pxImg, buf, pixels, measurementList, "Hematoxylin 8-bit" + postfix, ColorTransformer.ColorTransformMethod.Hematoxylin_H_E_8_bit, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "Eosin 8-bit" + postfix, ColorTransformer.ColorTransformMethod.Eosin_H_E_8_bit, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
    } else if (stainsName.equals("Optical density")) {
        minValue = 0;
        maxValue = 2.5;
        processTransformedImage(pxImg, buf, pixels, measurementList, "OD sum" + postfix, ColorTransformer.ColorTransformMethod.Optical_density_sum, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
    } else if (stainsName.equals("RGB")) {
        minValue = 0;
        maxValue = 255;
        processTransformedImage(pxImg, buf, pixels, measurementList, "Red" + postfix, ColorTransformer.ColorTransformMethod.Red, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "Green" + postfix, ColorTransformer.ColorTransformMethod.Green, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "Blue" + postfix, ColorTransformer.ColorTransformMethod.Blue, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
    } else if (stainsName.equals("RGB OD")) {
        minValue = 0;
        // Actual possible max is around 2.4 for 8-bit input... but this gives a lot of bins for (almost) saturated pixels
        maxValue = 1.5;
        processTransformedImage(pxImg, buf, pixels, measurementList, "Red OD" + postfix, ColorTransformer.ColorTransformMethod.Red_OD, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "Green OD" + postfix, ColorTransformer.ColorTransformMethod.Green_OD, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "Blue OD" + postfix, ColorTransformer.ColorTransformMethod.Blue_OD, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
    } else if (stainsName.equals("Grayscale")) {
        minValue = 0;
        maxValue = 255;
        processTransformedImage(pxImg, buf, pixels, measurementList, "Grayscale" + postfix, ColorTransformer.ColorTransformMethod.RGB_mean, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
    } else if (stainsName.equals("HSB")) {
        minValue = 0;
        maxValue = 1;
        float[] hsb = null;
        double sinX = 0;
        double cosX = 0;
        float[] pixelsBrightness = new float[pixels.length];
        float[] pixelsSaturation = new float[pixels.length];
        for (int i = 0; i < buf.length; i++) {
            if (maskBytes != null && maskBytes[i] == (byte) 0)
                continue;
            int val = buf[i];
            hsb = Color.RGBtoHSB(ColorTools.red(val), ColorTools.green(val), ColorTools.blue(val), hsb);
            pixelsSaturation[i] = hsb[1];
            pixelsBrightness[i] = hsb[2];
            double alpha = hsb[0] * 2 * Math.PI;
            sinX += Math.sin(alpha);
            cosX += Math.cos(alpha);
        }
        measurementList.putMeasurement("Mean hue", Math.atan2(sinX, cosX) / (2 * Math.PI) + 0.5);
        // measurementList.putMeasurement("Mean saturation", hsb[1]);
        // measurementList.putMeasurement("Mean brightness", hsb[2]);
        processTransformedImage(SimpleImages.createFloatImage(pixelsSaturation, w, h), buf, pixelsSaturation, measurementList, "Saturation" + postfix, null, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
        processTransformedImage(SimpleImages.createFloatImage(pixelsBrightness, w, h), buf, pixelsBrightness, measurementList, "Brightness" + postfix, null, minValue, maxValue, d, nBins, stains, maskBytes, includeStats, doCircular);
    }
    measurementList.close();
    return true;
}
Also used : MeasurementList(qupath.lib.measurements.MeasurementList) PixelCalibration(qupath.lib.images.servers.PixelCalibration) ROI(qupath.lib.roi.interfaces.ROI) BufferedImage(java.awt.image.BufferedImage) SimpleModifiableImage(qupath.lib.analysis.images.SimpleModifiableImage) ImmutableDimension(qupath.lib.geom.ImmutableDimension) RegionRequest(qupath.lib.regions.RegionRequest) PathCellObject(qupath.lib.objects.PathCellObject)

Example 19 with MeasurementList

use of qupath.lib.measurements.MeasurementList in project qupath by qupath.

the class CoherenceFeaturePlugin method processObject.

static boolean processObject(final PathObject pathObject, final ParameterList params, final ImageServer<BufferedImage> server, final ColorDeconvolutionStains stains) throws InterruptedException, IOException {
    String stainsName = (String) params.getChoiceParameterValue("stainChoice");
    double mag = params.getDoubleParameterValue("magnification");
    boolean includeStats = params.getBooleanParameterValue("includeStats");
    boolean doCircular = params.getBooleanParameterValue("doCircular");
    double downsample = server.getMetadata().getMagnification() / mag;
    ROI pathROI = pathObject.getROI();
    if (pathROI == null)
        return false;
    // Get bounds
    ImmutableDimension size = getPreferredTileSizePixels(server, params);
    if (size.getWidth() / downsample < 1 || size.getHeight() / downsample < 1)
        return false;
    // RegionRequest region = RegionRequest.createInstance(server.getPath(), downsample, (int)(pathROI.getCentroidX() + .5) - size.width/2, (int)(pathROI.getCentroidY() + .5) - size.height/2, size.width, size.height, pathROI.getT(), pathROI.getZ());
    // Try to align with pixel boundaries according to the downsample being used - otherwise, interpolation can cause some strange, pattern artefacts
    int xStart = (int) ((int) (pathROI.getCentroidX() / downsample + .5) * downsample) - size.width / 2;
    int yStart = (int) ((int) (pathROI.getCentroidY() / downsample + .5) * downsample) - size.height / 2;
    int width = Math.min(server.getWidth(), xStart + size.width) - xStart;
    int height = Math.min(server.getHeight(), yStart + size.height) - yStart;
    RegionRequest region = RegionRequest.createInstance(server.getPath(), downsample, xStart, yStart, width, height, pathROI.getT(), pathROI.getZ());
    // System.out.println(bounds);
    // System.out.println("Size: " + size);
    BufferedImage img = server.readBufferedImage(region);
    // Get a buffer containing the image pixels
    int w = img.getWidth();
    int h = img.getHeight();
    int[] buf = img.getRGB(0, 0, w, h, null, 0, w);
    // Create a color transformer to get the images we need
    float[] pixels = new float[buf.length];
    SimpleModifiableImage pxImg = SimpleImages.createFloatImage(pixels, w, h);
    MeasurementList measurementList = pathObject.getMeasurementList();
    String postfix = " (" + getDiameterString(server, params) + ")";
    if (stainsName.equals("H-DAB")) {
        processTransformedImage(pxImg, buf, pixels, measurementList, "Hematoxylin" + postfix, ColorTransformer.ColorTransformMethod.Hematoxylin_H_DAB, stains, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "DAB" + postfix, ColorTransformer.ColorTransformMethod.DAB_H_DAB, stains, includeStats, doCircular);
    } else if (stainsName.equals("H&E")) {
        processTransformedImage(pxImg, buf, pixels, measurementList, "Hematoxylin" + postfix, ColorTransformer.ColorTransformMethod.Hematoxylin_H_E, stains, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "Eosin" + postfix, ColorTransformer.ColorTransformMethod.Eosin_H_E, stains, includeStats, doCircular);
    } else if (stainsName.equals("H-DAB (8-bit)")) {
        processTransformedImage(pxImg, buf, pixels, measurementList, "Hematoxylin 8-bit" + postfix, ColorTransformer.ColorTransformMethod.Hematoxylin_H_DAB_8_bit, stains, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "DAB 8-bit" + postfix, ColorTransformer.ColorTransformMethod.DAB_H_DAB_8_bit, stains, includeStats, doCircular);
    } else if (stainsName.equals("H&E (8-bit)")) {
        processTransformedImage(pxImg, buf, pixels, measurementList, "Hematoxylin 8-bit" + postfix, ColorTransformer.ColorTransformMethod.Hematoxylin_H_E_8_bit, stains, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "Eosin 8-bit" + postfix, ColorTransformer.ColorTransformMethod.Eosin_H_E_8_bit, stains, includeStats, doCircular);
    } else if (stainsName.equals("Optical density")) {
        processTransformedImage(pxImg, buf, pixels, measurementList, "OD sum" + postfix, ColorTransformer.ColorTransformMethod.Optical_density_sum, stains, includeStats, doCircular);
    } else if (stainsName.equals("RGB")) {
        processTransformedImage(pxImg, buf, pixels, measurementList, "Red" + postfix, ColorTransformer.ColorTransformMethod.Red, stains, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "Green" + postfix, ColorTransformer.ColorTransformMethod.Green, stains, includeStats, doCircular);
        processTransformedImage(pxImg, buf, pixels, measurementList, "Blue" + postfix, ColorTransformer.ColorTransformMethod.Blue, stains, includeStats, doCircular);
    } else if (stainsName.equals("Grayscale")) {
        processTransformedImage(pxImg, buf, pixels, measurementList, "Grayscale" + postfix, ColorTransformer.ColorTransformMethod.RGB_mean, stains, includeStats, doCircular);
    }
    measurementList.close();
    return true;
}
Also used : SimpleModifiableImage(qupath.lib.analysis.images.SimpleModifiableImage) MeasurementList(qupath.lib.measurements.MeasurementList) ImmutableDimension(qupath.lib.geom.ImmutableDimension) ROI(qupath.lib.roi.interfaces.ROI) RegionRequest(qupath.lib.regions.RegionRequest) BufferedImage(java.awt.image.BufferedImage)

Example 20 with MeasurementList

use of qupath.lib.measurements.MeasurementList in project qupath by qupath.

the class PathObjectTestWrapper method test_getMeasurementList.

// @Test
public void test_getMeasurementList(PathObject myPO) {
    MeasurementList myPOML = myPO.getMeasurementList();
    assertTrue(myPOML instanceof MeasurementList);
}
Also used : MeasurementList(qupath.lib.measurements.MeasurementList)

Aggregations

MeasurementList (qupath.lib.measurements.MeasurementList)24 PathObject (qupath.lib.objects.PathObject)12 ArrayList (java.util.ArrayList)9 ROI (qupath.lib.roi.interfaces.ROI)9 BufferedImage (java.awt.image.BufferedImage)6 RegionRequest (qupath.lib.regions.RegionRequest)6 List (java.util.List)5 PixelCalibration (qupath.lib.images.servers.PixelCalibration)5 IOException (java.io.IOException)4 HashMap (java.util.HashMap)4 TMACoreObject (qupath.lib.objects.TMACoreObject)4 PathClass (qupath.lib.objects.classes.PathClass)4 LinkedHashSet (java.util.LinkedHashSet)3 Map (java.util.Map)3 SimpleModifiableImage (qupath.lib.analysis.images.SimpleModifiableImage)3 ImmutableDimension (qupath.lib.geom.ImmutableDimension)3 PathCellObject (qupath.lib.objects.PathCellObject)3 ParameterList (qupath.lib.plugins.parameters.ParameterList)3 Calibration (ij.measure.Calibration)2 ImageProcessor (ij.process.ImageProcessor)2