Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/update_suite2psegmentationextrac…
Browse files Browse the repository at this point in the history
…tor' into update_suite2psegmentationextractor
  • Loading branch information
weiglszonja committed Oct 31, 2023
2 parents 55589ca + ade4b3f commit c26c4ca
Show file tree
Hide file tree
Showing 12 changed files with 1,235 additions and 13 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/check-docstrings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Check Docstrings
on:
workflow_dispatch:
pull_request:

jobs:
check-docstrings:
uses: catalystneuro/.github/.github/workflows/check_docstrings.yaml@main
with:
python-version: '3.10'
repository: 'catalystneuro/roiextractors'
package-name: 'roiextractors'
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 23.9.1
rev: 23.10.1
hooks:
- id: black
exclude: ^docs/
Expand Down
6 changes: 6 additions & 0 deletions src/roiextractors/extractorlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from .extractors.tiffimagingextractors import (
TiffImagingExtractor,
ScanImageTiffImagingExtractor,
ScanImageTiffSinglePlaneImagingExtractor,
ScanImageTiffMultiPlaneImagingExtractor,
BrukerTiffMultiPlaneImagingExtractor,
BrukerTiffSinglePlaneImagingExtractor,
MicroManagerTiffImagingExtractor,
Expand All @@ -25,12 +27,15 @@
from .extractors.miniscopeimagingextractor import MiniscopeImagingExtractor
from .multisegmentationextractor import MultiSegmentationExtractor
from .multiimagingextractor import MultiImagingExtractor
from .volumetricimagingextractor import VolumetricImagingExtractor

imaging_extractor_full_list = [
NumpyImagingExtractor,
Hdf5ImagingExtractor,
TiffImagingExtractor,
ScanImageTiffImagingExtractor,
ScanImageTiffSinglePlaneImagingExtractor,
ScanImageTiffMultiPlaneImagingExtractor,
BrukerTiffMultiPlaneImagingExtractor,
BrukerTiffSinglePlaneImagingExtractor,
MicroManagerTiffImagingExtractor,
Expand All @@ -39,6 +44,7 @@
SbxImagingExtractor,
NumpyMemmapImagingExtractor,
MemmapImagingExtractor,
VolumetricImagingExtractor,
]

segmentation_extractor_full_list = [
Expand Down
12 changes: 10 additions & 2 deletions src/roiextractors/extractors/tiffimagingextractors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
TiffImagingExtractor
A ImagingExtractor for TIFF files.
ScanImageTiffImagingExtractor
Specialized extractor for reading TIFF files produced via ScanImage.
Legacy extractor for reading TIFF files produced via ScanImage v3.8.
ScanImageTiffSinglePlaneImagingExtractor
Specialized extractor for reading single-plane TIFF files produced via ScanImage.
ScanImageTiffMultiPlaneImagingExtractor
Specialized extractor for reading multi-plane TIFF files produced via ScanImage.
BrukerTiffMultiPlaneImagingExtractor
Specialized extractor for reading TIFF files produced via Bruker.
BrukerTiffSinglePlaneImagingExtractor
Expand All @@ -25,6 +29,10 @@
Specialized extractor for reading TIFF files produced via Micro-Manager.
"""
from .tiffimagingextractor import TiffImagingExtractor
from .scanimagetiffimagingextractor import ScanImageTiffImagingExtractor
from .scanimagetiffimagingextractor import (
ScanImageTiffImagingExtractor,
ScanImageTiffMultiPlaneImagingExtractor,
ScanImageTiffSinglePlaneImagingExtractor,
)
from .brukertiffimagingextractor import BrukerTiffMultiPlaneImagingExtractor, BrukerTiffSinglePlaneImagingExtractor
from .micromanagertiffimagingextractor import MicroManagerTiffImagingExtractor
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
"""Utility functions for ScanImage TIFF Extractors."""
import numpy as np
from ...extraction_tools import PathType, get_package


def _get_scanimage_reader() -> type:
"""Import the scanimage-tiff-reader package and return the ScanImageTiffReader class."""
return get_package(
package_name="ScanImageTiffReader", installation_instructions="pip install scanimage-tiff-reader"
).ScanImageTiffReader


def extract_extra_metadata(
file_path: PathType,
) -> dict: # TODO: Refactor neuroconv to reference this implementation to avoid duplication
"""Extract metadata from a ScanImage TIFF file.
Parameters
----------
file_path : PathType
Path to the TIFF file.
Returns
-------
extra_metadata: dict
Dictionary of metadata extracted from the TIFF file.
Notes
-----
Known to work on SI versions v3.8.0, v2019bR0, v2022.0.0, and v2023.0.0
"""
ScanImageTiffReader = _get_scanimage_reader()
io = ScanImageTiffReader(str(file_path))
extra_metadata = {}
for metadata_string in (io.description(iframe=0), io.metadata()):
metadata_dict = {
x.split("=")[0].strip(): x.split("=")[1].strip()
for x in metadata_string.replace("\n", "\r").split("\r")
if "=" in x
}
extra_metadata = dict(**extra_metadata, **metadata_dict)
return extra_metadata


def parse_matlab_vector(matlab_vector: str) -> list:
"""Parse a MATLAB vector string into a list of integer values.
Parameters
----------
matlab_vector : str
MATLAB vector string.
Returns
-------
vector: list of int
List of integer values.
Raises
------
ValueError
If the MATLAB vector string cannot be parsed.
Notes
-----
MATLAB vector string is of the form "[1 2 3 ... N]" or "[1,2,3,...,N]" or "[1;2;3;...;N]".
There may or may not be whitespace between the values. Ex. "[1, 2, 3]" or "[1,2,3]".
"""
vector = matlab_vector.strip("[]")
if ";" in vector:
vector = vector.split(";")
elif "," in vector:
vector = vector.split(",")
elif " " in vector:
vector = vector.split(" ")
elif len(vector) == 1:
pass
else:
raise ValueError(f"Could not parse vector from {matlab_vector}.")
vector = [int(x.strip()) for x in vector if x != ""]
return vector


def parse_metadata(metadata: dict) -> dict:
"""Parse metadata dictionary to extract relevant information and store it standard keys for ImagingExtractors.
Currently supports
- sampling_frequency
- num_planes
- frames_per_slice
- channel_names
- num_channels
Parameters
----------
metadata : dict
Dictionary of metadata extracted from the TIFF file.
Returns
-------
metadata_parsed: dict
Dictionary of parsed metadata.
Notes
-----
Known to work on SI versions v2019bR0, v2022.0.0, and v2023.0.0. Fails on v3.8.0.
SI.hChannels.channelsActive = string of MATLAB-style vector with channel integers (see parse_matlab_vector).
SI.hChannels.channelName = "{'channel_name_1' 'channel_name_2' ... 'channel_name_M'}"
where M is the number of channels (active or not).
"""
sampling_frequency = float(metadata["SI.hRoiManager.scanFrameRate"])
num_planes = int(metadata["SI.hStackManager.numSlices"])
frames_per_slice = int(metadata["SI.hStackManager.framesPerSlice"])
active_channels = parse_matlab_vector(metadata["SI.hChannels.channelsActive"])
channel_indices = np.array(active_channels) - 1 # Account for MATLAB indexing
channel_names = np.array(metadata["SI.hChannels.channelName"].split("'")[1::2])
channel_names = channel_names[channel_indices].tolist()
num_channels = len(channel_names)
metadata_parsed = dict(
sampling_frequency=sampling_frequency,
num_channels=num_channels,
num_planes=num_planes,
frames_per_slice=frames_per_slice,
channel_names=channel_names,
)
return metadata_parsed


def parse_metadata_v3_8(metadata: dict) -> dict:
"""Parse metadata dictionary to extract relevant information and store it standard keys for ImagingExtractors.
Requires old version of metadata (v3.8).
Currently supports
- sampling frequency
- num_channels
- num_planes
Parameters
----------
metadata : dict
Dictionary of metadata extracted from the TIFF file.
Returns
-------
metadata_parsed: dict
Dictionary of parsed metadata.
"""
sampling_frequency = float(metadata["state.acq.frameRate"])
num_channels = int(metadata["state.acq.numberOfChannelsSave"])
num_planes = int(metadata["state.acq.numberOfZSlices"])
metadata_parsed = dict(
sampling_frequency=sampling_frequency,
num_channels=num_channels,
num_planes=num_planes,
)
return metadata_parsed


def extract_timestamps_from_file(file_path: PathType) -> np.ndarray:
"""Extract the frame timestamps from a ScanImage TIFF file.
Parameters
----------
file_path : PathType
Path to the TIFF file.
Returns
-------
timestamps : numpy.ndarray
Array of frame timestamps in seconds.
Raises
------
AssertionError
If the frame timestamps are not found in the TIFF file.
Notes
-----
Known to work on SI versions v2019bR0, v2022.0.0, and v2023.0.0. Fails on v3.8.0.
"""
ScanImageTiffReader = _get_scanimage_reader()
io = ScanImageTiffReader(str(file_path))
assert "frameTimestamps_sec" in io.description(iframe=0), "frameTimestamps_sec not found in TIFF file"
num_frames = io.shape()[0]
timestamps = np.zeros(num_frames)
for iframe in range(num_frames):
description = io.description(iframe=iframe)
description_lines = description.split("\n")
for line in description_lines:
if "frameTimestamps_sec" in line:
timestamps[iframe] = float(line.split("=")[1].strip())
break

return timestamps
Loading

0 comments on commit c26c4ca

Please sign in to comment.