Skip to content

Commit d5da437

Browse files
authored
add reader for imagej tiffs and auto-conversion for big endian dtypes (#877)
* add reader for imagej tiffs and auto-conversion for big endian dtypes * minor fixes * add changelog entries * update changelog
1 parent cf99816 commit d5da437

File tree

4 files changed

+72
-2
lines changed

4 files changed

+72
-2
lines changed

webknossos/Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ For upgrade instructions, please check the respective _Breaking Changes_ section
1515
### Breaking Changes
1616

1717
### Added
18+
- Added support to import ImageJ Hyperstack tiff files via `Dataset.from_images` and `dataset.add_layer_from_images`. [#877](https://github.com/scalableminds/webknossos-libs/pull/877)
1819

1920
### Changed
21+
- `Dataset.from_images` and `dataset.add_layer_from_images` now automatically convert big endian dtypes to their little endian counterparts by default. [#877](https://github.com/scalableminds/webknossos-libs/pull/877)
2022

2123
### Fixed
2224
- Fixed reading czi files with non-zero axis offsets. [#876](https://github.com/scalableminds/webknossos-libs/pull/876)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from os import PathLike
2+
from pathlib import Path
3+
from typing import Set
4+
5+
import numpy as np
6+
7+
try:
8+
from pims import FramesSequenceND
9+
except ImportError as e:
10+
raise RuntimeError(
11+
"Cannot import pims, please install it e.g. using 'webknossos[all]'"
12+
) from e
13+
14+
try:
15+
import tifffile
16+
except ImportError as e:
17+
raise RuntimeError(
18+
"Cannot import tifffile, please install it e.g. using 'webknossos[tifffile]'"
19+
) from e
20+
21+
22+
class PimsImagejTiffReader(FramesSequenceND):
23+
@classmethod
24+
def class_exts(cls) -> Set[str]:
25+
return {"tif", "tiff"}
26+
27+
# class_priority is used in pims to pick the reader with the highest priority.
28+
# Default is 10, and bioformats priority is 2.
29+
# See http://soft-matter.github.io/pims/v0.6.1/custom_readers.html#plugging-into-pims-s-open-function
30+
class_priority = 20
31+
32+
def __init__(self, path: PathLike) -> None:
33+
super().__init__()
34+
path = Path(path)
35+
tiff = tifffile.TiffFile(path)
36+
assert tiff.is_imagej, f"{path} is not an ImageJ Tiff"
37+
channels = tiff.imagej_metadata["channels"]
38+
z = tiff.imagej_metadata["images"] / channels
39+
40+
self.memmap = tifffile.memmap(path)
41+
# shape should be zcyx
42+
assert len(self.memmap.shape) == 4
43+
assert self.memmap.shape[0] == z
44+
assert self.memmap.shape[1] == channels
45+
46+
self._init_axis("x", self.memmap.shape[3])
47+
self._init_axis("y", self.memmap.shape[2])
48+
self._init_axis("z", z)
49+
self._init_axis("c", channels)
50+
self._register_get_frame(self._get_frame, "cyx")
51+
52+
@property
53+
def pixel_type(self) -> np.dtype:
54+
return self.memmap.dtype
55+
56+
def _get_frame(self, **ind: int) -> np.ndarray:
57+
return self.memmap[ind["z"]]

webknossos/webknossos/dataset/_utils/pims_images.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
import webknossos.dataset._utils.pims_dm_readers
3535
except ImportError:
3636
pass
37+
38+
try:
39+
import webknossos.dataset._utils.pims_imagej_tiff_reader
40+
except ImportError:
41+
pass
3742
# pylint: enable=unused-import
3843

3944
from webknossos.dataset.mag_view import MagView

webknossos/webknossos/dataset/dataset.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,11 +1149,17 @@ def add_layer_from_images(
11491149
is_segmentation=category == "segmentation",
11501150
**pims_open_kwargs,
11511151
)
1152+
if dtype is None:
1153+
current_dtype = np.dtype(pims_images.dtype)
1154+
if current_dtype.byteorder == ">":
1155+
current_dtype = current_dtype.newbyteorder("<")
1156+
else:
1157+
current_dtype = np.dtype(dtype)
11521158
layer = self.add_layer(
11531159
layer_name=layer_name + layer_name_suffix,
11541160
category=category,
11551161
data_format=data_format,
1156-
dtype_per_channel=pims_images.dtype if dtype is None else dtype,
1162+
dtype_per_channel=current_dtype,
11571163
num_channels=pims_images.num_channels,
11581164
**add_layer_kwargs, # type: ignore[arg-type]
11591165
)
@@ -1198,7 +1204,7 @@ def add_layer_from_images(
11981204
pims_images.copy_to_view,
11991205
mag_view=mag_view,
12001206
is_segmentation=category == "segmentation",
1201-
dtype=dtype,
1207+
dtype=current_dtype,
12021208
)
12031209

12041210
args = []

0 commit comments

Comments
 (0)