如何使用OpenCV获取视频的时长

37

我只能使用OpenCV获取帧数CAP_PROP_FRAME_COUNT

然而,我找不到使用OpenCV获取视频持续时间的参数。

该怎么做呢?

非常感谢。


如果我没记错的话,应该是帧数乘以频率。 - Mathieu
@Mathieu 实际上是帧数/频率。(频率的单位为1/秒) 因此,一个有60帧和30 Hz的视频持续时间为2秒。 - Dorian
6个回答

59

在OpenCV 3中,解决方案是:

import cv2 as cv

cap = cv.VideoCapture("./video.mp4")
fps = cap.get(cv.CAP_PROP_FPS)      # OpenCV v2.x used "CV_CAP_PROP_FPS"
frame_count = int(cap.get(cv.CAP_PROP_FRAME_COUNT))
duration = frame_count/fps

print('fps = ' + str(fps))
print('number of frames = ' + str(frame_count))
print('duration (S) = ' + str(duration))
minutes = int(duration/60)
seconds = duration%60
print('duration (M:S) = ' + str(minutes) + ':' + str(seconds))

cap.release()

1
当你在回答中说你正在使用OpenCV 3时,为什么要导入cv2cv2不是表示OpenCV 2吗?还是我理解错了? - HelloGoodbye
3
你好@HelloGoodbye,这个页面应该可以解释你的问题:https://dev59.com/oKHia4cB1Zd3GeqPbO6l - Ryan Loggerythm

37

OpenCV并不是专门用于探索视频元数据的,因此VideoCapture没有直接检索元数据的API。

相反,您可以“测量”流的长度:跳到结尾,然后获取时间戳:

>>> import cv2 as cv
>>> v = cv.VideoCapture('sample.avi')
>>> v.set(cv.CAP_PROP_POS_AVI_RATIO, 1)
True
>>> v.get(cv.CAP_PROP_POS_MSEC)
213400.0

检查显示这将时间戳设置为最后一帧之后(而不是之前),因此时间戳确实是流的精确总长度:

>>> v.get(cv.CAP_PROP_POS_FRAMES)
5335.0
>>>> v.get(cv.CAP_PROP_FRAME_COUNT)
5335.0

>>> v.set(cv.CAP_PROP_POS_AVI_RATIO, 0)
>>> v.get(cv.CAP_PROP_POS_FRAMES)
0.0        # the 1st frame is frame 0, not 1, so "5335" means after the last frame

1
除非在设置位置后调用v.read(),包括寻找结尾,否则对v.get(cv2.CAP_PROP_POS_MSEC)的调用可能不会返回正确的值。请参见https://github.com/opencv/opencv/issues/15749。 - kfx
@kfx 我明白了。所以这是 4.1.2 中的新行为。当我在结尾时,即使在 read() 之后,我也会得到错误的数字;从代码来看,它似乎不需要调用 read(),因为它设置了 picture_pts。所以在我看来,这是一个 bug。 - ivan_pozdeev
使用CAP_PROP_POS_AVI_RATIO寻找流的结尾似乎并不总是有效,这取决于视频类型(例如,无法在QuickTime .mov文件中使用)。我建议谨慎使用。 - Jack

7
捕获视频并输出其时长(以秒为单位)。
import cv2 as cv
vidcapture = cv.VideoCapture('myvideo.mp4')
fps = vidcapture.get(cv.CAP_PROP_FPS)
totalNoFrames = vidcapture.get(cv.CAP_PROP_FRAME_COUNT)
durationInSeconds = totalNoFrames / fps

print("durationInSeconds:", durationInSeconds, "s")

4

首先按照以下方式计算每秒帧数:

import cv2 as cv
# cap = cv.VideoCapture...
fps = cap.get(cv.CAP_PROP_FPS)

然后,时长可以计算为(帧数)/(每秒帧数)。
 duration = float(num_frames) / float(fps) # in seconds

3
遗憾的是,这种方法并不总是有效。CAP_PROP_FPS来自头部数据,其计算结果并不可靠。 - Connor

2

根据我的个人经验,我一直在使用OpenCV方法。请尝试以下代码:

import cv2 as cv

def get_dur(filename):
    video = cv.VideoCapture(filename)
    fps = video.get(cv.CAP_PROP_FPS)
    frame_count = video.get(cv.CAP_PROP_FRAME_COUNT)
    seconds = frame_count / fps
    minutes = int(seconds / 60)
    rem_sec = int(seconds % 60)
    return f"{minutes}:{rem_sec}"

print(get_dur("dafuck.mp4"))

你可以使用Python的divmod函数一次计算商(分钟)和余数(秒)。例如,对于100秒:minutes,seconds = divmod(100,60) - Michael S.
你可以使用Python的divmod函数一次性计算商(分钟)和余数(秒)。例如,对于100秒:minutes, seconds = divmod(100, 60) - undefined

1
我注意到一个奇怪的现象,许多视频的帧数不如 vid.get(cv.CAP_PROP_FRAME_COUNT) 所得的那么多。
我认为视频的持续时间应该是 TOTAL FRAMES 除以 FPS 的商,但它总是不匹配。视频的持续时间会比我们计算的长。考虑到 FFMPEG 的作用,原始视频可能有一些空白帧。
希望这可以帮助你。

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