QuPath: JPEG support for multi-channel 8bit OME-TIFF export

In QuPath>File>Export images…>OME Tiff the JPEG compression is only available for single-channel images.

With the following modification in the OMEPyramidWriter the JPEG compression can be activated for multi-channel 8bit:

161	public boolean supportsImage(ImageServer<?> server) {
162			switch(this) {
163			case JPEG:
164				return server.isRGB() || 
165						(server.nChannels() == 1 && server.getPixelType() == qupath.lib.images.servers.PixelType.UINT8);

Line 165 changed to

165						(server.nChannels() >= 1 && server.getPixelType() == qupath.lib.images.servers.PixelType.UINT8);

This makes JPEG accessible for multi-channel 8bit images in the GUI Export command as well as in scrips.

I have tested this modification with multi-channel 8bit images of type Fluorescence and transmitted light RGB images.

In all of my tests - writing multi-channel 8bit OME-TIFFs from GUI command or via script - I have not seen general problems with the image data.
All the exported multi-channel 8bit JPEG compressed OME.Tiff files could be loaded in FIJI/BioFormats and Halo.

I discovered only one aspect: Transmitted light RGB images exported as multi-channel 8bit JPEG compressed OME.Tiff files will not be displayed correctly in e.g. Windows Preview or IrfanView.

@petebankhead has mentioned in a PR that multichannel JPEG “may fail under certain circumstances (e.g. chunky rather than planar representation; because of how QuPath requests channels all at once, writing in planar would be much slower for large images and so chunky/interleaved is preferred).”

I wonder if the above modification has some drawbacks or if problems can occur in image/channel/type constellations which if havn’t tested.

Could the above modification be used in the official QuPath distribution?

Thanks @phaub, I’ll look into it when I have a chance.

Just to confirm, did you try changing the method of channel export in the builder, to see if both planar & interleaved work (link below)? And how many channels have you tried exporting?

1 Like

No, but I will catch this up.

I have successfully exported (8bit with JPEG):

  • 4 channel Fluorescence (via GUI)
  • 4 channel Fluorescence + additional channel 5 (via script)
  • RGB (HTX/DAB image) (via GUI and script)

I tested all exports with / without pyramid creation.

1 Like

@petebankhead I have tested the behavior of the QuPath OME.TIFF export
by explicite selection of the channels configuration in a script.

The images used for testing did not contain pyramids and the automatic building of pyramids during loading was inactive.

Output was pyramidal ome.tiff

(In the following OK means in case of UNCOMPRESSED: No data difference)
(In the following OK means in case of JEPG: Data is not identical to original. But differences are in the low single digit 8bit range.)
(In the following NOTHING means: channels configuration not explicite selected via channelsPlanar() or channelsInterleaved(). )

Here are my notes:

****** Test with OFFICIAL QUPATH VERSION  **************************


TL UNCOMPRESSED
 NOTHING => OK  (output is RGB composite)
.channelsInterleaved()  => OK  (output is RGB composite)
.channelsPlanar()
	//ERROR: BufferOverflowException at line 368: null

	//ERROR: java.base/java.nio.Buffer.nextPutIndex(Unknown Source)
	   java.base/java.nio.HeapByteBuffer.put(Unknown Source)
	   qupath.lib.images.writers.ome.OMEPyramidWriter$OMEPyramidSeries.writeRegion(OMEPyramidWriter.java:701)


TL with JPEG
 NOTHING => OK  (output is RGB composite)
.channelsInterleaved()  => OK  (output is RGB composite)
.channelsPlanar()
	//ERROR: BufferOverflowException at line 368: null

	//ERROR: java.base/java.nio.Buffer.nextPutIndex(Unknown Source)
	   java.base/java.nio.HeapByteBuffer.put(Unknown Source)
	   qupath.lib.images.writers.ome.OMEPyramidWriter$OMEPyramidSeries.writeRegion(OMEPyramidWriter.java:701)


FL 2chn UNCOMPRESSED
 NOTHING => OK  (is identical to planar)
.channelsPlanar()  => OK
.channelsInterleaved()  => OK (but all channels have LUT RED of first channel when open in FIJI, data is identical)


FL 3chn UNCOMPRESSED
 NOTHING => OK  (is identical to planar)
.channelsPlanar()  => OK
.channelsInterleaved()  => OK (but all channels have LUT RED of first channel when open in FIJI, data is identical)


FL 4chn UNCOMPRESSED
 NOTHING => OK  (is identical to planar)
.channelsPlanar()  => OK
.channelsInterleaved()  => OK (but all channels have LUT RED of first channel when open in FIJI, data is identical)


****** Test with MODIFIED QUPATH VERSION  **************************

FL 2chn JPEG
 NOTHING => OK  (is identical to planar)
.channelsPlanar()  => OK
.channelsInterleaved()  => NOT OK.   Image is empty (all pixels black)


FL 3chn JPEG
 NOTHING => OK  (is identical to planar)
.channelsPlanar()  => OK
.channelsInterleaved()  => OK (but all channels have LUT RED of first channel when open in FIJI)
                           AND file size is smaller then in planar configuration 
                           AND difference between original and create (jpeg) data is bigger then in planar configuration 

 
FL 4chn JPEG
 NOTHING => OK  (is identical to planar)
.channelsPlanar()  => OK
.channelsInterleaved()  => NO error message
                           BUT channels are empty (intensity = 0), file size 4 kB much to small

Conclusion

If no channels configuration is explicite selected then QuPath uses:

  • planar configuration for images of type ‘Fluorescence’
  • interleaved configuration for images of type ‘Brightfield’

This leads to correct output images.

For images of type ‘Brightfield’ the explicite configuration channelsPlanar() leads to BufferOverflowException.
This is not because of my modification in the QuPath code.
The error happens in the official version 0.2.3.

For images of type ‘Fluorescence’ the explicite configuration channelsInterleaved() leads to empty images if the number of channels is > 3 in the modified QuPath version.