Efficiently open qptiff images with Napari


I want to efficiently open qptiff images with Napari. qptiff images are whole slide images acquired with a Vectra Polaris. In the following example, the image I want to load is 43200x62640, with 9 different resolutions.

I first tried to use python-bioformats, but I get a Java exception:
JavaException: Array size too large: 43200 x 62640 x 1

I then tried using tifffile that allows to read qptiff as well. It works, but it takes more than 10s to read the file using tifffile.imread and about 1min to load it with Napari. As a comparison, it takes less than 5s to load the same image with QuPath. Is there a more efficient way to load a qptiff file with Napari?

Thanks a lot!

@tpecot would you be able to share the file with us for testing?

We just use tifffile for reading, so the 10s is definitely a floor for us for now, but 1min with napari does seem excessive. As a first pass, I would suggest explicitly setting contrast_limits=[low_value, high_value] when adding the image, as, otherwise, napari will try to compute it on the whole image, which might indeed take a while in this case.

tifffile.imread() loads the largest pyramid image into memory. QuPath loads a lower resolution image on startup and only parts of the larger pyramid levels on demand.

If you think 10s is too slow to load a 43200x62640 image, please share the file, tifffile version, and system info.

1 min maybe spent by Napari calculating the pyramid levels. It should be faster to load the levels from the qptiff file. Tifffile doesn’t have a high level API for pyramids, but it should not be too difficult, e.g.:

import tifffile
import napari

with tifffile.Timer('Loading pyramid:'):
    with tifffile.TiffFile('HandEcompressed_Scan1.qptiff') as tif:
        pyramid = list(reversed(sorted(tif.series, key=lambda p:p.size)))
        size = pyramid[0].size
        pyramid = [p for p in pyramid if size % p.size == 0]
        pyramid = [p.asarray() for p in pyramid]

print('pyramid levels:', [p.shape for p in pyramid])

with napari.gui_qt():
    napari.view_image(pyramid, is_pyramid=True)

The image is displayed in less than 5 seconds on my system:

Loading pyramid: 2.247248 s
pyramid levels: [(26640, 30720, 3), (13320, 15360, 3), (6660, 7680, 3), (3330, 3840, 3), (1665, 1920, 3)]


First of all, thanks a lot for your replies, it really feels good to have such reactivity from the community.

The image I’m testing is available here:

The loading of the image (about 10s) is acceptable, that’s definitely not a bottleneck here.

For Napari, I first tried to define the contrast_limits, it does not change. I then tried is_pyramid=True and that makes a huge change (just a few seconds), Napari was effectively computing the pyramid levels, which is not necessary as they are already in the qptiff file. However, I’m now facing a weird problem. Napari opens with only the top left quarter of the image:

With all the image, it looks like this:

If I zoom in, I can then see the other parts of the image, but they disappear again as soon as I zoom out.

Bonus question: is there a possibility to start Napari in a way that it will be able to load a qptiff file directly from the tab File -> Open image(s)… ? That would help future collaborations with people afraid of any code line.

That link requires to “Sign in with your MUSC NetID”.

Hi @tpecot, I can respond to the bonus question. The ability to add IO plugins to handle exactly this sort of use case is in very active development this week actually (PR #891). This would let your collaborators pip install a plugin that will handle this sort of thing directly from the Open image(s) dialog or dragging and dropping a file onto the viewer.

I would also like to see the data to keep this use case in mind while developing (preferably without having to create a Box account, as @cgohlke also mentioned).

Sorry guys, I thought it’d be available to anyone. It should be fine with this link:

Thanks for the link to the IO plugins development, it surely will be very helpful.

1 Like

Hi @tpecot, so great that you’re trying napari out and thanks for sharing that data with everyone, it makes such a difference to be able to work from the same example.

I was able to download the file from the latest link without signing in and load it up with the code snippet that @cgohlke provided (thanks so much!!)

I will note that to get the above code snippet working I had to do both

pip install tifffile
pip install imagecodecs

otherwise I get a cannot decompress JPEG error, in case anyone else is trying to replicate.

On load I see the following full image (which is low resolution)

I’m surprised if you see that on open, as it should be showing you one of the low resolution images which cover the whole image. Does that happen after you zoom in? At larger zoom napari might not be fetching a large enough tile to cover your entire canvas. We’ve had some problems with that in the past (see https://github.com/napari/napari/issues/458 but it’s been hard to replicate). It could be that in those cases your canvas is larger than was expected by napari and we need to take that into account (like you’re in fullscreen mode on a very big monitor of something). I’m not quite sure but will think about this more. Any additional detail you can provide would be helpful.

Also I want to note in response to

We’ll be looking at our handling of this in https://github.com/napari/napari/issues/736, it’s always good to have more example use-cases as we think about what the best behaviour is. I think we’ll be moving away from the auto-pyramid calculation though as it seems to have lead to bad / confusing things more often than not, and might instead (or in addition) print more helpful error / warning messages

Thanks for your answer. Actually, when Napari opens, it’s already just a quarter of the image. I tried several monitors and two computers to check, I still have the same issue. However, it seems that there’s something related to what you’re mentioning as when I decrease the size of Napari, some parts of the image appear at some point. I quickly made a video to try to illustrate it:

Hope it’ll help.

Unfortunately I’m getting an mp4 error when trying to read it into quicktime on my mac. I could see if I could load it in napari :wink: but maybe you could send the movie as another file type .mov (maybe ?) / or it got corrupted somewhere along the way and it just needs to be resent?

I converted it in .mov:

Hope it’ll work this time :crossed_fingers:

Unfortunately not right away. I can look into some more software options later this afternoon and should be able to get one of them open (though curious if anyone else has the same problems as I do, I’m on a OS X)

An animated gif should work then:

1 Like

I can’t open it with Quicktime either, but VLC opens it fine. I highly recommend having it installed. My rule of thumb is, if it can’t open in VLC, it’s not a movie. =P


Yes this looks very similar to my issues in #458. I just haven’t followed it up because I rarely work with pyramid data, sorry about that!

But thank you @tpecot for all your testing, data, and videos! It’s extremely useful!

1 Like