Created
July 8, 2020 16:23
-
-
Save petebankhead/6caf71249f7511288805fb659f877698 to your computer and use it in GitHub Desktop.
Create a 'counts' image in QuPath that can be used to compute the local density of specific objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Create a 'counts' image in QuPath that can be used to compute the local density of specific objects. | |
* | |
* This implementation uses ImageJ to create and display the image, which can then be filtered as required. | |
* | |
* Written for QuPath v0.2.0. | |
* | |
* @author Pete Bankhead | |
*/ | |
import ij.ImagePlus | |
import ij.process.FloatProcessor | |
import qupath.imagej.gui.IJExtension | |
import qupath.lib.objects.PathObjectTools | |
import qupath.lib.regions.RegionRequest | |
import static qupath.lib.gui.scripting.QPEx.* | |
import qupath.imagej.tools.IJTools | |
// Define the resolution at which the image should be generated | |
double requestedPixelSizeMicrons = 20 | |
// Get the current image | |
def imageData = getCurrentImageData() | |
def server = imageData.getServer() | |
// Set the downsample directly (without using the requestedPixelSize) if you want; 1.0 indicates the full resolution | |
double downsample = requestedPixelSizeMicrons / server.getPixelCalibration().getAveragedPixelSizeMicrons() | |
def request = RegionRequest.createInstance(server, downsample) | |
def imp = IJTools.convertToImagePlus(server, request).getImage() | |
// Get the objects you want to count | |
// Potentially you can add filters for specific objects, e.g. to get only those with a 'Positive' classification | |
def detections = getDetectionObjects() | |
//detections = detections.findAll {it.getPathClass() == getPathClass('Positive')} | |
// Create a counts image in ImageJ, where each pixel corresponds to the number of centroids at that pixel | |
int width = imp.getWidth() | |
int height = imp.getHeight() | |
def fp = new FloatProcessor(width, height) | |
for (detection in detections) { | |
// Get ROI for a detection; this method gets the nucleus if we have a cell object (and the only ROI for anything else) | |
def roi = PathObjectTools.getROI(detection, true) | |
int x = (int)(roi.getCentroidX() / downsample) | |
int y = (int)(roi.getCentroidY() / downsample) | |
fp.setf(x, y, fp.getf(x, y) + 1 as float) | |
} | |
// Show the images | |
IJExtension.getImageJInstance() | |
imp.show() | |
new ImagePlus(imp.getTitle() + "-counts", fp).show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yes, it is definitely a result of rounding. Thanks for the fix on my non-fix (which you are correct, just shifted the error). We were looking into the densityMaps class but have not had the time to figure out the correct way to script them.