use of qupath.lib.regions.RegionRequest in project qupath by qupath.
the class DensityMapDataOp method apply.
@Override
public Mat apply(ImageData<BufferedImage> imageData, RegionRequest request) throws IOException {
ensureInitialized();
logger.trace("Applying density map op for {}", request);
// Calculate how much padding we need
var padding = op.getPadding();
if (!padding.isEmpty()) {
// Add padding to the request
double downsample = request.getDownsample();
var padding2 = Padding.getPadding((int) Math.round(padding.getX1() * downsample), (int) Math.round(padding.getX2() * downsample), (int) Math.round(padding.getY1() * downsample), (int) Math.round(padding.getY2() * downsample));
request = request.pad2D(padding2);
}
// Get all objects within the padded region
var allPathObjects = imageData.getHierarchy().getObjectsForRegion(null, request, null).stream().filter(allObjects).collect(Collectors.toList());
if (allPathObjects.size() == 1)
logger.trace("Generating counts tile for 1 object");
else
logger.trace("Generating counts tile for {} objects", allPathObjects.size());
// Create an output mat
int nChannels = getChannelCount();
int width = (int) Math.round(request.getWidth() / request.getDownsample());
int height = (int) Math.round(request.getHeight() / request.getDownsample());
var mat = new Mat(height, width, opencv_core.CV_64FC(nChannels), Scalar.ZERO);
DoubleIndexer idx = mat.createIndexer();
// Get points representing all the centroids of each subpopulation of object
// Use these to increment pixel values in a counts image
int c = 0;
for (var entry : primaryObjects.entrySet()) {
var predicate = entry.getValue();
var primaryROIs = allPathObjects.stream().filter(predicate).map(p -> PathObjectTools.getROI(p, true)).collect(Collectors.toList());
var points = objectsToPoints(primaryROIs);
incrementCounts(idx, points, request, width, height, c);
c++;
}
// Get points for all objects, if we need them
if (c < getChannelCount()) {
var allObjectROIs = allPathObjects.stream().map(p -> PathObjectTools.getROI(p, true)).collect(Collectors.toList());
var points = objectsToPoints(allObjectROIs);
incrementCounts(idx, points, request, width, height, c);
c++;
}
idx.close();
// Now apply the op
var output = this.op.apply(mat);
return output;
}
use of qupath.lib.regions.RegionRequest 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;
}
use of qupath.lib.regions.RegionRequest 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;
}
use of qupath.lib.regions.RegionRequest in project qupath by qupath.
the class IJTools method extractHyperstack.
/**
* Extract a full ImageJ hyperstack for a specific region, for specified ranges of z-slices and time points.
*
* @param server server from which to extract pixels
* @param request region and downsample value; if null, the entire image is used
* @param zStart starting z-slice index (0-based index)
* @param zEnd ending z-slice index (exclusive)
* @param tStart starting timepoint index (0-based index)
* @param tEnd ending timepoint index (exclusive)
* @return the ImageJ hyperstack
* @throws IOException
*/
public static ImagePlus extractHyperstack(ImageServer<BufferedImage> server, RegionRequest request, int zStart, int zEnd, int tStart, int tEnd) throws IOException {
if (request == null)
request = RegionRequest.createInstance(server);
int nChannels = -1;
int nZ = zEnd - zStart;
int nT = tEnd - tStart;
double downsample = request.getDownsample();
ImageStack stack = null;
Calibration cal = null;
for (int t = tStart; t < tEnd; t++) {
for (int z = zStart; z < zEnd; z++) {
RegionRequest request2 = RegionRequest.createInstance(server.getPath(), downsample, request.getX(), request.getY(), request.getWidth(), request.getHeight(), z, t);
ImagePlus imp = IJTools.convertToImagePlus(server, request2).getImage();
if (stack == null) {
stack = new ImageStack(imp.getWidth(), imp.getHeight());
}
// Append to original image stack
for (int i = 1; i <= imp.getStack().getSize(); i++) {
stack.addSlice(imp.getStack().getSliceLabel(i), imp.getStack().getProcessor(i));
}
// Get the last calibration
cal = imp.getCalibration();
nChannels = imp.getNChannels();
}
}
PixelCalibration pixelCalibration = server.getPixelCalibration();
if (cal != null && !Double.isNaN(pixelCalibration.getZSpacingMicrons())) {
cal.pixelDepth = pixelCalibration.getZSpacingMicrons();
cal.setZUnit("um");
}
String name = ServerTools.getDisplayableImageName(server);
ImagePlus imp = new ImagePlus(name, stack);
CompositeImage impComp = null;
if (imp.getType() != ImagePlus.COLOR_RGB && nChannels > 1) {
impComp = new CompositeImage(imp, CompositeImage.COMPOSITE);
imp = impComp;
}
imp.setCalibration(cal);
imp.setDimensions(nChannels, nZ, nT);
// Set colors, if necesssary
if (impComp != null) {
for (int c = 0; c < nChannels; c++) {
impComp.setChannelLut(LUT.createLutFromColor(ColorToolsAwt.getCachedColor(server.getChannel(c).getColor())), c + 1);
}
}
return imp;
}
use of qupath.lib.regions.RegionRequest in project qupath by qupath.
the class AbstractImageServer method getDefaultThumbnail.
@Override
public T getDefaultThumbnail(int z, int t) throws IOException {
int ind = nResolutions() - 1;
double targetDownsample = Math.sqrt(getWidth() / 1024.0 * getHeight() / 1024.0);
double[] downsamples = getPreferredDownsamples();
while (ind > 0 && downsamples[ind - 1] >= targetDownsample) ind--;
double downsample = downsamples[ind];
RegionRequest request = RegionRequest.createInstance(getPath(), downsample, 0, 0, getWidth(), getHeight(), z, t);
return readBufferedImage(request);
}
Aggregations