Writing QuPath/Bio-Formats compatible pyramidal image with libvips

Not exactly on this topic, but quite related. In my case I am using C/C++ with the libvips to generate and write large images in TIFF format with pyramids but they are not correctly interpreted by qupath so this could be related with the problems exposed in this thread. Indeed:

  • If I use the default way (bioformats) for letting qupath read the image, it does not see the pyramid and ask for the construction of it by itself (which it does, but it takes time). Moreover, it seems to assume that the TIFF tags TIFFTAG_XRESOLUTION and TIFFTAG_YRESOLUTION are expressed in pixels/mm, despite the fact that the tag TIFFTAG_RESOLUTIONUNIT is set to cm (I know that because vips provides a program, vipsheader, to examine the tiff header). This means that pixel size is taken by QuPath as one tenth of its real value, which alters the behaviour of the cell detection algorithms.

  • On the contrary, if I set QuPath preferences so that Bioformats is NOT used for TIFF images, pyramid is understood; the image is loaded very fast BUT: pixel size is ignored (but this time the cell detection algorithm does not seem to be puzzled by that…)

I suspect that this is not a problem of QuPath but of the low level libraries used to read the formats, but I think it should be pointed out because if it can be at least temporarily patched at a higher level (when the image has been read).

Thanks a lot for maintaining such a complex program, it is a really hard task!

1 Like

Thanks @jdomingo as I understand it, libvips 8.10 introduced support for writing Bio-Formats-friendly TIFF pyramids: What's new in 8.10
Are you already using this? There are some mentions of QuPath on the libvips GitHub issues, since I think it was being used to test things a bit during development – so I believe it should be compatible.

If at all possible, I’d rather things could be worked out without needing to patch them in QuPath since I fear that will only lead to further incompatibilities somewhere :slight_smile: If there isn’t another solution, are you able to share any example files and further info about how exactly they are written with libvips?

1 Like

Hello, Pete.
Thanks a lot for the so quick reply!.
I have checked and no, indeed, I am using the vips version installed as a Fedora package, which is currently 8.9.2 in the latest update. So what I am doing is to uninstall that one, get the 8.10 from the git version of vips and compile with it.
I’ll post a note here with the result as soon as done.
Thanks again

1 Like

Hi @jdomingo,

quickly cross-linking this topic with Correct way to convert SVS slides for Omero import which also discusses conversion and libvips.

First of all, I confirm the TIFF-based pyramidal format generated by libvips is currently not supported by Bio-Formats which explains the first issue you are seeing in QuPath. Adding support is currently captured as a GitHub issue with the potential to reuse some existing code. To the best of our knowledge, no progress has been made so far and there is no immediate driver from the OME side. We would be happy to assist anyone who would feel like championing this support.

Re libvips, as mentioned in the other thread, I think you want to pass the subifd option e.g.

vips copy source.tiff target.ome.tif[pyramid,subifd]

adding optional arguments to the commands like bigtiff, or compression=<compression> as necessary.

Looking forward to hearing about your results with libvips 8.10.

2 Likes

Dear Pete and Sébastien:
Thank you very much for your quick reply. I will look at the tiff issue with Bio-Formats to see if I could do something.
With respect to results with libvips 8.10, I certainly could download, compile and use it to link my programs. Unfortunately, using the subfid tag has not really helped. I upload with this comment a .zip file containing my report and screenshoot captures of the error windows and log. My concern is: I am now using libvips 8.10 but is QuPath using it, too, to load the images? I guess not in the case of relying on Bio-formats, but what if we don’t allow to use them (as I have tried)? Does QuPath use in this case vips or openslide?
Thanks a lot for your help.
Juan
report_jdomingo.zip (121.3 KB)

1 Like

Hello, libvips maintainer here. It ought to work, so please open a bug on the libvips issue tracker if it’s failing for you.

The two things to bear in mind when converting are that 1) bioformats needs some XML in the TIFF IMAGEDESCRIPTION tag setting out how the image should be interpreted, and 2) OME-TIFF always has split image planes, so you’ll need to break up colour images and encode the bands as separate TIFF pages.

Here’s a sample conversion script:

#!/usr/bin/python3
  
import sys
import pyvips

im = pyvips.Image.new_from_file(sys.argv[1])

# openslide will add an alpha ... drop it
if im.hasalpha():
    im = im[:-1]

image_height = im.height
image_bands = im.bands

# split to separate image planes and stack vertically ready for OME 
im = pyvips.Image.arrayjoin(im.bandsplit(), across=1)

# set minimal OME metadata
# before we can modify an image (set metadata in this case), we must take a 
# private copy
im = im.copy()
im.set_type(pyvips.GValue.gint_type, "page-height", image_height)
im.set_type(pyvips.GValue.gstr_type, "image-description",
f"""<?xml version="1.0" encoding="UTF-8"?>
<OME xmlns="http://www.openmicroscopy.org/Schemas/OME/2016-06"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.openmicroscopy.org/Schemas/OME/2016-06 http://www.openmicroscopy.org/Schemas/OME/2016-06/ome.xsd">
    <Image ID="Image:0">
        <!-- Minimum required fields about image dimensions -->
        <Pixels DimensionOrder="XYCZT"
                ID="Pixels:0"
                SizeC="{image_bands}"
                SizeT="1"
                SizeX="{im.width}"
                SizeY="{image_height}"
                SizeZ="1"
                Type="uint8">
        </Pixels>
    </Image>
</OME>""")

