Source code for roiextractors.extractors.tiffimagingextractors.tiffimagingextractor
"""A TIFF imaging extractor for TIFF files.
Classes
-------
TiffImagingExtractor
A TIFF imaging extractor for TIFF files.
"""
from pathlib import Path
from warnings import warn
import numpy as np
from ...extraction_tools import (
PathType,
get_package,
raise_multi_channel_or_depth_not_implemented,
)
from ...imagingextractor import ImagingExtractor
[docs]
class TiffImagingExtractor(ImagingExtractor):
"""A ImagingExtractor for TIFF files."""
extractor_name = "TiffImaging"
mode = "file"
def __init__(self, file_path: PathType, sampling_frequency: float):
"""Create a TiffImagingExtractor instance from a TIFF file.
Parameters
----------
file_path : PathType
Path to the TIFF file.
sampling_frequency : float
The frequency at which the frames were sampled, in Hz.
"""
tifffile = get_package(package_name="tifffile")
super().__init__()
self.file_path = Path(file_path)
self._sampling_frequency = sampling_frequency
if self.file_path.suffix not in [".tiff", ".tif", ".TIFF", ".TIF"]:
warn(
"File suffix ({self.file_path.suffix}) is not one of .tiff, .tif, .TIFF, or .TIF! "
"The TiffImagingExtractor may not be appropriate."
)
with tifffile.TiffFile(self.file_path) as tif:
self._num_channels = len(tif.series)
try:
self._video = tifffile.memmap(self.file_path, mode="r")
except Exception as e:
try:
with tifffile.TiffFile(self.file_path) as tif:
self._video = tif.asarray()
warn(
f"memmap of TIFF file could not be established due to the following error: {e}. "
"Reading entire matrix into memory. Consider using the ScanImageTiffSinglePlaneImagingExtractor or ScanImageTiffMultiPlaneImagingExtractor for lazy data access.",
stacklevel=2,
)
except Exception as e2:
raise RuntimeError(
f"Memory mapping failed: {e}. \n"
f"Attempt to read the TIFF file directly also failed: {e2}. \n"
f"Consider using ScanImageTiffSinglePlaneImagingExtractor or ScanImageTiffMultiPlaneImagingExtractor for lazy data access, check the file integrity. \n"
f"If problems persist, please report an issue at roiextractors/issues."
)
shape = self._video.shape
if len(shape) == 3:
self._num_samples, self._num_rows, self._num_columns = shape
self._num_channels = 1
else:
raise_multi_channel_or_depth_not_implemented(extractor_name=self.extractor_name)
self._kwargs = {
"file_path": str(Path(file_path).absolute()),
"sampling_frequency": sampling_frequency,
}
[docs]
def get_series(self, start_sample=None, end_sample=None) -> np.ndarray:
return self._video[start_sample:end_sample, ...]
[docs]
def get_image_shape(self) -> tuple[int, int]:
"""Get the shape of the video frame (num_rows, num_columns).
Returns
-------
image_shape: tuple
Shape of the video frame (num_rows, num_columns).
"""
return (self._num_rows, self._num_columns)
[docs]
def get_channel_names(self) -> list:
"""Return the channel names (deprecated)."""
warn(
"get_channel_names is deprecated and will be removed in or after October 2026.",
FutureWarning,
stacklevel=2,
)
return [f"channel_{i}" for i in range(self._num_channels)]
[docs]
def get_native_timestamps(
self, start_sample: int | None = None, end_sample: int | None = None
) -> np.ndarray | None:
# Basic TIFF files do not have native timestamps
return None