MathOnco / valis

Virtual Alignment of pathoLogy Image Series
https://valis.readthedocs.io/en/latest/
MIT License
104 stars 26 forks source link

check_flattened_pyramid_tiff question #113

Open p-smirnov opened 3 months ago

p-smirnov commented 3 months ago

Hi!

First of all, impressive work! The registration works really well out of the box with almost no fiddling around.

I have had a couple of issues reading in simple multi-channel tiff files with no metadata, saved using tifffile. Currently, I have a tiff image with 55 channels, saved as 55 separate pages of the same size (height, width and channels).

It seems that in the current implementation, check_flattened_pyramid_tiff returns True in this case. I stepped through the code, and this condition: https://github.com/MathOnco/valis/blob/aa8368c7b4bf7ac79bad5c3fe170296700428603/valis/slide_io.py#L588C9-L590C1

returns true, with n_zero_diff = 55 and len(unique_areas) = 1

Is this intended in this case? While my image is technically a flattened pyramid (of pyramid depth 1), I think it would make more sense to read it in using a simple image reader.

The actual error occurs when FlattenedPyramidReader is instantiated to read in this source file, as it expects metadata in the description which does not exist (specifically, I have no channel names). If its relevant, this is my image description:

>>> vips_img.get("image-description")
'{"shape": [56, 3000, 3000]}'

The image is simply a numpy array saved using the defaults of the tifffile.imwrite function.

If this is not intended behaviour, then I think just checking that there actually exists more than 1 unique_area would be sufficient, but I am not 100% sure as I haven't worked with Flattened Pyramid Tiffs before.

Best, Petr

p-smirnov commented 3 months ago

Actually, I was incorrect regarding it failing because channel names are missing, but rather, because "image-description" only exists for the first page.

The error happens in _get_channel_names for VipsSlideReader, on this line:https://github.com/MathOnco/valis/blob/aa8368c7b4bf7ac79bad5c3fe170296700428603/valis/slide_io.py#L1801C17-L1801C62

>>> pyvips.Image.new_from_file(src_f, page=0).get("image-description")
'{"shape": [56, 3000, 3000]}'
>>> pyvips.Image.new_from_file(src_f, page=1).get("image-description")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/src/.venv/lib/python3.10/site-packages/pyvips/vimage.py", line 1062, in get
    raise Error('unable to get {0}'.format(name))
pyvips.error.Error: unable to get image-description
  vips_image_get: field "image-description" not found

Would it make sense to check whether "image-description" exists for each page inside the loop?

cdgatenbee commented 3 months ago

Hi @p-smirnov, Glad to hear you're finding valis useful! Sorry you're having this issue though, but thank you for taking time to pinpoint the source of the problem. I think your suggestion is a good one, and I'll include it in the next update (which should be soon). In the meantime though, maybe try creating a modified version of VipsSlideReader and passing that to the reader_cls argument when you call Valis.register. For example, something like:

from valis import slide_io

class VipsSlideReaderNoChannelNames(slide_io.VipsSlideReader):
    def __init__(self, src_f, *args, **kwargs):
        super().__init__(src_f=src_f, *args, **kwargs)

    def _get_channel_names(self, vips_img, *args, **kwargs):
        channel_names = slide_io.get_default_channel_names(vips_img.bands, src_f=self.src_f)
        return channel_names

registrar = registration.Valis(src_dir, dst_dir)
rigid_registrar, non_rigid_registrar, error_df = registrar.register(reader_cls=VipsSlideReaderNoChannelNames)

This will skip slide_io.get_slide_reader (which calls check_flattened_pyramid_tiff) and so should bypass the problem. Maybe try giving that a shot and let me know how it goes.

Best, -Chandler

p-smirnov commented 3 months ago

Thanks for the suggestion! I found the BioFormats slide reader also works in my case, but doesn't get selected automatically. I'll try out this workaround as well, I suspect Pyvips would probably be more efficient.

Best, Petr