如何在python中使用cv2知道文件中帧的总数


77

如何使用Open CV模块通过Python知道文件(.avi)中帧的总数。

如果可能的话,我们可以通过它获得视频文件的所有信息(分辨率,fps,持续时间等)。

Answers:


114

使用较新的OpenCV版本(我使用3.1.0)时,其工作方式如下:

import cv2

cap = cv2.VideoCapture("video.mp4")
length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
print( length )

与其他视频属性类似 cv2.CAP_PROP_*


3
“模块”对象没有属性“ CAP_PROP_FRAME_COUNT”
约翰·ktejik

1
您确定使用的是OpenCV 3+版本吗?我刚刚使用3.3.1版进行了测试,但仍然可以使用。
phev8

任何想法的复杂性是cap.get()什么?

我刚刚进行了测试,对我来说,它也可以使用.avi视频文件。现在,我在Ubuntu 18.04计算机上使用4.0.1-dev版本。您确定视频文件没有损坏吗?
phev8

或如此处其他评论者所暗示的,这取决于您的avi容器中的内容...显然,有时它不可用-您可以尝试为视频文件使用其他编码器。
phev8

40
import cv2

cap = cv2.VideoCapture(fn)

if not cap.isOpened(): 
    print "could not open :",fn
    return

length = int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT))
width  = int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT))
fps    = cap.get(cv2.cv.CV_CAP_PROP_FPS)

有关更多信息,请参见此处

而且,所有这些都带有一粒盐,并不是所有这些道具都是强制性的,有些可能在您的捕获/视频编解码器中不可用


1
CAP_PROP_FRAME_COUNT给出0个值,这是代码导入cv2#--编码:utf-8 --filename =“ test.avi” cap = cv2.VideoCapture(文件名)fps = cap.get(cv2.cv.CV_CAP_PROP_FPS)打印'fps ='+ str(fps)Frames = cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT)print'Frames ='+ str(Frames)您能告诉我我做错了什么吗?
尼拉吉

您可能没有做错任何事情。同样,avi只是一个容器,其中可能有任何东西,并且某些编解码器只是不支持查询某些属性。
2014年

嗨,您好,抱歉,重播已晚,请您给我更多提示。
Niraj 2014年

12

这是它与Python 3.6.5(在Anaconda上)和OpenCV 3.4.2一起工作的方式。[注意]:对于OpenCV官方网站上提供的任何属性,您需要从“ CV_CAP_PROP_xx”中删除“ CV_” 。

import cv2
cap = cv2.VideoCapture("video.mp4")
property_id = int(cv2.CAP_PROP_FRAME_COUNT) 
length = int(cv2.VideoCapture.get(cap, property_id))
print( length )

2
这很棒!您也可以使用length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
Scratch'N'Purr

9

有两种方法可以确定视频文件中的帧数

  • 方法#1:利用内置的OpenCV属性访问视频文件元信息,该信息快速,高效但不准确
  • 方法2:使用慢速,低效但准确的计数器手动循环播放视频文件中的每个帧

方法1速度很快,并且依赖于OpenCV的视频属性功能,该功能几乎可以瞬间确定视频文件中的帧数。但是,由于它取决于您的OpenCV和视频编解码器版本,因此需要进行精度折衷。另一方面,手动计数每个帧的准确率将达到100%,尽管会慢很多。这是一个默认情况下尝试执行方法1的函数,如果失败,它将自动利用方法2

def frame_count(video_path, manual=False):
    def manual_count(handler):
        frames = 0
        while True:
            status, frame = handler.read()
            if not status:
                break
            frames += 1
        return frames 

    cap = cv2.VideoCapture(video_path)
    # Slow, inefficient but 100% accurate method 
    if manual:
        frames = manual_count(cap)
    # Fast, efficient but inaccurate method
    else:
        try:
            frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        except:
            frames = manual_count(cap)
    cap.release()
    return frames

基准测试

if __name__ == '__main__':
    import timeit
    import cv2

    start = timeit.default_timer()
    print('frames:', frame_count('fedex.mp4', manual=False))
    print(timeit.default_timer() - start, '(s)')

    start = timeit.default_timer()
    print('frames:', frame_count('fedex.mp4', manual=True))
    print(timeit.default_timer() - start, '(s)')

方法1的结果

frames: 3671
0.018054921 (s)

方法2的结果

frames: 3521
9.447095287 (s)

请注意,这两种方法相差150帧,并且方法#2比方法#1慢得多。因此,如果您需要速度但又愿意牺牲精度,请使用方法1。如果您可以延迟但需要准确的帧数,请使用方法2


4

另一个不依赖有时会发生错误的CV_CAP_PROP吸气剂的解决方案是循环遍历整个视频文件

  • 每次遇到有效帧时增加一个帧计数器变量,并在出现无效帧时停止(视频文件结尾)。
  • 收集有关分辨率的信息比较棘手,因为某些编解码器支持可变分辨率(类似于音频文件中的VBR,其中比特率不是恒定的,而是覆盖了一些预定义的范围)。

    • 恒定的分辨率-在这种情况下,您只需要第一帧即可确定整个视频文件的分辨率,因此不需要遍历整个视频
    • 可变分辨率-您需要获取每帧的分辨率(宽度和高度),并计算平均值才能获得视频的平均分辨率
  • 可以计算FPS,但是这里您遇到与分辨率相同的问题-常数(CFR)与变量(VFR)。这更多是一个多线程问题。我个人将使用帧计数器,该帧计数器在每个有效帧之后增加,而每隔1秒(在后台线程中运行),计时器将触发保存当前计数器的值,然后将其重置。您可以将值存储在列表中,以便在最后还知道视频具有的总帧数时计算平均/恒定帧速率。

这种相当简单的处理方式的缺点在于,您必须遍历整个文件,如果文件长达数小时,则肯定会引起用户注意。在这种情况下,您可以对此有所了解,并在后台过程中做到这一点,同时让您的应用程序在收集有关已加载视频文件的信息时让用户执行其他操作。

优点是,无论您拥有什么视频文件,只要OpenCV可以读取它,您都将获得非常准确的结果,CV_CAP_PROP这与您预期的效果可能不一样。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.