Skip to content

Commit 862d327

Browse files
committed
add extracting frames from video tutorial
1 parent 58258fb commit 862d327

File tree

6 files changed

+134
-0
lines changed

6 files changed

+134
-0
lines changed

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
170170
-[How to Combine a Static Image with Audio in Python](https://www.thepythoncode.com/article/add-static-image-to-audio-in-python). ([code](python-for-multimedia/add-photo-to-audio))
171171
-[How to Concatenate Video Files in Python](https://www.thepythoncode.com/article/concatenate-video-files-in-python). ([code](python-for-multimedia/combine-video))
172172
-[How to Concatenate Audio Files in Python](https://www.thepythoncode.com/article/concatenate-audio-files-in-python). ([code](python-for-multimedia/combine-audio))
173+
-[How to Extract Frames from Video in Python](https://www.thepythoncode.com/article/extract-frames-from-videos-in-python). ([code](python-for-multimedia/extract-frames-from-video))
173174

174175

175176
For any feedback, please consider pulling requests.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# [How to Extract Frames from Video in Python](https://www.thepythoncode.com/article/extract-frames-from-videos-in-python)
2+
To run this:
3+
-`pip3 install -r requirements.txt`
4+
- Use `extract_frames_opencv.py` for using OpenCV to extract frames, or use `extract_frames_moviepy.py` for using MoviePy library.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
frommoviepy.editorimportVideoFileClip
2+
importnumpyasnp
3+
importos
4+
fromdatetimeimporttimedelta
5+
6+
# i.e if video of duration 30 seconds, saves 10 frame per second = 300 frames saved in total
7+
SAVING_FRAMES_PER_SECOND=10
8+
9+
defformat_timedelta(td):
10+
"""Utility function to format timedelta objects in a cool way (e.g 00:00:20.05)
11+
omitting microseconds and retaining milliseconds"""
12+
result=str(td)
13+
try:
14+
result, ms=result.split(".")
15+
exceptValueError:
16+
returnresult+".00".replace(":", "-")
17+
ms=int(ms)
18+
ms=round(ms/1e4)
19+
returnf"{result}.{ms:02}".replace(":", "-")
20+
21+
22+
defmain(video_file):
23+
# load the video clip
24+
video_clip=VideoFileClip(video_file)
25+
# make a folder by the name of the video file
26+
filename, _=os.path.splitext(video_file)
27+
filename+="-moviepy"
28+
ifnotos.path.isdir(filename):
29+
os.mkdir(filename)
30+
31+
# if the SAVING_FRAMES_PER_SECOND is above video FPS, then set it to FPS (as maximum)
32+
saving_frames_per_second=min(video_clip.fps, SAVING_FRAMES_PER_SECOND)
33+
# if SAVING_FRAMES_PER_SECOND is set to 0, step is 1/fps, else 1/SAVING_FRAMES_PER_SECOND
34+
step=1/video_clip.fpsifsaving_frames_per_second==0else1/saving_frames_per_second
35+
# iterate over each possible frame
36+
forcurrent_durationinnp.arange(0, video_clip.duration, step):
37+
# format the file name and save it
38+
frame_duration_formatted=format_timedelta(timedelta(seconds=current_duration)).replace(":", "-")
39+
frame_filename=os.path.join(filename, f"frame{frame_duration_formatted}.jpg")
40+
# save the frame with the current duration
41+
video_clip.save_frame(frame_filename, current_duration)
42+
43+
44+
if__name__=="__main__":
45+
importsys
46+
video_file=sys.argv[1]
47+
main(video_file)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
fromdatetimeimporttimedelta
2+
importcv2
3+
importnumpyasnp
4+
importos
5+
6+
# i.e if video of duration 30 seconds, saves 10 frame per second = 300 frames saved in total
7+
SAVING_FRAMES_PER_SECOND=10
8+
9+
defformat_timedelta(td):
10+
"""Utility function to format timedelta objects in a cool way (e.g 00:00:20.05)
11+
omitting microseconds and retaining milliseconds"""
12+
result=str(td)
13+
try:
14+
result, ms=result.split(".")
15+
exceptValueError:
16+
returnresult+".00".replace(":", "-")
17+
ms=int(ms)
18+
ms=round(ms/1e4)
19+
returnf"{result}.{ms:02}".replace(":", "-")
20+
21+
22+
defget_saving_frames_durations(cap, saving_fps):
23+
"""A function that returns the list of durations where to save the frames"""
24+
s= []
25+
# get the clip duration by dividing number of frames by the number of frames per second
26+
clip_duration=cap.get(cv2.CAP_PROP_FRAME_COUNT) /cap.get(cv2.CAP_PROP_FPS)
27+
# use np.arange() to make floating-point steps
28+
foriinnp.arange(0, clip_duration, 1/saving_fps):
29+
s.append(i)
30+
returns
31+
32+
33+
defmain(video_file):
34+
filename, _=os.path.splitext(video_file)
35+
filename+="-opencv"
36+
# make a folder by the name of the video file
37+
ifnotos.path.isdir(filename):
38+
os.mkdir(filename)
39+
# read the video file
40+
cap=cv2.VideoCapture(video_file)
41+
# get the FPS of the video
42+
fps=cap.get(cv2.CAP_PROP_FPS)
43+
# if the SAVING_FRAMES_PER_SECOND is above video FPS, then set it to FPS (as maximum)
44+
saving_frames_per_second=min(fps, SAVING_FRAMES_PER_SECOND)
45+
# get the list of duration spots to save
46+
saving_frames_durations=get_saving_frames_durations(cap, saving_frames_per_second)
47+
# start the loop
48+
count=0
49+
whileTrue:
50+
is_read, frame=cap.read()
51+
ifnotis_read:
52+
# break out of the loop if there are no frames to read
53+
break
54+
# get the duration by dividing the frame count by the FPS
55+
frame_duration=count/fps
56+
try:
57+
# get the earliest duration to save
58+
closest_duration=saving_frames_durations[0]
59+
exceptIndexError:
60+
# the list is empty, all duration frames were saved
61+
break
62+
ifframe_duration>=closest_duration:
63+
# if closest duration is less than or equals the frame duration,
64+
# then save the frame
65+
frame_duration_formatted=format_timedelta(timedelta(seconds=frame_duration))
66+
cv2.imwrite(os.path.join(filename, f"frame{frame_duration_formatted}.jpg"), frame)
67+
# drop the duration spot from the list, since this duration spot is already saved
68+
try:
69+
saving_frames_durations.pop(0)
70+
exceptIndexError:
71+
pass
72+
# increment the frame count
73+
count+=1
74+
75+
76+
77+
if__name__=="__main__":
78+
importsys
79+
video_file=sys.argv[1]
80+
main(video_file)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
python-opencv
2+
moviepy
719 KB
Binary file not shown.

0 commit comments

Comments
(0)