xtiff
xtiff copied to clipboard
Compression error/ how to define the "compression_type" argument?
Hello,
I like this package as it's easy to install and use, however I have a question regarding the compression setting, specifically the compression type.
compression_type=None
What to pass here instead of the None to activate a compression?
I saw in the code that it counterchecks with the tifffile.TIFF.COMPRESSION()
, but was not able to figure out what to pass here.
Help would be appreciated
@Phlpp-S
Thank you for bringing up this issue. The options for compression_type
as specified by tifffile.TIFF.COMPRESSION()
should be:
NONE, CCITTRLE, CCITT_T4, CCITT_T6, LZW, OJPEG, JPEG, ADOBE_DEFLATE , JBIG_BW , JBIG_COLOR , JPEG_99 , KODAK_262 , JPEGXR_NDPI , NEXT , SONY_ARW , PACKED_RAW , SAMSUNG_SRW , CCIRLEW , SAMSUNG_SRW2 , PACKBITS , THUNDERSCAN , IT8CTPAD , IT8LW , IT8MP , IT8BL , PIXARFILM , PIXARLOG , DEFLATE , DCS , APERIO_JP2000_YCBC , JPEG_2000_LOSSY , APERIO_JP2000_RGB , ALT_JPEG , JBIG , SGILOG , SGILOG24 , JPEG2000 , NIKON_NEF , JBIG2 , MDI_BINARY , MDI_PROGRESSIVE , MDI_VECTOR , LERC , JPEG_LOSSY , LZMA , ZSTD_DEPRECATED , WEBP_DEPRECATED , PNG , JPEGXR , JETRAW , ZSTD , WEBP , JPEGXL , PIXTIFF , EER_V0 , EER_V1 , EER_V2
However xtiff.to_tiff(<a numpy ndarray>,<path/to/tiff/file>, compression_type = 'JPEG')
returns the following error for me:
TypeError: __call__() missing 1 required positional argument: 'value'
This is caused by the line 191 and compression_type not in tifffile.TIFF.COMPRESSION()
. It appears that tifffile.TIFF.COMPRESSION()
is not what is expected in the current code. substituting the check with something like: hasattr(tifffile.TIFF.COMPRESSION, 'compression_type')
seems to fix the issue.
@jwindhager what do you think?
@Phlpp-S Could you please confirm that you get the above error if you specify: compression_type = 'JPEG'
?
Hi @Milad4849
Without looking into this in too much detail, I would suspect that the TiffWriter.write
API may have changed since the last release of xtiff: instead of a single compression
argument, there now seems to be compression
and compressionargs
: https://github.com/cgohlke/tifffile/blob/5ced58caa74936ecc53f58ade94938e251e83138/tifffile/tifffile.py#L1637-L1638
Searching for compressionargs
in the tifffile changelog, this is indeed the case (version 2022.7.28):
Deprecate tuple type compression argument on write (use compressionargs).
As you can see in xtiff's setup.cfg, the last tested version for xtiff was 2022.4.22. I therefore see two options:
- Pin the max tifffile version to the last supported version (probably anything between 2022.4.22 and 2022.7.28, you'd need to check the changelog) and deprecate xtiff (add a deprecation warning to both the Python package and the GitHub repository)
- Work through the changes in the tifffile changelog and update xtiff accordingly (not just compression-related issues)
Option 1 is probably the easiest, but xtiff seems to be used quite regularly, still (it's also a dependency of steinbock!). In general, I suspect that tifffile has become much more powerful wrt. OME-TIFF since the last version of xtiff was released, so I'm not sure how justified xtiff's existence still is nowadays?
@Phlpp-S as a quick fix, could you try installing tifffile==2022.4.22
into your environment where xtiff is installed?
Hi @Milad4849 and @jwindhager , thank you very much for taking a look into this issue.
- First, I got the same error
TypeError: __call__() missing 1 required positional argument: 'value'
. - Substituting with
hasattr(tifffile.TIFF.COMPRESSION, 'compression_type')
also fixed this issue for me, however I got a follow up error stating that the compression needs the "imagecodecs" package. This was easily solved withpip install imagecodecs
andfrom imagecodecs import *
. - Without the substitution, but with the installation of
tifffile==2022.4.22
the value error remains for me.
With the substitution and imagecodecs, now the .tiff export works with a specified compression.
However now it seems that the array is not exported correct. I tried it with
comp = 'JPEG'
prof = xtiff.TiffProfile.OME_TIFF
xtiff.to_tiff(img_out_tif.astype('uint8'), 'xtiff_test_out.ome.tiff', image_name=None, image_date=None, channel_names=['Red', 'Green', 'Blue', 'Classnumber'], description=None,
profile = prof, big_endian=None, big_tiff=None, big_tiff_threshold=4261412864,
compression_type = comp, compression_level = 8, pixel_size=None, pixel_depth=None,
interleaved=True, software='xtiff', ome_xml_fun=xtiff.get_ome_xml)
where img_out_tif
is a (4 x N x M) matrix, where the first three channels are RGB from my input image, and the fourth channel contains class-values. I guess my simple list channel_names=['Red', 'Green', 'Blue', 'Classnumber']
is not sufficient?
The corresponding xtiff doc states channel_names: A list of channel names. If True, channel names are determined using the DataArray channel coordinate;
. How to specify the DataArray channel coordinate names?
Hi @Phlpp-S What is the exact problem when you execute the above command? I tested your command, I can write out arrays of shape (4 x N x M) and when I read it the the channel names are correctly assigned in the metadata.
Hi @Milad484
The export with the command I posted works, but when reading the exported file again it only contains 1 channel. What library (& function) do you use to read the .tiff image?
I tried cv2.imread()
which reads 3 channels, and matplotlib plt.imread()
which reads only 1 channel.
This is the code I use check the metadata of the tiff file:
import tifffile
import xml.dom.minidom
with tifffile.TiffFile('xtiff_test_out.ome.tiff') as tiff:
#ImageDescription tag
Image_description = tiff.pages[0].tags.values()[5].value
xml_tree = xml.dom.minidom.parseString(Image_description)
prettified_xml = xml_tree.toprettyxml(indent=" ")
print(prettified_xml)
and the output:
<?xml version="1.0" ?>
<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" Name="xtiff_test_out.ome.tiff">
<Pixels ID="Pixels:0" Type="uint8" SizeX="600" SizeY="400" SizeC="4" SizeZ="1" SizeT="1" DimensionOrder="XYCZT" Interleaved="true" BigEndian="false">
<Channel ID="Channel:0:0" SamplesPerPixel="1" Name="Red"/>
<Channel ID="Channel:0:1" SamplesPerPixel="1" Name="Green"/>
<Channel ID="Channel:0:2" SamplesPerPixel="1" Name="Blue"/>
<Channel ID="Channel:0:3" SamplesPerPixel="1" Name="Classnumber"/>
<TiffData/>
</Pixels>
</Image>
</OME>
The value of the ImageDescription tag in the first page of the TiffFile object is the above OME XML. Reading the image with tifffile: tifffile.imread('xtiff_test_out.ome.tiff')
, I get an array of shape (4 x N xM). As far as know the functions that you are using are primary for reading standard formats, tifffile or imageio can handle multi-channel TIFFs better.
Hi @Milad484
thanks for your answer.
tifffile.imread()
did what I wanted, to read in the image as a matrix for further processing.