#!/usr/bin/env python3
"""
Use ``io_tif_to_tifs`` from UNRAVEL to load a 3D .tif image and save it as tifs.
Input:
- image.tif (either from -i path/image.tif or largest `*`.tif in cwd)
Outputs:
- ./<tif_dir_out>/slice_`*`.tif series
- ./parameters/metadata (text file)
Next command:
``reg_prep`` to prep autofluo images registration
Usage:
------
io_tif_to_tifs -i <path/image.tif> -t 488 [-v]
"""
import glob
import os
import numpy as np
from pathlib import Path
from rich import print
from rich.traceback import install
from tifffile import imwrite
import tifffile
from unravel.core.help_formatter import RichArgumentParser, SuppressMetavar, SM
from unravel.core.config import Configuration
from unravel.core.utils import log_command, verbose_start_msg, verbose_end_msg
[docs]
def parse_args():
parser = RichArgumentParser(formatter_class=SuppressMetavar, add_help=False, docstring=__doc__)
reqs = parser.add_argument_group('Required arguments')
reqs.add_argument('-i', '--input', help='path/image.tif', required=True, action=SM)
reqs.add_argument('-t', '--tif_dir', help='Name of output folder for outputting tifs', required=True, action=SM)
general = parser.add_argument_group('General arguments')
general.add_argument('-v', '--verbose', help='Increase verbosity. Default: False', action='store_true', default=False)
return parser.parse_args()
# TODO: Could remove find_largest_tif_file() and use glob matching only.
# TODO: Could keep metadata functions specific to io_metadata and the img_io module.
[docs]
def find_largest_tif_file():
""" Find and return the path to the largest .tif file in the current directory """
largest_file = None
max_size = -1
for file in glob.glob('*.tif'):
size = os.path.getsize(file)
if size > max_size:
max_size = size
largest_file = file
return largest_file
[docs]
def load_3D_tif(tif_path, desired_axis_order="xyz", return_res=False):
"""Load full res image from a 3D .tif and return ndarray
Default: axis_order=xyz (other option: axis_order="zyx")
Default: returns: ndarray
If return_res=True returns: ndarray, xy_res, z_res (resolution in um)"""
with tifffile.TiffFile(tif_path) as tif:
print(f"\n Loading {tif_path} as ndarray")
ndarray = tif.asarray() # Load image into memory (if not enough RAM, chunck data [e.g., w/ dask array])
ndarray = np.transpose(ndarray, (2, 1, 0)) if desired_axis_order == "xyz" else ndarray
print(f' {ndarray.shape=}')
if return_res:
xy_res, z_res = metadata_from_3D_tif(tif_path)
return ndarray, xy_res, z_res
else:
return ndarray
[docs]
def save_as_tifs(ndarray, tif_dir_out, ndarray_axis_order="xyz"):
"""Save <ndarray> as tifs in <Path(tif_dir_out)>"""
tif_dir_out = Path(tif_dir_out)
tif_dir_out.mkdir(parents=True, exist_ok=True)
if ndarray_axis_order == "xyz":
ndarray = np.transpose(ndarray, (2, 1, 0)) # Transpose to zyx (tiff expects zyx)
for i, slice_ in enumerate(ndarray):
slice_file_path = tif_dir_out / f"slice_{i:04d}.tif"
imwrite(str(slice_file_path), slice_)
print(f" Output: [default bold]{tif_dir_out}\n")
[docs]
@log_command
def main():
install()
args = parse_args()
Configuration.verbose = args.verbose
verbose_start_msg()
if args.input:
tif_path = args.input
else:
print("\n [red1]Please provide a path/image.tif for the -t option\n")
import sys ; sys.exit()
# Load .tif image (highest res dataset) as ndarray and extract voxel sizes in microns
img, xy_res, z_res = load_3D_tif(tif_path, desired_axis_order="xyz", return_res=True)
# Make parameters directory in the sample?? folder
os.makedirs("parameters", exist_ok=True)
# Save metadata to text file so resolution can be obtained by other commands/modules
metadata_txt_path = Path(".", "parameters", "metadata")
with open(metadata_txt_path, 'w') as file:
file.write(f"Voxel size: {xy_res:.4f}x{xy_res:.4f}x{z_res:.4f} µm^3")
# Save as tifs
tifs_output_path = Path(args.tif_dir)
save_as_tifs(img, tifs_output_path)
verbose_end_msg()
if __name__ == '__main__':
main()