Import Fiji Roi to QuPath timelapse case

Dear all,

I would like to import a time-lapse image with ROIs/overlays per each time point in Qupath (0.2.3).
The overlays are imported but the ROIs appear only for the first time point.
I tried also [Plugins > Send ROI to QuPath] or [Plugins > Send Overlay to Qupath]. All the ROIs are only in the first image.

Is there a way to perform such operation? Even with scripting?

Here is the example image. Two time points with 2 ROIs/Overlays per timepoint.

example_overlay.tif (314.2 KB)

Thanks

Antonio

HI @apoliti,

If I open your TIFF in Fiji and run the following Groovy script:

def overlay = ij.IJ.getImage().getOverlay()
for (roi in overlay.toList()) {
	println "Roi: ${roi}"
	println "Position: ${roi.getPosition()}"
	println "Z: ${roi.getZPosition()}"
	println "T: ${roi.getTPosition()}"
}

the result is

Roi: Roi[Polygon, x=163, y=227, width=52, height=49]
Position: 1
Z: 1
T: 0
Roi: Roi[Polygon, x=167, y=175, width=57, height=53]
Position: 1
Z: 1
T: 0
Roi: Roi[Polygon, x=162, y=226, width=54, height=50]
Position: 2
Z: 2
T: 0
Roi: Roi[Polygon, x=167, y=173, width=57, height=55]
Position: 2
Z: 2
T: 0

So basically the ROI itself seems to be only storing a ‘position’, which ImageJ (confusingly) reports as a z-position – even you don’t have a z-stack, and so it ultimately ends up appearing in ImageJ on a different time-point instead.

This is the reason why QuPath is assuming that your ROIs actually belong on different z-slices rather than timepoints: that’s what the ROI itself is reporting.

Admittedly QuPath’s behavior here isn’t great, and it should probably try harder to sanity-check the position values… but the underlying problem is that the ImageJ ROIs need to have the ‘correct’ position property set before attempting to get them into QuPath.

1 Like

Thanks, this makes sense. The solution would be to reassign the Z-position to the T-roiPosition.

The rois comes from stardist run in ImageJ, somehow the ROi are associated to the Z-position instead to the T-position. Luckily this does not seem to matter much to IJ1 as it does shows the ROIs porperly.

Greetings

Antonio

1 Like

Hi @apoliti, I suspect the source of the problem is that ImageJ1 ROIs have position, channel, slice, frame and hyperstackPosition fields internally… and the logic is not entirely obvious from the outside.

It looks like if position is set then hyperstackPosition becomes false and then slice returns the value of position… regardless of what it actually refers to.

So basically you have different fields being relevant under different conditions.

Relevant code is around here:

Basically, at the creation of the ROIs the position should be set using the Roi.setPosition(int channel, int slice, int frame) method and not Roi.setPosition(int position) method… then the right info should be returned to QuPath.

(I hadn’t previously realised all that was happening. On our side, we should probably check Roi. hasHyperStackPosition() in our own code – pinging @melvingelbard in case he solves it before me!)

1 Like