Skip to content

Commit

Permalink
Merge pull request #67 from matham/io
Browse files Browse the repository at this point in the history
Support single z-stack tif file for input
  • Loading branch information
alessandrofelder authored May 3, 2024
2 parents 0e9768e + ed40e38 commit 98b02a1
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 5 deletions.
45 changes: 41 additions & 4 deletions brainglobe_utils/image_io/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -665,14 +665,15 @@ def load_from_paths_sequence(

def get_size_image_from_file_paths(file_path, file_extension="tif"):
"""
Returns the size of an image (which is a list of 2D tiff files),
without loading the whole image.
Returns the size of an image (which is a list of 2D tiff files or a
single-file tif stack), without loading the whole image.
Parameters
----------
file_path : str or pathlib.Path
Filepath of text file containing paths of all 2D files, or
filepath of a directory containing all 2D files.
Filepath of text file containing paths of all 2D files, a
filepath of a directory containing all 2D files, or a single
tiff file z-stack.
file_extension : str, optional
Optional file extension (if a directory is passed).
Expand All @@ -683,6 +684,42 @@ def get_size_image_from_file_paths(file_path, file_extension="tif"):
Dict of image sizes.
"""
file_path = Path(file_path)
if file_path.suffix in [".tif", ".tiff"]:
# read just the metadata
with tifffile.TiffFile(file_path) as tiff:
if not len(tiff.series):
raise ValueError(
f"Attempted to load {file_path} but didn't find a z-stack"
)
if len(tiff.series) != 1:
raise ValueError(
f"Attempted to load {file_path} but found multiple stacks"
)

shape = tiff.series[0].shape
axes = tiff.series[0].axes.lower()

if len(shape) != 3:
raise ValueError(
f"Attempted to load {file_path} but didn't find a "
f"3-dimensional stack. Found {axes} axes "
f"with shape {shape}"
)
# axes is e.g. "zxy"
if set(axes) == {"x", "y", "z"}:
image_shape = {ax: n for ax, n in zip(axes, shape)}
return image_shape
else: # metadata does not specify axes as expected,
logging.debug(
f"Axis metadata is {axes}, "
"which is not the expected set of x,y,z in any order. "
"Assume z,y,x"
)
image_shape = {
ax: n
for ax, n in zip(["z", "y", "x"], tiff.series[0].shape)
}
return image_shape

img_paths = get_sorted_file_paths(file_path, file_extension=file_extension)
z_shape = len(img_paths)
Expand Down
7 changes: 6 additions & 1 deletion brainglobe_utils/image_io/save.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@ def to_tiff(img_volume, dest_path, photometric="minisblack"):
Use 'minisblack' (default) for grayscale and 'rgb' for rgb
"""
dest_path = Path(dest_path)
tifffile.imwrite(dest_path, img_volume, photometric=photometric)
tifffile.imwrite(
dest_path,
img_volume,
photometric=photometric,
metadata={"axes": "ZYX"},
)


def to_tiffs(img_volume, path_prefix, path_suffix="", extension=".tif"):
Expand Down
13 changes: 13 additions & 0 deletions tests/tests/test_image_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,19 @@ def test_image_size_dir(tmp_path, array_3d):
assert image_shape["z"] == array_3d.shape[0]


def test_image_size_tiff_stack(tmp_path, array_3d):
"""
Test that image size can be detected from a directory of 2D tiffs
"""
filename = tmp_path.joinpath("image_size_tiff_stack.tif")
save.save_any(array_3d, filename)

image_shape = load.get_size_image_from_file_paths(filename)
assert image_shape["x"] == array_3d.shape[2]
assert image_shape["y"] == array_3d.shape[1]
assert image_shape["z"] == array_3d.shape[0]


def test_image_size_txt(txt_path, array_3d):
"""
Test that image size can be detected from a text file containing the paths
Expand Down

0 comments on commit 98b02a1

Please sign in to comment.