Export tiles from ROI in QuPath

Hi there,

I am trying to export tiles from a ROI (annotation) using QuPath. I have drawn a ROI, set a class and tried to modify the script below in order to export images in .tif format from this ROI. However when I run the code it is still exporting from the entire image, not just my selected region. I found an old thread on GitHub (https://github.com/qupath/qupath/issues/62) that discusses this issue, but when applying the suggested changes it doesn’t seem to work on the newest version of QuPath (v 0.2.0).

I think I am missing some additional information, but as I am new to writing and interpreting script I am not sure where to start. Any advice would be appreciated!

// SCRIPT TO EXPORT IMAGE TILES (CAN BE CUSTOMIZED IN VARIOUS WAYS)./

// Get the current image (supports 'Run for project')
def imageData = getCurrentImageData()

// Define output path (here, relative to project)
def name = GeneralTools.getNameWithoutExtension(imageData.getServer().getMetadata().getName())
def pathOutput = buildFilePath(PROJECT_BASE_DIR, 'tiles', name)
mkdirs(pathOutput)

// Define output resolution in calibrated units (e.g. µm if available)
double requestedPixelSize = 5.0

// Convert output resolution to a downsample factor
double pixelSize = imageData.getServer().getPixelCalibration().getAveragedPixelSize()
double downsample = requestedPixelSize / pixelSize

// Create an exporter that requests corresponding tiles from the original & labelled image servers
new TileExporter(imageData)
    .downsample(1)   // Define export resolution
    .imageExtension('.tif')   // Define file extension for original pixels (often .tif, .jpg, '.png' or '.ome.tif')
    .tileSize(2064, 1600)            // Define size of each tile, in pixels
    .annotatedTilesOnly(true) // If true, only export tiles if there is a (classified) annotation present
    .overlap(64)              // Define overlap, in pixel units at the export resolution
    .writeTiles(pathOutput)   // Write tiles to the specified directory

print 'Done!'

Does any of this accomplish what you want?
https://qupath.readthedocs.io/en/latest/docs/advanced/exporting_images.html
And I am assuming by 0.2.0 you mean M9 specifically. There are many 0.2.0s!

Unfortunately that is where I sourced the original code (the bottom of the page for tile export). However I am still unable to export the tiles from within the ROI itself, if that makes sense!

And yes, I am running m9!

Any other suggestions? Thank you

1 Like

Dear @Research_Associate

I have modified another script I found addressing this issue (original post Exporting labelled images after tiling a specific annotations)

However it is now returning the following error: NO COMPATIBLE WRITER FOUND.

Do you have any suggestions for this?

You need to create your file path before giving it to ImageWriterTools. So perhaps something like this:

def pathOutput = buildFilePath(dirOutput, tilename)
ImageWriterTools.writeImageRegion(server, request, pathOutput)

Hi Pete,

Thanks so much for responding. Unfortunately that didn’t work either. See error below.

You need to put the lines further down in the code - after you have defined tilename (and replacing the line that involves ImageWriterTools).

1 Like

Hi Pete, that works, thank you, thank you!!

However, I am also wondering if it is possible to define the size of the tile for export? I want a rectangle if possible.

I have the following path, but unsure exactly what to change to define the tile size:

runPlugin(‘qupath.lib.algorithms.TilerPlugin’, ‘{“tileSizeMicrons”: 100, 200 “trimToROI”: false, “makeAnnotations”: true, “removeParentAnnotation”: false}’);

Also, for others the final code I used was as follows:

`// Create output directory inside the project
def imageData = getCurrentImageData()
def server = imageData.getServer()

def filename = GeneralTools.getNameWithoutExtension(imageData.getServer().getMetadata().getName())

def dirOutput = buildFilePath(PROJECT_BASE_DIR, ‘Exported Tiles’, filename)
mkdirs(dirOutput)

i = 1

for (annotation in getAnnotationObjects()) {

roi = annotation.getROI()

def request = RegionRequest.createInstance(imageData.getServerPath(), 
    0.5, roi)

String tiletype = annotation.getParent().getPathClass()

if (!tiletype.equals("tile")) {

    String tilename = String.format("%s_%s%d.jpg", filename, tiletype, i)

   def pathOutput = buildFilePath(dirOutput, tilename)

ImageWriterTools.writeImageRegion(server, request, pathOutput)

    print("wrote " + tilename)

    i++
    
}
}

`

Can you describe very precisely what output you need at the end, and ideally the purpose (i.e. what you’ll do with it afterwards)?

As I describe in the documentation there are so many ways to interpret exporting tiles/annotations, and it is usually much easier and faster to plot a direct route to the end goal rather than iteratively refining existing scripts.

Sidenote: you can format the code to make the whole thing more readable if you add a line with ``` above and below it, or select the text and click the ‘Preformatted’ button. Some more info at How to put code in a post?

(Adding ```groovy at the start is even better to highly the language appropriately)

