Created
March 22, 2022 08:46
-
-
Save petebankhead/a2b08b9c3afb399b2dbf4d66915eb788 to your computer and use it in GitHub Desktop.
Export annotations representing instance labels from an image, in QuPath v0.3
This file contains hidden or 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
| /* | |
| * 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