from __future__ import annotations
from tifffile import TiffFile, imwrite, memmap
import json
import re
import os
import numpy as np
from dask import array as da
from .._cupy import xp
from ..utils.axesop import switch_slice
__all__ = ["imwrite",
"memmap",
"open_tif",
"open_mrc",
"open_img",
"open_as_dask",
"get_scale_from_meta",
"get_imsave_meta_from_img"]
def load_json(s:str):
return json.loads(re.sub("'", '"', s))
[docs]def open_tif(path:str, return_img:bool=False, memmap:bool=False):
with TiffFile(path) as tif:
ijmeta = tif.imagej_metadata
series0 = tif.series[0]
pagetag = series0.pages[0].tags
hist = []
if ijmeta is None:
ijmeta = {}
ijmeta.pop("ROI", None)
if "Info" in ijmeta.keys():
try:
infodict = load_json(ijmeta["Info"])
except:
infodict = {}
if "impyhist" in infodict.keys():
hist = infodict["impyhist"].split("->")
try:
axes = series0.axes.lower()
except:
axes = None
tags = {v.name: v.value for v in pagetag.values()}
out = {"axes": axes, "ijmeta": ijmeta, "history": hist, "tags": tags}
if return_img:
if memmap:
out["image"] = tif.asarray(out="memmap")
else:
out["image"] = tif.asarray()
return out
[docs]def open_mrc(path:str, return_img:bool=False, memmap:bool=False):
import mrcfile
if memmap:
open_func = mrcfile.mmap
else:
open_func = mrcfile.open
# By default mrcfile functions returns non-writeable array, which is incompatible
# with some functions in ImgArray. We need to specify mode="r+".
with open_func(path, mode="r+") as mrc:
ijmeta = {"unit": "nm"}
ndim = len(mrc.voxel_size.item())
if ndim == 3:
axes = "zyx"
ijmeta["spacing"] = mrc.voxel_size.z/10
elif ndim == 2:
axes = "yx"
else:
raise RuntimeError(f"ndim = {ndim} not supported")
tags = {}
tags["XResolution"] = [1, mrc.voxel_size.x/10]
tags["YResolution"] = [1, mrc.voxel_size.y/10]
out = {"axes": axes, "ijmeta": ijmeta, "history": [], "tags": tags}
if return_img:
out["image"] = mrc.data
return out
[docs]def open_as_dask(path: str, chunks):
meta, img = open_img(path, memmap=True)
axes = meta["axes"]
if chunks == "default":
chunks = switch_slice("yx", axes, ifin=img.shape, ifnot=("auto",)*img.ndim)
if img.dtype == ">u2":
img = img.astype(np.uint16)
img = da.from_array(img, chunks=chunks).map_blocks(
np.array, meta=np.array([], dtype=img.dtype)
)
return meta, img
[docs]def open_img(path, memmap: bool = False):
_, fext = os.path.splitext(os.path.basename(path))
if fext in (".tif", ".tiff"):
meta = open_tif(path, True, memmap=memmap)
img = meta.pop("image")
elif fext in (".mrc", ".rec"):
meta = open_mrc(path, True, memmap=memmap)
img = meta.pop("image")
else:
from skimage import io
img = io.imread(path)
if fext in (".png", ".jpg") and img.ndim == 3 and img.shape[-1] <= 4:
meta = {"axes":"yxc", "ijmeta":{}, "history":[]}
else:
meta = {"axes":None, "ijmeta":{}, "history":[]}
return meta, img