Exporting tiles with binary masks of 1 cell detection at a time

Hi Qupath Community,

I would like to export tiles of the images and binary masks of cell detections downstream of the watershed cell detection. The below script works great for this but i would like to add a wrinkle if possible. For every tile, i only want 1 cell mask. I can almost get there by exporting really small tiles, which is fine but for the densely pack cells i still get a couple of cell masks within the exported tile. Is this possible with arguments in the label server? could i iteratively generate a new class label for every cell and loop through those in the export? Any help would be amazing!

Thanks

Exporting Detection Labels from QuPath - Image Analysis - Image.sc Forum

It’s not quite what you’re asking for, but could a labelled image where each cell as a unique integer label do the job? Providing your cells aren’t overlapping, you can then create distinct binary images later (e.g. easily in Python).

To get a labelled image, you’d use LabeledImageServer.Builder and include useUniqueLabels() as an option.

If that doesn’t help, can you post the exact script you’re working with that is closest to what you need? There are multiple scripts on the other thread; the first one looks quite close to what you describe.

Alternatively, if you describe the end goal / what happens next after export there may well be other ways to get there.

Pete - That would work but i have a lot of cells and am getting this error

ERROR: IllegalArgumentException at line 14: You’ve requested 7094 output channels, but the maximum supported number is 256

and this is just a toy example, i would need to have this run on an image with 100-500k cells. is there a way to limit the number of unique labels and just cycle through them as it would be very unlikely to label adjacent cells the same thing?

The end goal is to generate an image of just the nuclei and “cytoplasm” expansion (generated with the cell detection process) and perform some image processing on these things specifically on a per cell basis.

Thanks

You’d need .multichannelOutput(false) to avoid requiring lots of channels – see here.

It has been a long time since I wrote it, but I think QuPath will try to handle large numbers of cells by using a packed int presentation… so you’ll end up with an (A)RGB image, however if you treat each ARGB value as a single 32-bit integer (rather than four 8-bit integers) you can get the labels back. This is due to a limitation in the kind of images that Java can render.

At least I remember planning to do that, I don’t remember if I actually did it. In any case, you’ll need to turn off multichannel output and hopefully it will result in something usable.

Where would this be done (e.g. QuPath, ImageJ, Python… somewhere else)?

You’d need .multichannelOutput(false) to avoid requiring lots of channels

i get this error

ERROR: NullPointerException at line 6: Cannot invoke method getServer() on null object

ERROR: org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:91)

This is my block of code right now

def labelServer = new LabeledImageServer.Builder(imageData)
.useCells()
.useUniqueLabels()
.backgroundLabel(0, ColorTools.WHITE) // Specify background label (usually 0 or 255)
.downsample(downsample) // Choose server resolution; this should match the resolution at which tiles are exported
.addLabel(‘Cartilage’,1)
//.lineThickness(2)
//.setBoundaryLabel(‘Ignore’, 2)

.multichannelOutput(false) // If true, each label is a different channel (required for multiclass probability)
.build()

Where would this be done (e.g. QuPath, ImageJ, Python… somewhere else)?

I would use python because of other down stream analysis, but if QuPath can give me the RGB histograms (not just the summary statistics from the “calculate features”) for each of the cells and two compartments, i would be happy to perform this task in QuPath

@rdbell3 It sounds like there probably isn’t an image open. There would need to be other earlier lines in the script as well (or else imageData wouldn’t be defined), so I can’t tell where line 6 is or what could be going wrong where.

Python is probably easiest in that case, I’d go for Python myself.

Yea that was a dumb mistake, i had closed the project and reopened, then just ran the script without opening the image. lol

thanks

Now i am getting images output but i can seem to open them with imageJ. I am sure it has to do with the format and the way you suggest these A(RGB) values are constructed. Do you know if there is a appropriate image format to export as, that can handle this? eg. tiff vs png

I will also need to write some python and see if i can just deal with it as a numpy array [Edit: I cant seem to open them in python either, but there is 22 kb of data in them so it makes me again think it is just a format issue but maybe it is an export issue]

Which formats have you tried? I would just be trying different ones (.tif, .png, .ome.tif) to see which, if any, work.

I have realized that i am not sure how to control the file format of the mask. The code i am working from is below. Where might i modify to change the mask format?

import qupath.lib.images.servers.LabeledImageServer

def imageData = getCurrentImageData()

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

// Convert to downsample
double downsample = 1

// Create an ImageServer where the pixels are derived from annotations
def labelServer = new LabeledImageServer.Builder(imageData)
    .useCells()
    .useUniqueLabels()
    .backgroundLabel(0, ColorTools.WHITE) // Specify background label (usually 0 or 255)
    .downsample(downsample)    // Choose server resolution; this should match the resolution at which tiles are exported
    .addLabel('Cartilage',1)

    .multichannelOutput(false)  // If true, each label is a different channel (required for multiclass probability)
    .build()

// Create an exporter that requests corresponding tiles from the original & labeled image servers
new TileExporter(imageData)
    .downsample(downsample)     // Define export resolution
    .imageExtension('.tif')     // Define file extension for original pixels (often .tif, .jpg, '.png' or '.ome.tif')
    .tileSize(256)              // Define size of each tile, in pixels

    .labeledServer(labelServer) // Define the labeled image server to use (i.e. the one we just built)
    .annotatedTilesOnly(true)  // If true, only export tiles if there is a (labeled) annotation present
    .overlap(0)                // Define overlap, in pixel units at the export resolution
    .writeTiles(pathOutput)     // Write tiles to the specified directory

print 'Done!'

You can add labeledImageExtension('.tif') or similar – that should work in a similar way to .imageExtension('.tif')

1 Like

labeledImageExtension(’.tif’) worked.

I tested the 4 formats (png tif, jpg, ome.tif), it looks like only .tif can handle these sorts of exports. I should be able to make this work in python for what i need. Thanks again!

2 Likes