im.tiffsave(sys.argv[2], compression="jpeg", tile=True,
            tile_width=512, tile_height=512,
            pyramid=True, subifd=True)

Using CMU-1.svs, the openslide sample image, I can convert like this:

$ /usr/bin/time -f %M:%e ~/try/convert.py CMU-1.svs CMU-1.tiff
439872:24.67

So 25s and 450mb of memory. This PC has 16 cores, you’ll probably see lower memory use. I can load into QuPath like this:

$ ~/packages/bioformats/QuPath-0.2.3/bin/QuPath-0.2.3 CMU-1.tiff 

And I see:

It loads quickly, I see the correct colours, and it can see and use the subifd pyramid structure. It’s not getting the type, I suppose I need a bit more XML for that.

libvips 8.11 is adding jpeg2000 TIFF compression, which ought to help a bit more.

3 Likes

QuPath uses OpenSlide. There are problems with this, but we don’t have a better solution yet.

Within QuPath, you should see which library was used for reading the image under the ‘Image’ tab (Server type). You can run a script

print getCurrentServer().dumpMetadata()

to print out whatever metadata QuPath got from whichever read it used.

Of for more detail, you might find the Bio-Formats command line tools useful for inspecting the file.

It never does :slight_smile: QuPath never reads the type, it only estimates it or the user sets it. Just yesterday I improved the ‘Show details’ content to make this dialog a little more informative and less annoying. For now, you can turn off the prompts int he preferences (search for ‘Set image type’).

This behavior might change in the future, since the OME metadata can contain relevant information – but even if that is provided, we don’t use it yet.

2 Likes

Within QuPath, you should see which library was used for reading the image under the ‘Image’ tab ( Server type ).

Ah that’s useful, thanks Pete. Yes, I see:

So QuPath is indeed using bioformats to load my converted slide (phew). I’m also glad the type issue isn’t my fault.

2 Likes

Hi @jdomingo another thought since you mentioned that you are working in a C/C++ software environment. The version 0.6.0 community fork of OME’s C++ library for reading/writing OME-TIFF files is capable of writing tiled/pyramided OME-TIFF files (same as the Bio-Formats software) and thus the results should be fully compatible with QuPath (and other Bio-Formats-capable packages). You can find OME Files C++ 0.6.0 at: codelibre / ome / ome-files-cpp · GitLab
Cheers,
Damir

1 Like

Dear Damir, Ashish, John, Pete and Sébastien:
First, thank you very much for your kind help; this is a really active and helpful community!.
Your comments helped me to clarify the situation. Summarizing:

  • Openslide works (almost) fine with one type of images generated by vips (TIFF, pyramid, no subifd) but had a problem with the units and also there is the fact that is not maintained and therefore support under QuPath might have to reach its end.
  • Vips is newer and (hopefully) supported by Qupath in a near future but Pete pointed the problems it could have to compile in multiple platforms. Certainly, I compiled in Linux (last version) and it was not difficult, but it needed a lot of dependencies that would be difficult to manage not only for OS-X and Windows, but even for different Linux distributions.
  • Bio-formats, as currently included in QuPath has the bug pointed out by Sébastien in the Github issue. I looked at here to see if could help, but it is written in Java, and I am not very familiar with it. Sorry.

From now on, I have decided to go on with vips in pyramid and with no subifd and let Openslide read it from Qupath. The problem with units is because openslide does not use the standard TIFF tags (TIFFTAG_XRESOLUTION and TIFFTAG_YRESOLUTION) but the “private” tags called openslide.mpp-x, openslide.mpp-y, derived in turn of the tags aperio.MPP (and the tag aperio.AppMag, relevant, too) which are extracted from the content of the TIFFTAG_IMAGEDESCRIPTION (this tag is standard). These are exclusive (I think) of the .svs Aperio file format. So my (dirty) solution was to read them from the original .svs file, create a synthetic image description (a short ASCII file) and insert it as a tag in my generated TIFF with the command “tiffset -sf 270 file_of_header myfile.tiff” (I didn’t find a way from vips to insert arbitrary tags from C/C++, but probably there is one…). This way, QuPath (using openslide) loads the pyramid TIFF (very fast) and is conscious of the real size of pixels (and the real magnification).

This is only temporary, but the solution provided by Damir (using the library he suggests) would solve the problem neatly, by writing OME-TIFF files fully compatible with Bio-formats and therefore with QuPath, which does not force anyone to change anything. I am trying and will post a comment when done.

Again, thaks a lot to everyone.
Juan

@jcupitt John, welcome to image.sc. Just wanted to say I have been a huge fan of libvips for its speed and low memory requirements, support for OME-TIFF is a cherry on top for Bioimage analysis community :+1:

4 Likes

Sorry if I confused things by splitting the topic, but I thought it would help to keep MATLAB and libvips discussions separate :slight_smile:

My preference is to be Bio-Formats compatible as much as possible, since it is ubiquitous, very well supported, and the future of OpenSlide is unclear (as far as I know it isn’t actively maintained). But when it comes to writing OpenSlide friendly images, this may be helpful:

4 Likes

Benjamin was working on openslide this morning:

(my PR from three (!!) years ago) so who knows, perhaps there will be a new version. Fingers crossed!

libvips does not try to write SVS format – that feels out of scope to me. The plan from our side is to write bioformats-compatible OME TIFF. If you have a case that doesn’t work, please open an enhancement request on libvips discussions and we’ll try to fix it (time permitting etc.):

5 Likes