在不下载视频的情况下提取 youtube 视频的特定帧
Extract specific frames of youtube video without downloading video
我需要提取在线视频的特定帧 来处理算法,但我不想下载整个视频,因为那样会非常低效。
首先,我尝试使用 YouTube 视频。我可以这样使用 youtube-dl
下载整个视频:
ydl_opts = {'outtmpl': r'OUTPUT_DIRECTORY_HERE',}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download([url])
然后我可以捕捉单独的帧。
我需要避免下载整个视频。经过一些研究,我发现 ffmpeg
可能会帮助我做到这一点。我发现无法只下载帧,所以如果这不可能,第二种选择是我可以下载视频的特定部分。 linux 中的一个这样的例子是 here 但我找不到 python 的任何解决方案。
只下载帧或部分视频(在 python 中)而不下载整个内容的好方法是什么?
我尝试了 @AyeshaKhan 在评论中分享的内容。
导入后cv2
,numpy
,youtube-dl
:
url=saved_url #The Youtube URL
ydl_opts={}
ydl=youtube_dl.YoutubeDL(ydl_opts)
info_dict=ydl.extract_info(video_url, download=False)
formats = info_dict.get('formats',None)
print("Obtaining frames")
for f in formats:
if f.get('format_note',None) == '144p':
url = f.get('url',None)
cap = cv2.VideoCapture(url)
x=0
count=0
while x<10:
ret, frame = cap.read()
if not ret:
break
filename =r"PATH\shot"+str(x)+".png"
x+=1
cv2.imwrite(filename.format(count), frame)
count+=300 #Skip 300 frames i.e. 10 seconds for 30 fps
cap.set(1,count)
if cv2.waitKey(30)&0xFF == ord('q'):
break
cap.release()
评论中的答案是下载所有帧,所以我在 .format()
中添加的 count
确保我按照我的要求跳过了帧。
另外,x
这里限制人数为10人。
尽管如此,我仍然不确定此方法是否实际捕获了指定的帧,或者它是否捕获了所有帧并将指定的帧保存到我的本地存储中。我需要前者。
但这仍然足够快并且适合我!
只是为了补充当前的答案,使用多处理可以进一步提高性能。例如,如果您想将视频拆分成帧并在 num_cpu 进程中独立处理它们:
import os
from functools import partial
from multiprocessing.pool import Pool
import cv2
import youtube_dl
def process_video_parallel(url, skip_frames, process_number):
cap = cv2.VideoCapture(url)
num_processes = os.cpu_count()
frames_per_process = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) // num_processes
cap.set(cv2.CAP_PROP_POS_FRAMES, frames_per_process * process_number)
x = 0
count = 0
while x < 10 and count < frames_per_process:
ret, frame = cap.read()
if not ret:
break
filename =r"PATH\shot"+str(x)+".png"
x += 1
cv2.imwrite(filename.format(count), frame)
count += skip_frames # Skip 300 frames i.e. 10 seconds for 30 fps
cap.set(1, count)
cap.release()
video_url = "..." # The Youtube URL
ydl_opts = {}
ydl = youtube_dl.YoutubeDL(ydl_opts)
info_dict = ydl.extract_info(video_url, download=False)
formats = info_dict.get('formats', None)
print("Obtaining frames")
for f in formats:
if f.get('format_note', None) == '144p':
url = f.get('url', None)
cpu_count = os.cpu_count()
with Pool(cpu_count) as pool:
pool.map(partial(process_video_parallel, url, 300), range(cpu_count))
出于此应用程序的目的,由于只是从视频中保存图像,因此这可能不会带来巨大的改进(可能几秒钟),但如果需要在帧上应用其他算法,它可能是有益的。
我需要提取在线视频的特定帧 来处理算法,但我不想下载整个视频,因为那样会非常低效。
首先,我尝试使用 YouTube 视频。我可以这样使用 youtube-dl
下载整个视频:
ydl_opts = {'outtmpl': r'OUTPUT_DIRECTORY_HERE',}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download([url])
然后我可以捕捉单独的帧。
我需要避免下载整个视频。经过一些研究,我发现 ffmpeg
可能会帮助我做到这一点。我发现无法只下载帧,所以如果这不可能,第二种选择是我可以下载视频的特定部分。 linux 中的一个这样的例子是 here 但我找不到 python 的任何解决方案。
只下载帧或部分视频(在 python 中)而不下载整个内容的好方法是什么?
我尝试了 @AyeshaKhan 在评论中分享的内容。
导入后cv2
,numpy
,youtube-dl
:
url=saved_url #The Youtube URL
ydl_opts={}
ydl=youtube_dl.YoutubeDL(ydl_opts)
info_dict=ydl.extract_info(video_url, download=False)
formats = info_dict.get('formats',None)
print("Obtaining frames")
for f in formats:
if f.get('format_note',None) == '144p':
url = f.get('url',None)
cap = cv2.VideoCapture(url)
x=0
count=0
while x<10:
ret, frame = cap.read()
if not ret:
break
filename =r"PATH\shot"+str(x)+".png"
x+=1
cv2.imwrite(filename.format(count), frame)
count+=300 #Skip 300 frames i.e. 10 seconds for 30 fps
cap.set(1,count)
if cv2.waitKey(30)&0xFF == ord('q'):
break
cap.release()
评论中的答案是下载所有帧,所以我在 .format()
中添加的 count
确保我按照我的要求跳过了帧。
另外,x
这里限制人数为10人。
尽管如此,我仍然不确定此方法是否实际捕获了指定的帧,或者它是否捕获了所有帧并将指定的帧保存到我的本地存储中。我需要前者。
但这仍然足够快并且适合我!
只是为了补充当前的答案,使用多处理可以进一步提高性能。例如,如果您想将视频拆分成帧并在 num_cpu 进程中独立处理它们:
import os
from functools import partial
from multiprocessing.pool import Pool
import cv2
import youtube_dl
def process_video_parallel(url, skip_frames, process_number):
cap = cv2.VideoCapture(url)
num_processes = os.cpu_count()
frames_per_process = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) // num_processes
cap.set(cv2.CAP_PROP_POS_FRAMES, frames_per_process * process_number)
x = 0
count = 0
while x < 10 and count < frames_per_process:
ret, frame = cap.read()
if not ret:
break
filename =r"PATH\shot"+str(x)+".png"
x += 1
cv2.imwrite(filename.format(count), frame)
count += skip_frames # Skip 300 frames i.e. 10 seconds for 30 fps
cap.set(1, count)
cap.release()
video_url = "..." # The Youtube URL
ydl_opts = {}
ydl = youtube_dl.YoutubeDL(ydl_opts)
info_dict = ydl.extract_info(video_url, download=False)
formats = info_dict.get('formats', None)
print("Obtaining frames")
for f in formats:
if f.get('format_note', None) == '144p':
url = f.get('url', None)
cpu_count = os.cpu_count()
with Pool(cpu_count) as pool:
pool.map(partial(process_video_parallel, url, 300), range(cpu_count))
出于此应用程序的目的,由于只是从视频中保存图像,因此这可能不会带来巨大的改进(可能几秒钟),但如果需要在帧上应用其他算法,它可能是有益的。