Skip to content

Instantly share code, notes, and snippets.

@petebankhead
Created March 22, 2022 08:46
Show Gist options
  • Select an option

  • Save petebankhead/a2b08b9c3afb399b2dbf4d66915eb788 to your computer and use it in GitHub Desktop.

Select an option

Save petebankhead/a2b08b9c3afb399b2dbf4d66915eb788 to your computer and use it in GitHub Desktop.
Export annotations representing instance labels from an image, in QuPath v0.3
/*
* Export annotations representing instance labels from an image.
*
* This supports exporting regions of an image (rather than the whole thing)
* defined using the annotation shape (i.e. rectangle) or classification.
*
* See the comments for more information, and parameters to adjust.
*
* Note that the instance labels are applied globalled, so if multiple distinct
* regions are export, the labels are not guaranteed to start from 1 or be consecutive
* in each region.
* This is a feature, not a bug, since it helps in cases whenever exported regions may overlap,
* or if a single instance is split across multiple exported regions.
*
* Note all that the file paths assume images are stored in a project.
* See https://qupath.readthedocs.io/en/stable/docs/tutorials/projects.html for more information.
*
* Written for QuPath v0.3.
*
* @author Pete Bankhead
*/
// Define image export file extensions
def ext = ".png"
def labelsExt = "-labels.png"
// Define output resolution, or -1 to export at full resolution
double requestedPixelSize = -1
// Get the current image
def imageData = getCurrentImageData()
def server = imageData.getServer()
// Select the regions we want to export, if needed
// Uncomment to select all annotations with rectangle ROIs
selectObjects(p -> p.isAnnotation() && p.getROI() instanceof qupath.lib.roi.RectangleROI)
// Uncomment to select all annotations classified as 'Region*'
//selectObjects(p -> p.isAnnotation() && p.getPathClass() == getPathClass('Region*'))
// Get the parent objects (the selected one that we want to use to define export regions)
def parents = getSelectedObjects()
// Add null to indicate we should export the whole image
if (!parents)
parents = [null]
// Define output path (relative to project)
def imageName = GeneralTools.getNameWithoutExtension(imageData.getServer().getMetadata().getName())
def pathOutput = buildFilePath(PROJECT_BASE_DIR, 'export')
mkdirs(pathOutput)
// Convert to downsample
double downsample = requestedPixelSize <= 0 ? 1.0 : requestedPixelSize / imageData.getServer().getPixelCalibration().getAveragedPixelSize()
// Create an ImageServer where the pixels are derived from annotations
def labelServer = new LabeledImageServer.Builder(imageData)
.backgroundLabel(0, ColorTools.WHITE) // Specify background label (usually 0 or 255)
.useInstanceLabels()
.useFilter(p -> p.isAnnotation() && !parents.contains(p)) // Avoid reusing the selected objects in the export
.build()
// Export each region
for (p in parents) {
// Write the first region
def region, name
if (p == null || p.getROI() == null) {
region = RegionRequest.createInstance(server, downsample)
name = "$imageName$ext"
} else {
region = RegionRequest.createInstance(server.getPath(), downsample, p.getROI())
name = "$imageName [$region.x, $region.y, $region.width, $region.height]$ext"
}
def outputPath = buildFilePath(pathOutput, name)
writeImageRegion(server, region, outputPath)
// Write the labels
def outputPathLabels = buildFilePath(pathOutput, name.substring(0, name.length()-ext.length()) + labelsExt)
def regionLabels = region.updatePath(labelServer.getPath())
writeImageRegion(labelServer, regionLabels, outputPathLabels)
}
println "Written ${parents.size()} region(s)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment