-
Notifications
You must be signed in to change notification settings - Fork 21
New Tool: Extract frames with CV2 #207
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
Merged
Merged
Changes from 4 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
adf8b71
added new tools to extract frames in cv2
rmassei 876f543
linted the python script
rmassei b9adc6d
corrected import order in the python script
rmassei b3d882f
fix: reduce video resolution to have smaller files
rmassei 9b66e20
Apply suggestions from code review
rmassei 97eb66b
fix: change argument to name in the XML inputs
rmassei 164d215
feature: renamed the folder and convert the tool into a suite
rmassei bbede1d
fix: Revise codec support details in cv2_extract_frames.xml
rmassei 27f675c
refactor: removed old structure
rmassei 2395ca3
fix: corrected the linting error, sheed and xml
rmassei 118fd36
fix: small review fixes, help section plus formatting
rmassei ca749df
fix: standardize the sheed structure
rmassei 4f011e1
fix: add default value to the input parameters
rmassei 3fc1cb3
minor code fixes for better input and error handling
rmassei 1b4a65a
Make `end_time` optional
kostrykin 71f96a9
Merge pull request #1 from kostrykin/dev/cv2_extract_frames
rmassei 2baa016
Add min attribute to start_time parameter
rmassei 905f18e
Fix XML formatting for start_time parameter
rmassei ded5ed4
fix: fixed the format code 'd' error
rmassei 9b3ec26
feature: new test for endtime equal 0 AND negative
rmassei 21b2862
fix: Update XML to use single quotes for command arguments
rmassei 37487fe
Fix quotes in cv2_extract_frames.xml command
rmassei File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| categories: | ||
| - Imaging | ||
| description: Extract frames from .MP4 and .AVI | ||
| long_description: This tools extract a user defined range of frames from an .MP4 or .AVI file and convert them to .TIFF files for further downstream analysis | ||
| name: extract_frames | ||
| owner: ufz | ||
|
rmassei marked this conversation as resolved.
Outdated
|
||
| homepage_url: https://github.com/bmcv | ||
|
rmassei marked this conversation as resolved.
Outdated
|
||
| remote_repository_url: https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/extract_frames | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../macros/creators.xml |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import argparse | ||
| import os | ||
| from pathlib import Path | ||
| from typing import Union | ||
|
|
||
| import cv2 | ||
|
|
||
|
|
||
| def extract_frames(output_dir: Union[str, Path], video_path: Union[str, Path], start_time: int, end_time: int, convert_to_grey: str = "false") -> Path: | ||
| """ | ||
| Extract frames from a video within a specified time range in seconds | ||
|
|
||
| Parameters | ||
| ---------- | ||
| video_path: Path to the input video file | ||
|
|
||
| start_time: Start time in seconds | ||
|
|
||
| end_time: End time in seconds | ||
|
|
||
| output_dir: Directory where extracted frames will be saved | ||
|
|
||
| convert_to_gray: Whether to convert frames to grayscale | ||
|
|
||
| Returns: | ||
| --------- | ||
| Path to the directory containing the extracted frames. | ||
| """ | ||
|
|
||
| try: | ||
| video = cv2.VideoCapture(video_path) | ||
|
|
||
| # get the video frames per second | ||
| fps = video.get(cv2.CAP_PROP_FPS) | ||
| print('Frames per second:', fps) | ||
| # get the video total frames | ||
| frame_count = video.get(cv2.CAP_PROP_FRAME_COUNT) | ||
| print('Total frames:', frame_count) | ||
|
|
||
| start_frame = int(start_time * fps) | ||
| end_frame = int(end_time * fps) | ||
| print(f'Starting extracting from frame {start_frame} until {end_frame}...') | ||
|
|
||
| video.set(cv2.CAP_PROP_POS_FRAMES, start_frame) | ||
| current_frame = start_frame | ||
|
|
||
| while current_frame <= end_frame: | ||
| ret, frame = video.read() | ||
| if not ret: | ||
| break | ||
|
|
||
| # Convert to single-channel grayscale | ||
| output_path = os.path.join(output_dir, f"frame_{current_frame:05d}.tiff") | ||
| if convert_to_grey == "true": | ||
| cv2.imwrite(output_path, cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY), [cv2.IMWRITE_TIFF_COMPRESSION, 1]) | ||
| else: | ||
| cv2.imwrite(output_path, frame, [cv2.IMWRITE_TIFF_COMPRESSION, 1]) | ||
| current_frame += 1 | ||
|
|
||
| video.release() | ||
|
|
||
| print('Extraction was successfully executed. Enjoy your frames.') | ||
|
|
||
| except IOError: | ||
| print("Cannot open video file") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| parser = argparse.ArgumentParser(description="Extract frames from video files") | ||
| parser.add_argument('output_dir', help="Name of the output folder") | ||
| parser.add_argument('-v', '--video_path', required=True, help="Path to the video to convert") | ||
| parser.add_argument('-s', '--start_time', required=True, type=float, help="Start time in seconds") | ||
| parser.add_argument('-e', '--end_time', required=True, type=float, help="End time in seconds") | ||
| parser.add_argument('-c', '--convert_to_grey', required=False, type=str, help="Convert the file to grayscale") | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| extract_frames(args.output_dir, video_path=args.video_path, start_time=args.start_time, end_time=args.end_time, convert_to_grey=args.convert_to_grey) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| <tool id="extract_frames" name="Extract video frames" version="@TOOL_VERSION@+galaxy@VERSION_SUFFIX@" profile="21.05"> | ||
|
rmassei marked this conversation as resolved.
Outdated
|
||
| <description>with cv2</description> | ||
| <macros> | ||
| <token name="@TOOL_VERSION@">0.1</token> | ||
|
rmassei marked this conversation as resolved.
Outdated
|
||
| <token name="@VERSION_SUFFIX@">1</token> | ||
|
rmassei marked this conversation as resolved.
Outdated
|
||
| <import>tests.xml</import> | ||
| <import>creators.xml</import> | ||
| </macros> | ||
| <creator> | ||
| <expand macro="creators/rmassei"/> | ||
| </creator> | ||
| <requirements> | ||
| <requirement type="package" version="4.13.0">opencv</requirement> | ||
| </requirements> | ||
| <command detect_errors="aggressive"> | ||
| <![CDATA[ | ||
| mkdir ./output_frames && | ||
|
|
||
| python "$__tool_directory__/cv2_extract_frames.py" output_frames | ||
| -v $video_path | ||
| -s $start_time | ||
| -e $end_time | ||
| -c $convert_to_grey | ||
|
|
||
| && ls -l ./output_frames | ||
| ]]> | ||
| </command> | ||
| <inputs> | ||
| <param argument="video_path" type="data" optional="False" format="mp4,avi" label="Input video to convert" help="Path to the video to convert"/> | ||
|
rmassei marked this conversation as resolved.
Outdated
|
||
| <param argument="start_time" type="float" optional="False" label="Start time (seconds)" help="Start time in seconds"/> | ||
| <param argument="end_time" type="float" optional="False" label="End time (seconds)" help="End time in seconds"/> | ||
| <param argument="convert_to_grey" type="boolean" label="Convert output to grayscale?" help="Convert the file to grayscale"/> | ||
|
rmassei marked this conversation as resolved.
Outdated
rmassei marked this conversation as resolved.
Outdated
|
||
| </inputs> | ||
| <outputs> | ||
| <collection name="frames" type="list" label="Output frames"> | ||
| <discover_datasets directory="output_frames" format="tiff" pattern="__name__"/> | ||
| </collection> | ||
| </outputs> | ||
| <tests> | ||
| <test> | ||
| <!-- test MP4 w/o grayscale conversion --> | ||
| <param name="video_path" value="input1.mp4"/> | ||
| <param name="start_time" value="0"/> | ||
| <param name="end_time" value="1"/> | ||
| <param name="convert_to_grey" value="False"/> | ||
| <output_collection name="frames" type="list"> | ||
| <expand macro="tests/intensity_image_diff/element" name="frame_00001.tiff" value="frame_00001.tiff" ftype="tiff"/> | ||
| <expand macro="tests/intensity_image_diff/element" name="frame_00002.tiff" value="frame_00002.tiff" ftype="tiff"/> | ||
| </output_collection> | ||
| </test> | ||
| <test> | ||
| <!-- test MP4 w grayscale conversion --> | ||
| <param name="video_path" value="input1.mp4"/> | ||
| <param name="start_time" value="0"/> | ||
| <param name="end_time" value="1"/> | ||
| <param name="convert_to_grey" value="True"/> | ||
| <output_collection name="frames" type="list"> | ||
| <expand macro="tests/intensity_image_diff/element" name="frame_00003.tiff" value="frame_00003.tiff" ftype="tiff"/> | ||
| <expand macro="tests/intensity_image_diff/element" name="frame_00004.tiff" value="frame_00004.tiff" ftype="tiff"/> | ||
| </output_collection> | ||
| </test> | ||
| <test> | ||
| <!-- test AVI w/o grayscale conversion --> | ||
| <param name="video_path" value="input2.avi"/> | ||
| <param name="start_time" value="0"/> | ||
| <param name="end_time" value="1"/> | ||
| <param name="convert_to_grey" value="False"/> | ||
| <output_collection name="frames" type="list"> | ||
| <expand macro="tests/intensity_image_diff/element" name="frame_00005.tiff" value="frame_00005.tiff" ftype="tiff"/> | ||
| <expand macro="tests/intensity_image_diff/element" name="frame_00006.tiff" value="frame_00006.tiff" ftype="tiff"/> | ||
| </output_collection> | ||
| </test> | ||
| <test> | ||
| <!-- test AVI w grayscale conversion --> | ||
| <param name="video_path" value="input2.avi"/> | ||
| <param name="start_time" value="0"/> | ||
| <param name="end_time" value="1"/> | ||
| <param name="convert_to_grey" value="True"/> | ||
| <output_collection name="frames" type="list"> | ||
| <expand macro="tests/intensity_image_diff/element" name="frame_00007.tiff" value="frame_00007.tiff" ftype="tiff"/> | ||
| <expand macro="tests/intensity_image_diff/element" name="frame_00008.tiff" value="frame_00008.tiff" ftype="tiff"/> | ||
| </output_collection> | ||
| </test> | ||
| </tests> | ||
| <help> | ||
|
|
||
| **Extract single frames as TIFFs from MP4 and AVI files** | ||
|
rmassei marked this conversation as resolved.
Outdated
|
||
|
|
||
| Frames captured within a specified time interval (in seconds) will be extracted from the video file as individual TIFF images. | ||
| Optionally, the extracted frames can be converted to grayscale. | ||
|
|
||
| **Codecs Support:** The library OpenCV's cv2 supports various video codecs including MPEG1, MPEG2, MPEG4, H264, HEVC, VP8, VP9, and more. Check | ||
|
rmassei marked this conversation as resolved.
Outdated
|
||
| the documentation for more information on the supported codecs. | ||
|
|
||
| </help> | ||
| <citations> | ||
| <citation type="bibtex">@article{opencv_library, | ||
| author = {Bradski, G.}, | ||
| citeulike-article-id = {2236121}, | ||
| journal = {Dr. Dobb's Journal of Software Tools}, | ||
| keywords = {bibtex-import}, | ||
| posted-at = {2008-01-15 19:21:54}, | ||
| priority = {4}, | ||
| title = {{The OpenCV Library}}, | ||
| year = {2000} | ||
| }</citation> | ||
| </citations> | ||
| </tool> | ||
|
|
||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ../../macros/tests.xml |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.