Last active
July 30, 2023 14:32
-
-
Save lacan/d284ef91160f9242ab8ce3a65b72cbd6 to your computer and use it in GitHub Desktop.
[QuPath Script To Export Annotations For Stardist] this script will take rectangular annotations in QuPath and export them and their containing objects as images and masks for deep neural netowrk training #qupath #stardist #BIOP
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
/* | |
// ABOUT | |
Exports Annotations for StarDist (Or other Deep Learning frameworks) | |
// INPUTS | |
You need rectangular annotations that have classes "Training" and "Validation" | |
After you have placed these annotations, lock them and start drawing the objects inside | |
// OUTPUTS | |
---------- | |
The script will export each annotation and whatever is contained within as an image-label pair | |
These will be placed in the folder specified by the user in the main project directory. | |
Inside that directory, you will find 'train' and 'test' directories that contain the images with | |
class 'Training' and 'Validation', respectively. | |
Inside each, you will find 'images' and 'masks' folders containing the exported image and the labels, | |
respectively. The naming convention was chosen to match the one used for the StarDist DSBdataset | |
//PARAMETERS | |
------------ | |
- channel_of_interest: You can export a single channel or all of them, currently no option for _some_ channels only | |
- downsample: you can downsample your image in case it does not make sense for you to train on the full resolution | |
- export_directory: name of the directory which will contain the 'train' and 'test' subdirectories | |
Authors: Olivier Burri, Romain Guiet, BioImaging & Optics Platform (EPFL BIOP) | |
Tested on QuPath 0.2.3, October 21st 2020 | |
Due to the simple nature of this code, no copyright is applicable | |
*/ | |
// USER SETTINGS | |
def channel_of_interest = 1 // null to export all the channels | |
def downsample = 1 | |
// START OF SCRIPT | |
println("Image: "+getProjectEntry().getImageName()) | |
def training_regions = getAnnotationObjects().findAll { it.getPathClass() == getPathClass("Training") } | |
def validation_regions = getAnnotationObjects().findAll { it.getPathClass() == getPathClass("Validation") } | |
if (training_regions.size() > 0 ) saveRegions( training_regions, channel_of_interest, downsample, 'train') | |
if (validation_regions.size() > 0 ) saveRegions( validation_regions, channel_of_interest, downsample, 'test') | |
println "done" | |
def saveRegions( def regions, def channel, def downsample, def type ) { | |
// Randomize names | |
def is_randomized = getProject().getMaskImageNames() | |
getProject().setMaskImageNames(true) | |
def rm = RoiManager.getRoiManager() ?: new RoiManager() | |
// Get the image name | |
def image_name = getProjectEntry().getImageName() | |
regions.eachWithIndex{ region, region_idx -> | |
println("Processing Region #"+( region_idx + 1 ) ) | |
def file_name = image_name+"_r"+( region_idx + 1 ) | |
imageData = getCurrentImageData(); | |
server = imageData.getServer(); | |
viewer = getCurrentViewer(); | |
hierarchy = getCurrentHierarchy(); | |
pathImage = null; | |
request = RegionRequest.createInstance(imageData.getServerPath(), downsample, region.getROI()) | |
pathImage = IJExtension.extractROIWithOverlay(server, region, hierarchy, request, false, viewer.getOverlayOptions()); | |
image = pathImage.getImage() | |
//println("Image received" ) | |
//image.show() | |
// Create the Labels image | |
def labels = IJ.createImage( "Labels", "16-bit black", image.getWidth(), image.getHeight() ,1 ); | |
rm.reset() | |
IJ.run(image, "To ROI Manager", "") | |
def rois = rm.getRoisAsArray() as List | |
//println("Creating Labels" ) | |
def label_ip = labels.getProcessor() | |
def idx = 0 | |
print( "Ignoring Rectangles: " ) | |
rois.each{ roi -> | |
if (roi.getType() == Roi.RECTANGLE) { | |
print( "." ) | |
} else { | |
label_ip.setColor( ++idx ) | |
label_ip.setRoi( roi ) | |
label_ip.fill( roi ) | |
} | |
} | |
print("\n") | |
labels.setProcessor( label_ip ) | |
//labels.show() | |
// Split to keep only channel of interest | |
def output = image | |
if ( channel != null ){ | |
imp_chs = ChannelSplitter.split( image ) | |
output = imp_chs[ channel - 1 ] | |
} | |
saveImages(output, labels, file_name, type) | |
//println( file_name + " Image and Mask Saved." ) | |
// Save some RAM | |
output.close() | |
labels.close() | |
image.close() | |
} | |
// Return Project setup as it was before | |
getProject().setMaskImageNames( is_randomized ) | |
} | |
// This will save the images in the selected folder | |
def saveImages(def images, def labels, def name, def type) { | |
def source_folder = new File ( buildFilePath( PROJECT_BASE_DIR, 'ground_truth', type, 'images' ) ) | |
def target_folder = new File ( buildFilePath( PROJECT_BASE_DIR, 'ground_truth', type, 'masks' ) ) | |
mkdirs( source_folder.getAbsolutePath() ) | |
mkdirs( target_folder.getAbsolutePath() ) | |
IJ.save( images , new File ( source_folder, name ).getAbsolutePath()+'.tif' ) | |
IJ.save( labels , new File ( target_folder, name ).getAbsolutePath()+'.tif' ) | |
} | |
// Manage Imports | |
import qupath.lib.roi.RectangleROI | |
import qupath.imagej.gui.IJExtension; | |
import ij.IJ | |
import ij.gui.Roi | |
import ij.plugin.ChannelSplitter | |
import ij.plugin.frame.RoiManager |
Hi, did you find the solution?,
I am also facing the same problem. All of my label images are empty (all black)
Sort of. The script exports the mask for the open image. So I open an
image, run the script (first option in dropdown menu), and move on to the
next. This will get you the right masks at the cost of more clicks.
Best,
Frank
…On Thu, Jan 14, 2021, 11:18 its-jd ***@***.***> wrote:
***@***.**** commented on this gist.
------------------------------
Hi, did you find the solution?,
I am also facing the same problem. All of my label images are empty (all
black)
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<https://gist.github.com/d284ef91160f9242ab8ce3a65b72cbd6#gistcomment-3593548>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ANN2EKBDES2TIK6BA7MHBGTSZ3AITANCNFSM4SNCRLYA>
.
This is quite strange. I noticed that there is a line missing
request = RegionRequest.createInstance(imageData.getServerPath(), downsample, region.getROI())
I guess QuPath creates a request by default for the current image.
Hopefully this was causing the error.
Please try now and let me know.
Best
Oli
That fixed it, thank you!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you for sharing this script!
When I run it on QuPath 0.2.3 the script exports all the files in my project, but each gets the masks for the currently opened image (or an empty mask if no image is open).