napari / napari

napari: a fast, interactive, multi-dimensional image viewer for python
https://napari.org
BSD 3-Clause "New" or "Revised" License
2.17k stars 419 forks source link

Saving layers as .tif images: voxel size (scale) is lost #5162

Open haesleinhuepf opened 1 year ago

haesleinhuepf commented 1 year ago

🐛 Bug

When saving an image layer as TIF to disc, the scale (a.k.a. voxel-size) is not stored in the metadata.

To Reproduce

Steps to reproduce the behavior:

  1. Execute this code, e.g. from a jupyter notebook:
    import napari
    import numpy as np
    viewer = napari.Viewer()
    image = np.random.random((5, 10, 10))
    viewer.add_image(image, scale=(0.3, 0.1, 0.1))
  2. Use the menu File > Save selected Layer(s)...
  3. Save the image as .tif file
  4. Reopen the file in Fiji
  5. Use the menu Image > properties

image

Expected behavior

I would expect voxel size 0.1 x 0.1 x 0.3 in Fiji

Environment

OpenGL:

Screens:

Plugins:

Additional context

Code for saving the image file properly can be found in this image.sc discussion. I'm happy to send a PR if core-developers tell me where to.

Czaki commented 1 year ago

Code for saving the image file properly can be found in this image.sc discussion. I'm happy to send a PR if core-developers tell me where to.

There are a few remarks to this code:

1) Imagej-Tiff supports only unit8, unit16, and float32. Because of this, I strongly suggest using OME-Tiff instead of ImageJ-Tiff 2) This code (and all others I know) requires to provide units. What unit did You prefer to set as default, any idea how to control it for the user (just start from using API)? 3) This code does not use compression. The current tiff saving is using compression: https://github.com/napari/napari/blob/3bf872cbb1df98665fdb7d5e0f3e1a4845a84202/napari/utils/io.py#L46 and code from the image.sc does not use compression. I remember that there were problems when opening compressed files in ImageJ (but it may be strongly related to multichannel data). I do not write that it is impossible, but it requires additional testing.

In my opinion, the best option will be to add writer to save ImageJ-tiff next to the existing writers. A user may select used writer in the save window.

The current implementation is here: https://github.com/napari/napari/blob/3bf872cbb1df98665fdb7d5e0f3e1a4845a84202/napari_builtins/io/_write.py#L96

And such implementation should be the modification of this or added next to it.

Please remember that napari_builtins is an npe2 plugin and requires to add new functions to YAML file: https://github.com/napari/napari/blob/3bf872cbb1df98665fdb7d5e0f3e1a4845a84202/napari_builtins/builtins.yaml

EDIT. It will also be nice to improve the napari reader to read metadata in the way that is saved by the builtin reader.