如何使用Python中的cv2知道文件中帧的总数?

111

如何使用Python和OpenCV模块来确定文件(.avi)中帧的总数。

如果可能的话,我们可以通过此方法获取哪些视频文件信息(分辨率、fps、持续时间等)。

5个回答

182

使用更新的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
“module”对象没有属性“CAP_PROP_FRAME_COUNT”。 - john k
1
你确定你在使用OpenCV版本3+吗?我刚刚测试了版本3.3.1仍然可以工作。 - phev8
1
你知道 cap.get() 的复杂度是多少吗? - user5586747
我刚刚测试了一下,对我来说它也可以使用.avi视频文件。现在我正在使用Ubuntu 18.04机器上的4.0.1-dev版本。你确定你的视频文件没有损坏吗? - phev8
或者正如其他评论者所暗示的那样,这取决于您的AVI容器中包含了什么... 显然,有时它并不可用 - 您可以尝试使用一些不同的编码器来处理您的视频文件。 - phev8

54
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

-- coding: utf-8 --

文件名=“test.avi” cap = cv2.VideoCapture(filename) fps = cap.get(cv2.cv.CV_CAP_PROP_FPS) print 'fps='+str(fps) Frames = cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT) print 'Frames='+str(Frames) 请问我哪里出错了?
- Niraj
你可能没有做错任何事情。再说,AVI只是一个容器,里面可能有任何东西,而且一些编解码器不支持查询某些属性。 - berak
嗨,berak,抱歉回复晚了,你能否给我更多的提示呢? - Niraj

21

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

  • 方法 #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)')

第一种方法的结果

frames: 3671
0.018054921 (s)

第二种方法的结果

frames: 3521
9.447095287 (s)

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


17

以下是Python 3.6.5(在Anaconda上)和OpenCV 3.4.2的操作方式。 [注意]: 您需要从官方OpenCV 网站中给出的任何属性的“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

6
另一种不依赖于有时会出现错误的CV_CAP_PROP获取器的解决方案是在循环中遍历整个视频文件。
增加一个帧计数器变量,每次遇到有效帧时递增,并在遇到无效帧(视频文件结尾)时停止。
收集有关分辨率的信息更加棘手,因为某些编解码器支持可变分辨率(类似于音频文件中的VBR,其中比特率不是恒定的,而是覆盖了一些预定义范围)。
  • 恒定分辨率 - 在这种情况下,您只需要第一帧即可确定整个视频文件的分辨率,因此不需要遍历整个视频。
  • 可变分辨率 - 您需要获取每个单独帧的分辨率(宽度和高度),并计算平均值以获得视频的平均分辨率。
FPS可以计算,但是这里与分辨率相同的问题-恒定(CFR)与可变(VFR)。这更像是一个多线程问题。我个人会使用一个帧计数器,每当遇到有效帧时就会增加,同时在1秒的时间间隔后,一个计时器(在后台线程中运行)会触发保存当前计数器的值,然后重置它。您可以将这些值存储在列表中,以便在最后计算视频的平均/恒定帧速率时使用,此时您还将知道视频的总帧数。
这种相当简单的做法的缺点是您必须遍历整个文件,如果它长达几个小时,用户肯定会注意到。在这种情况下,您可以聪明地做,并在让用户执行其他操作的同时在后台进程中执行该操作,而应用程序正在收集有关已加载的视频文件的信息。
优点是,无论您拥有什么样的视频文件,只要OpenCV可以从中读取,您就会获得相当准确的结果,不像CV_CAP_PROP可能按您预期工作或可能不按预期工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接