Import labeled tiles into qupath

I am trying to work on WSI that are already annotated in Qupath 0.2.1
There is 1 class of annotation “ASCO”, and the majority of the slide is uniformative. Instead on training on the WSI, I want to work on 1024 x1024 tile that contain the annotation “ASCO”.
using the TileExporter, I was able to export a tile1.tif and another file tile1-labelled.tif.
the tile1-labelled.tif file appears to be multipage and contains the polygon of annotation.

I have 2 questions:

  1. is there a way to import the pair of tif files to view them? if this is possible, I can then export the annotation as json for training?
  2. is it possible to convert direclty the tile1-labelled.tif to json or xml?
    Thanks in advance

Hi @kimalaacer,

  • You should be able to import the pair of tif files in QuPath if you wish to work individually on each of them. A normal import should do (File > Open…). From a WSI you might have a lot of these tiles, so I’m not sure that’s what you want to do?

  • Your questions remind me of this thread, in which the person needed to import the annotations present in a ‘labelled tile’ (originally resulting from the TileExporter). This script imports back the labelled tile(s) as annotation in your image.

  • You can convert annotations to JSON (and back) with the script I posted here.

So overall, what I think you want is something like this?

  1. Use the TileExporter with a LabeledImageServer, using .multichannelOutput(false).
  2. Import the tiles (not the labeled images. E.g. tile1.tif) you want to work with inside a (new?) project.
  3. Modify the script posted here to import annotations from the labeled images (e.g. tile1-labelled.tif) for each of your tiles in your project.
  4. Use the script posted here to export your annotations as JSON.

If this is your end goal, this small workflow should do it. There are other ways to do this, but I suppose this here requires less extra scripting, as it was already done before.

1 Like

Thank you @melvingelbard
the mulltichanneloutput setting have worked since i have only one class.
Like you said, a WSI have a lot of tiles, but When i did my export, i only exported the tiles with annotation.
Since some of my WSI have only 3 annotations, I have 3 corresponding tiles.

The code you have referenced to import the tile-labeled.tif worked, but it seems that the annotation is referencing the original WSI, and not the tile.
to confirm that, I drew an annotation (where the old one would be) and exported them to json, and vertices location confirm that.
I will work on it some more.

If you run the code as is, that’s what will happen. But a solution would be to do as I suggested before:

Where you individually import your tiles in a new project in QuPath, then run a modified version of the script posted to make it process ONLY the relevant tile and doesn’t translate it to its original location in the WSI. Something like this I suppose:

// Script written for QuPath v0.2.3
// Minimal working script to import labelled images 
// (from the TileExporter) back into QuPath as annotations.

import qupath.lib.objects.PathObjects
import qupath.lib.regions.ImagePlane
import static qupath.lib.gui.scripting.QPEx.*
import ij.IJ
import ij.process.ColorProcessor
import qupath.imagej.processing.RoiLabeling
import java.util.regex.Matcher
import java.util.regex.Pattern

def directoryPath = 'path/to/your/directory' // TO CHANGE
File folder = new File(directoryPath);
File[] listOfFiles = folder.listFiles();

listOfFiles.each { file ->
    def path = file.getPath()
    def imageName = getProjectEntry().getImageName()

    // We only want to process the labelled image corresponding to the currently-opened tile
    if (!path.contains(imageName))
    print "Now processing: " + path
    def imp = IJ.openImage(path)
    double downsample = 1 // TO CHANGE (if needed)
    ImagePlane plane = ImagePlane.getDefaultPlane()
    // Convert labels to ImageJ ROIs
    def ip = imp.getProcessor()
    if (ip instanceof ColorProcessor) {
        throw new IllegalArgumentException("RGB images are not supported!")
    int n = imp.getStatistics().max as int
    if (n == 0) {
        print 'No objects found!'
    def roisIJ = RoiLabeling.labelsToConnectedROIs(ip, n)
    // Convert ImageJ ROIs to QuPath ROIs
    def rois = roisIJ.collect {
        if (it == null)
        return IJTools.convertToROI(it, 0, 0, downsample, plane);
    // Remove all null values from list
    rois = rois.findAll{null != it}
    // Convert QuPath ROIs to objects
    def pathObjects = rois.collect {
        return PathObjects.createAnnotationObject(it)


I haven’t tested this script, so you will have to modify it accordingly!

1 Like