以较低的帧频解析视频

时间:2018-11-02 20:14:50

标签: python opencv computer-vision video-processing

我目前正在一个项目中,我需要解析视频并将其传递给多个模型。视频以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()

任何有关如何以最有效的方式实现这一目标的建议将不胜感激。

3 个答案:

答案 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