Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update ImagingExtractor #365

Open
wants to merge 27 commits into
base: 0.6.0dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4043df4
updated imaging extractor to reflect 1-channel imaging extractors
pauladkisson Sep 19, 2024
b3fc00c
updated get_dtype to abstract to facilitate more efficient implementa…
pauladkisson Sep 19, 2024
889f721
removed channel from get_frames and get_video
pauladkisson Sep 19, 2024
ae8f055
removed write_imaging
pauladkisson Sep 19, 2024
76aa346
cleaned up numpyimagingextractor init
pauladkisson Sep 20, 2024
c9c3a54
removed channels from numpyimagingextractor
pauladkisson Sep 20, 2024
bd954c4
removed get_available_channels from imagingextractor
pauladkisson Sep 20, 2024
6431da8
updated testing with no channels
pauladkisson Sep 20, 2024
358923e
updated get_frames to allow frame_idxs out of order
pauladkisson Sep 20, 2024
0dfab19
moved check_imaging_equal to imagingextractor itself
pauladkisson Sep 20, 2024
0d45f9f
added imagingextractor_mixin
pauladkisson Sep 20, 2024
a4797ee
added test_numpy_imaging_extractor with mixin
pauladkisson Sep 20, 2024
1cd743d
fixed imaging extractor to pass tests
pauladkisson Sep 20, 2024
8db166f
switched to fixtures to allow more complex setup
pauladkisson Sep 21, 2024
1bdf12e
added from file test
pauladkisson Sep 21, 2024
fc43167
fixed frame_slice so that it passes tests
pauladkisson Sep 23, 2024
ca7bcc3
moved input handling to frame_slice method instead of init
pauladkisson Sep 23, 2024
36ed953
updated frame validation
pauladkisson Sep 23, 2024
2d1f3f2
updated frame validation
pauladkisson Sep 23, 2024
cd26c34
refactored frame slice tests into their own mixin
pauladkisson Sep 24, 2024
211f9c3
added tests for frame_slice method
pauladkisson Sep 24, 2024
7ea7142
Merge branch '0.6.0dev' into 0.6.0
pauladkisson Sep 24, 2024
2e8dc4f
reorganized tests to pass while PR is in progress
pauladkisson Sep 24, 2024
777393e
ignore old_tests
pauladkisson Sep 24, 2024
667ebb8
Merge branch '0.6.0dev' into 0.6.0
pauladkisson Sep 24, 2024
ae8d6e6
fixed python 3.9 isinstance bug
pauladkisson Sep 24, 2024
30279d2
refactored input validation for get_video and get_frames into their o…
pauladkisson Sep 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- name: Install roiextractors with testing requirements
run: pip install .[test]
- name: Run minimal tests
run: pytest tests/test_internals -n auto --dist loadscope
run: pytest tests/test_minimal -n auto --dist loadscope

- name: Test full installation
run: pip install .[full]
Expand All @@ -53,7 +53,7 @@ jobs:
key: ophys-datasets-042023-${{ matrix.os }}-${{ steps.ophys.outputs.HASH_OPHYS_DATASET }}

- name: Run full pytest with coverage
run: pytest -n auto --dist loadscope --cov=./ --cov-report xml:./codecov.xml
run: pytest -n auto --dist loadscope --cov=./ --cov-report xml:./codecov.xml --ignore=old_tests
- if: ${{ matrix.python-version == '3.9' && matrix.os == 'ubuntu-latest'}}
name: Upload full coverage to Codecov
uses: codecov/codecov-action@v4
Expand Down
File renamed without changes.
4 changes: 4 additions & 0 deletions old_tests/gin_test_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"LOCAL_PATH": "/Users/pauladkisson/Documents/CatalystNeuro/Neuroconv/testing_data/aws/neuroconv_gin_datasets",
"SAVE_OUTPUTS": false
}
File renamed without changes.
Empty file.
File renamed without changes.
File renamed without changes.
File renamed without changes.
112 changes: 14 additions & 98 deletions src/roiextractors/extractors/numpyextractors/numpyextractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
"""

from pathlib import Path
from typing import Optional, Tuple
from typing import Optional, Tuple, Union

import numpy as np

from ...extraction_tools import PathType, FloatType, ArrayType
from ...extraction_tools import PathType, FloatType, ArrayType, IntType
from ...imagingextractor import ImagingExtractor
from ...segmentationextractor import SegmentationExtractor

Expand All @@ -26,24 +26,17 @@ class NumpyImagingExtractor(ImagingExtractor):
is_writable = True
installation_mesg = "" # error message when not installed

def __init__(
self,
timeseries: PathType,
sampling_frequency: FloatType,
channel_names: ArrayType = None,
):
"""Create a NumpyImagingExtractor from a .npy file.
def __init__(self, timeseries: Union[PathType, np.ndarray], sampling_frequency: FloatType):
"""Create a NumpyImagingExtractor from a .npy file or a numpy.ndarray.

Parameters
----------
timeseries: PathType
Path to .npy file.
timeseries: PathType or numpy.ndarray
Path to .npy file or numpy array containing the video.
sampling_frequency: FloatType
Sampling frequency of the video in Hz.
channel_names: ArrayType
List of channel names.
"""
ImagingExtractor.__init__(self)
super().__init__()

