-
يكشنبه, ۳۰ آبان ۱۴۰۰، ۰۴:۴۸ ب.ظ
-
۱۰۷۳
سلام دوستان :)
توی پست امروز قراره با هم نحوه ساخت یک اسکریپت پایتونی که فریم های ویدیو رو استخراج می کنه ببینیم.
برای این کار ما قراره از دو روش استفاده کنیم:
- استخراج کردن فریم ها با استفاده از opencv.
- استخراج کردن فریم ها با استفاده از moviepy.
پس قبل از اینکه بخوایم هر کاری انجام بدیم بریم کتابخونه هایی که نیاز داریم رو نصب کنیم.
برای نصب کتابخونه ها در ویندوز وارد cmd بشین و دستور زیر رو وارد کنین:
pip install opencv-python moviepy numpy
برای نصب کتابخونه ها در لینوکس یا مک هم وارد terminal بشین و دستور زیر رو وارد کنین:
sudo pip3 install opencv-python moviepy numpy
خب حالا که همه چی آمادست بریم کارمون رو شروع کنیم :)
1-روش اول: استخراج کردن frame های ویدیو با استفاده از opencv:
خب همونطور که میدونین opencv یک کتابخونه بسیار گسترده هست که کار های خیلی زیادی میشه باهاش انجام داد. اما ما توی این پست از بخش کوچیکی از این کتابخونه استفاده می کنیم.
برای شروع کار یک سورس پایتون درست کنین و کد های زیر رو داخلش قرار بدین:
from datetime import timedelta import cv2 import numpy as np import os # i.e if video of duration 30 seconds, saves 10 frame per second = 300 frames saved in total SAVING_FRAMES_PER_SECOND = 10 def format_timedelta(td): """Utility function to format timedelta objects in a cool way (e.g 00:00:20.05) omitting microseconds and retaining milliseconds""" result = str(td) try: result, ms = result.split(".") except ValueError: return result + ".00".replace(":", "-") ms = int(ms) ms = round(ms / 1e4) return f"{result}.{ms:02}".replace(":", "-") def get_saving_frames_durations(cap, saving_fps): """A function that returns the list of durations where to save the frames""" s = [] # get the clip duration by dividing number of frames by the number of frames per second clip_duration = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS) # use np.arange() to make floating-point steps for i in np.arange(0, clip_duration, 1 / saving_fps): s.append(i) return s def main(video_file): filename, _ = os.path.splitext(video_file) filename += "-opencv" # make a folder by the name of the video file if not os.path.isdir(filename): os.mkdir(filename) # read the video file cap = cv2.VideoCapture(video_file) # get the FPS of the video fps = cap.get(cv2.CAP_PROP_FPS) # if the SAVING_FRAMES_PER_SECOND is above video FPS, then set it to FPS (as maximum) saving_frames_per_second = min(fps, SAVING_FRAMES_PER_SECOND) # get the list of duration spots to save saving_frames_durations = get_saving_frames_durations(cap, saving_frames_per_second) # start the loop count = 0 while True: is_read, frame = cap.read() if not is_read: # break out of the loop if there are no frames to read break # get the duration by dividing the frame count by the FPS frame_duration = count / fps try: # get the earliest duration to save closest_duration = saving_frames_durations[0] except IndexError: # the list is empty, all duration frames were saved break if frame_duration >= closest_duration: # if closest duration is less than or equals the frame duration, # then save the frame frame_duration_formatted = format_timedelta(timedelta(seconds=frame_duration)) cv2.imwrite(os.path.join(filename, f"frame{frame_duration_formatted}.jpg"), frame) # drop the duration spot from the list, since this duration spot is already saved try: saving_frames_durations.pop(0) except IndexError: pass # increment the frame count count += 1 if __name__ == "__main__": import sys video_file = sys.argv[1] main(video_file)
توضیح: خب اول کتابخونه های مورد نیازمون رو import کردیم،
بعد یک متغیر به نام SAVING_FRAMES_PER_SECOND تعریف کردیم که مشخص میکنه که در هر ثانیه چند تا فریم ذخیره کنه،شما میتونین این مقدار رو به مقدار دلخواه خودتون تغییر بدین.
بعدش یک تابع تعریف کردیم که خیلی نقش مهمی توی برناممون نداره و تنها کاری که انجام میده خوشگل کردن فرمت تایم هست :))
تابع بعدی هم یک لیست به ما بر می گردونه که هر فریم در زمان مشخص شده داخلش ذخیره شده.
خب حالا رسیدیم به تابع main که کار اصلی رو انجام میده و تمام فریم ها رو بیرون میکشه و تو یک فولدر با اسم خود ویدیو ذخیره میکنه.
خب برای اجرا وارد cmd یا terminal بشین و اول وارد مسیر ویدیوتون بشین و بعد دستور زیر رو وارد کنین:
python {name}.py {videoname}
بجای name باید اسم اسکریپت پایتونتون رو وارد کنین و بجای videoname باید اسم ویدیویی که میخواین فریم هاشو استخراج کنین وارد کنین.
خب این روش opencv بود.
بریم سراغ روش دوم یعنی استخراج از طریق moviepy.
2-روش دوم: استخراج کردن frame های ویدیو با استفاده از moviepy:
خب moviepy هم یک کتابخونه مثل opencv هست اما با امکانات خیلی کمتر،ولی فعلا کار ما رو راه میندازه :))) پس بریم شروع کنیم :)
خب برای شروع یک سورس پایتون درست کنین و کد زیر رو داخلش قرار بدین:
from moviepy.editor import VideoFileClip import numpy as np import os from datetime import timedelta # i.e if video of duration 30 seconds, saves 10 frame per second = 300 frames saved in total SAVING_FRAMES_PER_SECOND = 10 def format_timedelta(td): """Utility function to format timedelta objects in a cool way (e.g 00:00:20.05) omitting microseconds and retaining milliseconds""" result = str(td) try: result, ms = result.split(".") except ValueError: return result + ".00".replace(":", "-") ms = int(ms) ms = round(ms / 1e4) return f"{result}.{ms:02}".replace(":", "-") def main(video_file): # load the video clip video_clip = VideoFileClip(video_file) # make a folder by the name of the video file filename, _ = os.path.splitext(video_file) filename += "-moviepy" if not os.path.isdir(filename): os.mkdir(filename) # if the SAVING_FRAMES_PER_SECOND is above video FPS, then set it to FPS (as maximum) saving_frames_per_second = min(video_clip.fps, SAVING_FRAMES_PER_SECOND) # if SAVING_FRAMES_PER_SECOND is set to 0, step is 1/fps, else 1/SAVING_FRAMES_PER_SECOND step = 1 / video_clip.fps if saving_frames_per_second == 0 else 1 / saving_frames_per_second # iterate over each possible frame for current_duration in np.arange(0, video_clip.duration, step): # format the file name and save it frame_duration_formatted = format_timedelta(timedelta(seconds=current_duration)).replace(":", "-") frame_filename = os.path.join(filename, f"frame{frame_duration_formatted}.jpg") # save the frame with the current duration video_clip.save_frame(frame_filename, current_duration) if __name__ == "__main__": import sys video_file = sys.argv[1] main(video_file)
توضیح: خب اول کتابخونه های مورد نیازمون رو import کردیم.
بعدش متغیر و تابع بعدی تکراریه و بالا هم تعریفشون کردیم.
توی بخش main هم گفتیم که یک ورودی video از ما بگیره و فریم هاشو استخراج کنه.
توی چند خط آخر هم گفتیم که مقدار ورودی video رو بگیره و تابع main رو روش اجرا کردیم.
روش اجرا کردن این کد هم به صورت همون کد بالایی هست.
خب همونطور که احتمالا متوجه شدین کد های روش دوم کمتره. ولی بجاش سرعت opencv از moviepy بیشتره. اگر بخواین برای video های طولانی و با حجم زیاد این اسکریپت رو استفاده کنین بهتون توصیه میکنم که از کتابخونه opencv استفاده کنین، ولی اگر میخواین برای ویدیو های کوتاه اینکار رو انجام بدین بهتره که از روش دوم یعنی moviepy استفاده کنین چون کد هایی که توی اسکریپت استفاده میشه کمتره و برای استفاده روی ویدیو های کم حجم و سبک بهتره.
امیدوارم براتون مفید بوده باشه D: