- czi: read tirf angle
- tiff: read spacing
This commit is contained in:
@@ -11,3 +11,4 @@
|
||||
/poetry.lock
|
||||
/dist/
|
||||
/uv.lock
|
||||
.agentbridge
|
||||
@@ -191,7 +191,8 @@ def get_positions(path: str | Path) -> Optional[list[int]]:
|
||||
return subclass.get_positions(AbstractReader.split_path_series(path)[0])
|
||||
|
||||
|
||||
class Imread(np.lib.mixins.NDArrayOperatorsMixin, ABC):
|
||||
# noinspection PyAbstractClass
|
||||
class Imread(np.lib.mixins.NDArrayOperatorsMixin):
|
||||
"""class to read image files, while taking good care of important metadata,
|
||||
currently optimized for .czi files, but can open anything that bioformats can handle
|
||||
path: path to the image file
|
||||
@@ -1528,6 +1529,12 @@ class AbstractReader(Imread, metaclass=ABCMeta):
|
||||
self.immersionN = 1
|
||||
|
||||
p = re.compile(r"(\d+):(\d+)$")
|
||||
if self.ome.structured_annotations is not None:
|
||||
tirf_angles = {}
|
||||
for annotation in self.ome.structured_annotations:
|
||||
if annotation.description is not None and annotation.description.lower() == "tirfangle":
|
||||
tirf_angles[int(annotation.id.split(":")[1])] = annotation.value
|
||||
self.tirfangle = [angle for track, angle in sorted(tirf_angles.items(), key=lambda x: x[0])]
|
||||
try:
|
||||
self.track, self.detector = zip(
|
||||
*[
|
||||
|
||||
@@ -248,7 +248,7 @@ class Reader(AbstractReader, ABC):
|
||||
return [(i - j, i - j + k) for i, j, k in zip(directory_entry.start, start, directory_entry.shape)]
|
||||
|
||||
@cached_property
|
||||
def tiles(self):
|
||||
def tiles(self) -> tuple[int, int]:
|
||||
columns = 1
|
||||
rows = 1
|
||||
xml = self.reader.metadata()
|
||||
@@ -335,6 +335,7 @@ class OmeParse:
|
||||
self.get_light_sources()
|
||||
self.get_filters()
|
||||
self.get_pixels()
|
||||
self.get_tirf_angle()
|
||||
self.get_channels()
|
||||
self.get_planes()
|
||||
self.get_annotations()
|
||||
@@ -555,6 +556,18 @@ class OmeParse:
|
||||
elif self.size_z > 1 and distance.attrib["Id"] == "Z":
|
||||
self.ome.images[0].pixels.physical_size_z = float(self.text(distance.find("Value"))) * 1e6
|
||||
|
||||
def get_tirf_angle(self) -> None:
|
||||
if self.version == "1.0":
|
||||
for track_setup in self.multi_track_setup:
|
||||
tirf_angle = track_setup.find("TirfAngle")
|
||||
if tirf_angle is not None:
|
||||
self.ome.structured_annotations.append(
|
||||
model.DoubleAnnotation(
|
||||
description="TirfAngle", id="Annotation:0", value=50 * float(tirf_angle.text)
|
||||
)
|
||||
)
|
||||
self.ome.images[0].annotation_refs.append(model.AnnotationRef(id="Annotation:0"))
|
||||
|
||||
@cached_property
|
||||
def positions(self) -> tuple[float, float, Optional[float]]:
|
||||
if self.version == "1.0":
|
||||
@@ -677,14 +690,12 @@ class OmeParse:
|
||||
else:
|
||||
light_source_settings = None
|
||||
|
||||
self.ome.images[0].pixels.channels.append(
|
||||
model.Channel(
|
||||
channel = dict(
|
||||
id=f"Channel:{idx}",
|
||||
name=channel.attrib["Name"],
|
||||
acquisition_mode=self.text(channel.find("AcquisitionMode")).replace( # type: ignore
|
||||
"SingleMoleculeLocalisation", "SingleMoleculeImaging"
|
||||
),
|
||||
color=color,
|
||||
detector_settings=model.DetectorSettings(
|
||||
id=detector.attrib["Id"].replace(" ", ""), binning=binning
|
||||
),
|
||||
@@ -697,7 +708,11 @@ class OmeParse:
|
||||
light_source_settings=light_source_settings,
|
||||
samples_per_pixel=samples_per_pixel,
|
||||
)
|
||||
)
|
||||
|
||||
if color is not None:
|
||||
channel["color"] = color
|
||||
|
||||
self.ome.images[0].pixels.channels.append(model.Channel(**channel))
|
||||
|
||||
def get_planes(self) -> None:
|
||||
try:
|
||||
|
||||
@@ -142,11 +142,18 @@ class Reader(AbstractReader, ABC):
|
||||
)
|
||||
for c, z, t in product(range(size_c), range(size_z), range(size_t)):
|
||||
ome.images[0].pixels.planes.append(model.Plane(the_c=c, the_z=z, the_t=t, delta_t=interval_t * t))
|
||||
if (spacing := self.metadata.get("spacing")) is not None:
|
||||
ome.images[0].pixels.physical_size_z = spacing
|
||||
if (unit := self.metadata.get("unit")) is not None and unit.lower() != "micron":
|
||||
raise ValueError(f"cannot parse unit {unit}")
|
||||
|
||||
return ome
|
||||
|
||||
def open(self):
|
||||
if self.series != 0:
|
||||
raise FileNotFoundError(f"Series {self.series} not found in {self.path}. Tifread only supports one series.")
|
||||
raise FileNotFoundError(
|
||||
f"Series {self.series} not found in {self.path}. Tifread only supports one series."
|
||||
)
|
||||
self.reader = tifffile.TiffFile(self.path)
|
||||
page = self.reader.pages.first
|
||||
self.p_ndim = page.ndim # noqa
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "ndbioimage"
|
||||
version = "2026.4.0"
|
||||
version = "2026.7.0"
|
||||
description = "Bio image reading, metadata and some affine registration."
|
||||
authors = [
|
||||
{ name = "W. Pomp", email = "w.pomp@nki.nl" }
|
||||
@@ -24,8 +24,8 @@ dependencies = [
|
||||
"pyyaml",
|
||||
"SimpleITK-SimpleElastix; sys_platform != 'darwin'",
|
||||
"scikit-image",
|
||||
"tifffile <= 2025.1.10",
|
||||
"tiffwrite >= 2024.12.1",
|
||||
"tifffile >= 2024.1.30, <= 2025.1.10",
|
||||
"tiffwrite >= 2026.5.0",
|
||||
"tqdm",
|
||||
]
|
||||
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user