if isinstance(timeseries, (str, Path)):
timeseries = Path(timeseries)
Expand All @@ -68,62 +61,12 @@ def __init__(
raise TypeError("'timeseries' can be a str or a numpy array")

self._sampling_frequency = float(sampling_frequency)
self._num_frames, self._num_rows, self._num_columns = self._video.shape
self._dtype = self._video.dtype

self._sampling_frequency = sampling_frequency
self._channel_names = channel_names

(
self._num_frames,
self._num_rows,
self._num_columns,
self._num_channels,
) = self.get_video_shape(self._video)

if len(self._video.shape) == 3:
# check if this converts to np.ndarray
self._video = self._video[np.newaxis, :]

if self._channel_names is not None:
assert len(self._channel_names) == self._num_channels, (
"'channel_names' length is different than number " "of channels"
)
else:
self._channel_names = [f"channel_{ch}" for ch in range(self._num_channels)]

@staticmethod
def get_video_shape(video) -> Tuple[int, int, int, int]:
"""Get the shape of a video (num_frames, num_rows, num_columns, num_channels).

Parameters
----------
video: numpy.ndarray
The video to get the shape of.

Returns
-------
video_shape: tuple
The shape of the video (num_frames, num_rows, num_columns, num_channels).
"""
if len(video.shape) == 3:
# 1 channel
num_channels = 1
num_frames, num_rows, num_columns = video.shape
else:
num_frames, num_rows, num_columns, num_channels = video.shape
return num_frames, num_rows, num_columns, num_channels

def get_frames(self, frame_idxs=None, channel: Optional[int] = 0) -> np.ndarray:
if frame_idxs is None:
frame_idxs = [frame for frame in range(self.get_num_frames())]

frames = self._video.take(indices=frame_idxs, axis=0)
if channel is not None:
frames = frames[..., channel].squeeze()

return frames

def get_video(self, start_frame=None, end_frame=None, channel: Optional[int] = 0) -> np.ndarray:
return self._video[start_frame:end_frame, ..., channel]
def get_video(self, start_frame: Optional[int] = None, end_frame: Optional[int] = None) -> np.ndarray:
start_frame, end_frame = self._validate_get_video_arguments(start_frame=start_frame, end_frame=end_frame)
return self._video[start_frame:end_frame, ...]

def get_image_size(self) -> Tuple[int, int]:
return (self._num_rows, self._num_columns)
Expand All @@ -134,35 +77,8 @@ def get_num_frames(self):
def get_sampling_frequency(self):
return self._sampling_frequency

def get_channel_names(self):
return self._channel_names

def get_num_channels(self):
return self._num_channels

@staticmethod
def write_imaging(imaging, save_path, overwrite: bool = False):
"""Write a NumpyImagingExtractor to a .npy file.

Parameters
----------
imaging: NumpyImagingExtractor
The imaging extractor object to be written to file.
save_path: str or PathType
Path to .npy file.
overwrite: bool
If True, overwrite file if it already exists.
"""
save_path = Path(save_path)
assert save_path.suffix == ".npy", "'save_path' should have a .npy extension"

if save_path.is_file():
if not overwrite:
raise FileExistsError("The specified path exists! Use overwrite=True to overwrite it.")
else:
save_path.unlink()

np.save(save_path, imaging.get_video())
def get_dtype(self):
return self._dtype


class NumpySegmentationExtractor(SegmentationExtractor):
Expand Down
Loading
Loading