Skip to content

Commit

Permalink
Merge branch 'main' into neuralynx_final_touches
Browse files Browse the repository at this point in the history
  • Loading branch information
h-mayorquin authored Oct 19, 2022
2 parents 89451af + a948581 commit 0416f30
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
### Features
* Added `ConverterPipe`, a class that allows chaining previously intialized interfaces for batch conversion and corresponding tests [PR #169](https://github.com/catalystneuro/neuroconv/pull/169)
* Added automatic extraction of metadata for `NeuralynxRecordingInterface` including filtering information for channels, device and recording time information [PR #170](https://github.com/catalystneuro/neuroconv/pull/170)
* Added stubbing capabilities to timestamp extraction in the `MovieInterface` avoiding scanning through the whole file when `stub_test=True` [PR #181](https://github.com/catalystneuro/neuroconv/pull/181)


# v0.2.1
Expand Down
6 changes: 4 additions & 2 deletions src/neuroconv/datainterfaces/behavior/movie/movie_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ def __init__(self, file_path: FilePathType):
self._frame_count = None
self._movie_open_msg = "The Movie file is not open!"

def get_movie_timestamps(self):
def get_movie_timestamps(self, max_frames=None):
"""Return numpy array of the timestamps(s) for a movie file."""
cv2 = get_package(package_name="cv2", installation_instructions="pip install opencv-python")

timestamps = []
for _ in tqdm(range(self.get_movie_frame_count()), desc="retrieving timestamps"):
total_frames = self.get_movie_frame_count()
frames_to_extract = min(total_frames, max_frames) if max_frames else total_frames
for _ in tqdm(range(frames_to_extract), desc="retrieving timestamps"):
success, _ = self.vc.read()
if not success:
break
Expand Down
31 changes: 19 additions & 12 deletions src/neuroconv/datainterfaces/behavior/movie/moviedatainterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def run_conversion(
starting_times : list, optional
List of start times for each movie. If unspecified, assumes that the movies in the file_paths list are in
sequential order and are contiguous.
starting_times : list, optional
starting_frames : list, optional
List of start frames for each movie written using external mode.
Required if more than one path is specified per ImageSeries in external mode.
timestamps : list, optional
Expand Down Expand Up @@ -220,8 +220,18 @@ def run_conversion(
else:
raise ValueError("provide starting times as a list of len " f"{len(movies_metadata_unique)}")

# Iterate over unique movies
stub_frames = 10
for j, (image_series_kwargs, file_list) in enumerate(zip(movies_metadata_unique, file_paths_list)):

with VideoCaptureContext(str(file_list[0])) as vc:
fps = vc.get_movie_fps()
max_frames = stub_frames if stub_test else None
extracted_timestamps = vc.get_movie_timestamps(max_frames)
movie_timestamps = (
starting_times[j] + extracted_timestamps if timestamps is None else timestamps[:max_frames]
)

if external_mode:
num_files = len(file_list)
if num_files > 1 and starting_frames is None:
Expand All @@ -236,10 +246,6 @@ def run_conversion(
elif num_files > 1:
image_series_kwargs.update(starting_frame=starting_frames[j])

with VideoCaptureContext(str(file_list[0])) as vc:
fps = vc.get_movie_fps()
if timestamps is None:
timestamps = starting_times[j] + vc.get_movie_timestamps()
image_series_kwargs.update(
format="external",
external_file=file_list,
Expand All @@ -256,18 +262,17 @@ def run_conversion(
chunk_data = True
with VideoCaptureContext(str(file)) as video_capture_ob:
if stub_test:
video_capture_ob.frame_count = 10
video_capture_ob.frame_count = stub_frames
total_frames = video_capture_ob.get_movie_frame_count()
frame_shape = video_capture_ob.get_frame_shape()
timestamps = starting_times[j] + video_capture_ob.get_movie_timestamps()
fps = video_capture_ob.get_movie_fps()

maxshape = (total_frames, *frame_shape)
best_gzip_chunk = (1, frame_shape[0], frame_shape[1], 3)
tqdm_pos, tqdm_mininterval = (0, 10)
if chunk_data:
video_capture_ob = VideoCaptureContext(str(file))
if stub_test:
video_capture_ob.frame_count = 10
video_capture_ob.frame_count = stub_frames
iterable = DataChunkIterator(
data=tqdm(
iterable=video_capture_ob,
Expand All @@ -289,7 +294,7 @@ def run_conversion(
iterable = np.zeros(shape=maxshape, dtype="uint8")
with VideoCaptureContext(str(file)) as video_capture_ob:
if stub_test:
video_capture_ob.frame_count = 10
video_capture_ob.frame_count = stub_frames
with tqdm(
desc=f"Reading movie data for {Path(file).name}",
position=tqdm_pos,
Expand All @@ -315,7 +320,9 @@ def run_conversion(
chunks=best_gzip_chunk,
)
image_series_kwargs.update(data=data)
rate = calculate_regular_series_rate(series=timestamps)

# Store sampling rate if timestamps are regular
rate = calculate_regular_series_rate(series=movie_timestamps)
if rate is not None:
if fps != rate:
warn(
Expand All @@ -325,7 +332,7 @@ def run_conversion(
)
image_series_kwargs.update(starting_time=starting_times[j], rate=rate)
else:
image_series_kwargs.update(timestamps=timestamps)
image_series_kwargs.update(timestamps=movie_timestamps)

if module_name is None:
nwbfile.add_acquisition(ImageSeries(**image_series_kwargs))
Expand Down
6 changes: 5 additions & 1 deletion tests/test_behavior/test_movie_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,10 @@ def test_external_mode_assertion_with_movie_name_duplication(self):
)

def test_movie_stub(self):
conversion_opts = dict(Movie=dict(starting_times=self.starting_times, external_mode=False, stub_test=True))
timestamps = [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15]
conversion_opts = dict(
Movie=dict(starting_times=self.starting_times, timestamps=timestamps, external_mode=False, stub_test=True)
)
self.nwb_converter.run_conversion(
nwbfile_path=self.nwbfile_path,
overwrite=True,
Expand All @@ -221,6 +224,7 @@ def test_movie_stub(self):
for no in range(len(metadata["Behavior"]["Movies"])):
movie_interface_name = metadata["Behavior"]["Movies"][no]["name"]
assert mod[movie_interface_name].data.shape[0] == 10
assert mod[movie_interface_name].timestamps.shape[0] == 10

def test_movie_irregular_timestamps(self):
timestamps = [1, 2, 4]
Expand Down

0 comments on commit 0416f30

Please sign in to comment.