-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
added a method for curating frame extraction within a start and end t… #2945
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
base: main
Are you sure you want to change the base?
Conversation
…ime in HH:MM:SS format. Minimum gap of frames between selected frames either in int # or percentage of the total frames of the video 2% gap. Introduced a separate number of frames selection using DLCs widget. Output pushes frames into a similar fashion with a meta-data like file
|
Let me know what you require to proceed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds functionality to extract frames from specific time windows within a video, enabling users to select behavior-specific or visible-subject frames. The feature introduces a "curated" extraction mode with customizable time ranges, minimum frame gaps, and frame counts.
Changes:
- Added a new "curated" extraction method to the frame extraction GUI
- Implemented time-windowed frame extraction with configurable parameters (start/end time, minimum gap, frame count)
- Created a parameter dialog for users to specify extraction criteria
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| deeplabcut/gui/tabs/extract_frames.py | Adds ParameterDialog UI and integrates curated extraction mode into the extraction workflow |
| deeplabcut/generate_training_dataset/curated_video_frame_extraction.py | Implements core logic for extracting frames within time windows with configurable spacing |
Comments suppressed due to low confidence (1)
deeplabcut/generate_training_dataset/curated_video_frame_extraction.py:1
- Using
indices.remove(frame_number)is O(n) for each iteration. Consider using a set for O(1) removal or removing by index afterrandom.choicereturns the selected element's index.
import os
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| self.cluster_step_widget.setEnabled(False) | ||
| self.frame_cropping_widget.setEnabled(False) | ||
| self.slider_width_widget.setEnabled(True) | ||
| if extraction_method == 'AER-Curated': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The extraction method is registered as "curated" in line 185, but checked as 'AER-Curated' here. This condition will never be true, causing the widget configuration to fail for curated extraction mode.
| if extraction_method == 'AER-Curated': | |
| elif extraction_method == "curated": |
| "Please select exactly one video to extract frames from.", | ||
| ) | ||
| return | ||
| if mode == "AER-Curated": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The extraction method is registered as "curated" in line 185, but checked as "AER-Curated" here. This condition will never be true, preventing the curated extraction dialog from appearing.
| first_video = videos[0] | ||
| if len(videos) > 1: | ||
| self.root.writer.write( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After handling the curated extraction mode, the code continues to line 289 without returning, causing the standard extraction logic to execute even after curated extraction completes. Add a return statement after line 287.
| frames_folder = f"/labeled-data/{video_name}" | ||
| output_image_folder = os.path.dirname(os.path.dirname(video_path)) + frames_folder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using an absolute path with a leading "/" will create the folder at the filesystem root rather than relative to the project. Remove the leading "/" to create the path relative to the video location.
| frames_folder = f"/labeled-data/{video_name}" | |
| output_image_folder = os.path.dirname(os.path.dirname(video_path)) + frames_folder | |
| frames_folder = os.path.join("labeled-data", video_name) | |
| output_image_folder = os.path.join(os.path.dirname(os.path.dirname(video_path)), frames_folder) |
| attempts += 1 | ||
|
|
||
| selected_frames.sort() # Sort frames for readability | ||
| print(f"Selected {len(selected_frames)} frames", "User selected", min_frames) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The print statement concatenates strings without proper formatting. Use an f-string for clarity: print(f"Selected {len(selected_frames)} frames (User requested: {min_frames})")
| print(f"Selected {len(selected_frames)} frames", "User selected", min_frames) | |
| print(f"Selected {len(selected_frames)} frames (User requested: {min_frames})") |
| with open(os.path.join(output_image_folder, "extraction_log.txt"), "a") as f: | ||
| f.write(f"Video: {video_name}\n") | ||
| f.write(f"Video Path: {video_path}\n") | ||
| f.write(f"Frame Rate: {round(frame_rate,0)}\n") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent spacing in function call. Add space after comma: round(frame_rate, 0) to match Python style conventions.
| f.write(f"Frame Rate: {round(frame_rate,0)}\n") | |
| f.write(f"Frame Rate: {round(frame_rate, 0)}\n") |
| else: | ||
| f.write(f"Min Gap: {min_gap_frames} frames\n") | ||
| f.write(f"Extracted Curated Frames: {selected_frames}\n\n") | ||
| f.write("Minimum Frames: {}\n".format(min_frames)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line uses .format() while surrounding lines use f-strings. Use consistent string formatting: f.write(f"Minimum Frames: {min_frames}\n")
| f.write("Minimum Frames: {}\n".format(min_frames)) | |
| f.write(f"Minimum Frames: {min_frames}\n") |
|
Does this need any more work or improvements? LMK |
Curating a specific number of frames using user's chosen start and end time in HH:MM:SS format.
Minimum gap of frames between selected frames either in int # or percentage of the total frames of the video 2% gap.
Introduced a separate number of frames selection using DLCs widget.
Output pushes frames into a similar fashion with a meta-data like file [can be removed if redundant].
curatedFrames for a specific timepoint within a single selected video, using start-end HH:MM:SS format, allowing user to select [for example] behavior specific frames, or only when the mice are visible within a time window.
@AlexEMG