| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -170,6 +170,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy | |||
| 170 | 170 | - [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)) | |
| 171 | 171 | - [How to Concatenate Video Files in Python](https://www.thepythoncode.com/article/concatenate-video-files-in-python). ([code](python-for-multimedia/combine-video)) | |
| 172 | 172 | - [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)) | ||
| 173 | 174 | ||
| 174 | 175 | ||
| 175 | 176 | For any feedback, please consider pulling requests. | |
| Original file line number | Diff line number | Diff 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. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,47 @@ | |||
| 1 | + from moviepy.editor import VideoFileClip | ||
| 2 | + import numpy as np | ||
| 3 | + import os | ||
| 4 | + from datetime import timedelta | ||
| 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 | + def format_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 | + except ValueError: | ||
| 16 | + return result + ".00".replace(":", "-") | ||
| 17 | + ms = int(ms) | ||
| 18 | + ms = round(ms / 1e4) | ||
| 19 | + return f"{result}.{ms:02}".replace(":", "-") | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + def main(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 | + if not os.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.fps if saving_frames_per_second == 0 else 1 / saving_frames_per_second | ||
| 35 | + # iterate over each possible frame | ||
| 36 | + for current_duration in np.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 | + import sys | ||
| 46 | + video_file = sys.argv[1] | ||
| 47 | + main(video_file) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,80 @@ | |||
| 1 | + from datetime import timedelta | ||
| 2 | + import cv2 | ||
| 3 | + import numpy as np | ||
| 4 | + import os | ||
| 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 | + def format_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 | + except ValueError: | ||
| 16 | + return result + ".00".replace(":", "-") | ||
| 17 | + ms = int(ms) | ||
| 18 | + ms = round(ms / 1e4) | ||
| 19 | + return f"{result}.{ms:02}".replace(":", "-") | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + def get_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 | + for i in np.arange(0, clip_duration, 1 / saving_fps): | ||
| 29 | + s.append(i) | ||
| 30 | + return s | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + def main(video_file): | ||
| 34 | + filename, _ = os.path.splitext(video_file) | ||
| 35 | + filename += "-opencv" | ||
| 36 | + # make a folder by the name of the video file | ||
| 37 | + if not os.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 | + while True: | ||
| 50 | + is_read, frame = cap.read() | ||
| 51 | + if not is_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 | + except IndexError: | ||
| 60 | + # the list is empty, all duration frames were saved | ||
| 61 | + break | ||
| 62 | + if frame_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 | + except IndexError: | ||
| 71 | + pass | ||
| 72 | + # increment the frame count | ||
| 73 | + count += 1 | ||
| 74 | + | ||
| 75 | + | ||
| 76 | + | ||
| 77 | + if __name__ == "__main__": | ||
| 78 | + import sys | ||
| 79 | + video_file = sys.argv[1] | ||
| 80 | + main(video_file) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + python-opencv | ||
| 2 | + moviepy | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments