我目前正在一个项目中,我需要解析视频并将其传递给多个模型。视频以60fps的速度播放。我不需要遍历模型的每一帧。尝试跳过不需要的帧时遇到了一些问题。我尝试了两种都很慢的方法。
方法1的代码段: 这里的问题是我仍在阅读视频的每一帧。我的模型仅运行第4帧。
cap = cv2.VideoCapture(self.video)
while cap.isOpened():
success, frame = cap.read()
if count % 4 !=0:
count += 1
continue
if success:
''Run frame through models''
else:
break
方法2的代码段: 这种方法比较慢。在这种情况下,我试图避免读取不必要的帧。
cap = cv2.VideoCapture(video)
count=0
while True:
if count % 4 != 0:
cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15)
count+=1
success, frame = cap.read()
任何有关如何以最有效的方式实现这一目标的建议将不胜感激。
答案 0 :(得分:1)
由于视频压缩的工作原理,使用关键帧,因此更改CV_CAP_PROP_POS_FRAMES来获取和设置帧是不准确(且缓慢)的。
完全不使用read()函数可能会有所帮助。而是使用grab(),仅检索()所需的帧。在documentation中:(读取)方法/函数在一次调用中将VideoCapture :: grab()和VideoCapture :: retrieve()组合在一起。
grab()获取帧数据,然后retrieve()对其进行解码(计算量很大)。您可能只想抓取要跳过的帧,而不要检索它们。
根据您的系统和opencv构建,您还可以使用硬件加速功能使ffmpeg解码视频。
答案 1 :(得分:0)
当我得到它时,您正在尝试处理每四个帧。您正在使用以下条件:
if count % 4 != 0
这将触发4帧中的3帧(您正在处理1、2、3、5、6、7等帧)!使用相反的方法:
if count % 4 == 0
尽管代码片段中,这两种方法似乎不能处理相同的帧。尽管在这两种情况下,您的计数器似乎每帧都增加1,但实际上在第二种情况下,您指向该计数器的15x帧(cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15)
。
您的代码上也有一些注释(也许我误解了):
情况1:
while cap.isOpened():
success, frame = cap.read()
if count % 4 !=0:
count += 1
continue
在这里,您似乎只算了几帧(如上所述,四分之三),因为跳过了4的倍数的帧:在这种情况下,不满足条件count % 4 !=0
并且计数器不会更新,尽管您已阅读一个框架。因此,您这里的计数器不正确。虽然未显示如何以及在何处处理帧以判断该部分。
情况2:
while True:
if count % 4 != 0:
cap.set(cv2.CV_CAP_PROP_POS_FRAMES, count*15)
count+=1
success, frame = cap.read()
这里仅在满足条件时才读取帧,因此在此代码段中,由于第0帧不会触发条件,因此您实际上不会读取任何帧!如果您在if范围之外更新计数器,则此处不清楚。但是,如果您这样做,也应该在那里阅读框架。无论如何,应该透露更多代码。
作为一般建议,每次阅读框架时都应更新计数器。
答案 2 :(得分:0)
与其为帧数设置阈值,不如使opencv处理所有帧(您正确指出,这会减慢视频处理速度),最好使用CAP_PROP_POS_MSEC
link并卸载处理到cv2
。通过使用此选项,您可以将cv2
配置为每n毫秒采样1帧。因此,在subsample_rate=1000
中设置vidcap.set(cv2.CAP_PROP_POS_MSEC, (frame_count * subsample_rate))
将每1秒采样1帧(因为1000毫秒等于1秒)。希望这可以提高您的视频处理速度。
def extractImagesFromVideo(path_in, subsample_rate, path_out, saveImage, resize=(), debug=False):
vidcap = cv2.VideoCapture(path_in)
if not vidcap.isOpened():
raise IOError
if debug:
length = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_COUNT))
width = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_WIDTH))
height = int(vidcap.get(cv2.cv2.CAP_PROP_FRAME_HEIGHT))
fps = vidcap.get(cv2.cv2.CAP_PROP_FPS)
print 'Length: %.2f | Width: %.2f | Height: %.2f | Fps: %.2f' % (length, width, height, fps)
success, image = vidcap.read() #extract first frame.
frame_count = 0
while success:
vidcap.set(cv2.CAP_PROP_POS_MSEC, (frame_count*subsample_rate))
success, image = vidcap.read()
if saveImage and np.any(image):
cv2.imwrite(os.path.join(path_out, "%s_%d.png" % (frame_count)), image)
frame_count = frame_count + 1
return frame_count