1 Like

Hi Pete,

Thanks so much.

So, essentially, I want to export tiles from within a ROI (in this case the area of infarct) so I can run images through a macro for particle analysis in ImageJ.

Previously in our lab we have been doing the very mundane task of manually exporting all images via NDP.view, hence the decision to automate the process using QuPath. To ensure new images exported on QuPath are comparable with those exported in previous studies however, we want to maintain a consistent tile size (if possible!).

Also, to ensure flexibility across studies, we would like to be able to export at various magnifications if possible.

With the macro in image J, we need the individual images to be exported so we can overlay the particle analysis outlines over the original image to manually check the results after.

1 Like

Hi @asorbyadams, in that case I’d suggest looking at this script as perhaps the closest starting point: https://qupath.readthedocs.io/en/latest/docs/advanced/exporting_annotations.html#labeled-tiles

You will need to modify it for your case, but it contains lots of comments to guide you. The basic idea is this:

  • Annotate the region you want to export
  • Assign the classification ‘Tumor’ to the annotation
  • Edit the script from .annotatedTilesOnly(false) to become .annotatedTilesOnly(true)
  • Edit the requestedPixelSize, downsample or overlap options as required

You don’t really need to use the classification ‘Tumor’ - you can use something more meaningful, but you’ll need to make sure a label exists (which means modifying the line .addLabel('Tumor', 1)).

This should export annotated tiles of a fixed size. This doesn’t mean that every pixel of the tile falls within the annotation, but it will also export masks corresponding to each tile that indicate which corresponding parts exactly have been annotated.

Hi Pete,

That works well, thank you!

However, is there a way to label the images that are exported with their class?

Not currently using the TileExporter class. This would need to be done later using the binary masks (probably outside QuPath).

Hi Pete, That is ok! Thanks anyway.

Is there however a way to run the script so it doesn’t export the mask images? I assume you can get the location of the tile from the x,y coordinates anyway.

I don’t think so (as far as I recall) if you only want it to export the annotated regions. Basically, you can

  1. Export the tiles like you were doing previously - but then unannotated regions are included.
  2. Export tiles and masks, optionally restricting the export to include only tiles with corresponding masks.

So if you want the advantages of exporting only annotated regions, but no masks, I’d suggest use the second method and just delete the masks if you don’t want them.

2 Likes

Hi!
I was messing around with something similar, and am posting it here in case it helps.


It is for a different type of project, but I suspect we will be wanting to export a lot of detection tiles at some point. Annotations could be swapped in for this, simply by changing what the tiles variable picks up. Say, getAnnotationObjects() instead of detections. Note that it uses both the center point of the tile and the class in the file name. Emphasis on the center point and not the upper left corner, if that matters.

I wasn’t able to figure out how to easily get the path to go to the PROJECT_DIR, so you would definitely want to edit the base path unless you have a G drive.

// Based on Pete's scripts here: https://qupath.readthedocs.io/en/latest/docs/advanced/exporting_images.html#images-regions
// Get the current image (supports 'Run for project')
def imageData = getCurrentImageData()
def server = getCurrentServer()
// Define output path (here, relative to project)
def name = GeneralTools.getNameWithoutExtension(imageData.getServer().getMetadata().getName())
/*******************
CHANGE THIS
*******************/
def pathOutput = "G:\\Tiles\\"+name+"\\"
//Define what you want to export here
tiles = getDetectionObjects().findAll{it.getPathClass() != null}


mkdirs(pathOutput)
i=1
for (tile in tiles){
    def requestFull = RegionRequest.createInstance(server.getPath(),1,tile.getROI())
    x = tile.getROI().getCentroidX()
    y = tile.getROI().getCentroidY()
    tileClass = tile.getPathClass().toString()
    fileName = pathOutput+"Tile "+"x "+x+" y "+y+" "+tileClass+" "+(i++)+".tif"
    //print describe(requestFull)
    writeImageRegion(server, requestFull, fileName)
    
}