首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Cv2. cap.set和循环读取之间的视频捕获不一致行为

Cv2. cap.set和循环读取之间的视频捕获不一致行为
EN

Stack Overflow用户
提问于 2022-04-29 06:31:35
回答 1查看 177关注 0票数 2

我试着用cv2.VideoCapture阅读第600帧的视频。但是,我发现以下两种方法都成功地读取了图像,但是图像不同。我想知道哪一种读取第600帧的方法是正确的,为什么产生的图像是不同的?它与mp4编码有关吗?谢谢!

方法1

代码语言:javascript
运行
复制
cap = cv2.VideoCapture("test.mp4")
print(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 1187
cap.set(1, 600)
ret, frame1 = cap.read()  # Read the frame

方法2

代码语言:javascript
运行
复制
cap = cv2.VideoCapture("test.mp4")
print(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 1187
for i in range(601):
    ret, frame2 = cap.read()  # Read the frame
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-29 08:27:37

要读取/获取视频的X第四帧或类似地确定视频文件中的帧数,有两种方法:

  • 方法1:利用内置的OpenCV属性访问视频文件元信息,这是快速、高效但不准确的
  • 方法2:用计数器手动遍历视频文件中的每一帧,该计数器是,速度慢,效率低,但准确

方法1是快速的,并且依赖OpenCV的视频属性功能,它几乎即时地确定视频文件中的帧信息。然而,由于它依赖于您的OpenCV和视频编解码器版本,所以有一个精确的折衷。从文件中:

读写属性涉及许多层。一些意想不到的结果可能会发生在这条链上。有效的行为取决于设备硬件、驱动程序和API后端。

另一方面,手动计数每个帧,直到我们达到预期的帧数将是100%的准确性,虽然它将显着地慢。这里有一个示例来演示这两种方法之间的不一致行为。默认情况下,它尝试执行方法#1,如果失败,它将自动使用方法#2。

代码语言:javascript
运行
复制
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

基准测试

代码语言:javascript
运行
复制
if __name__ == '__main__':
    import timeit
    import cv2

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

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

方法1结果

代码语言:javascript
运行
复制
frames: 3671
0.018054921 (s)

方法2结果

代码语言:javascript
运行
复制
frames: 3521
9.447095287 (s)

注意这两种方法是如何区别150帧的,方法2比方法1要慢得多。一般来说,如果您需要速度,但愿意牺牲准确性,请使用方法1。在有延迟但需要精确框架的情况下,请使用方法2。

因此得出的结论是:当您使用cap.get或任何内置的VideoCaptureProperties (如cv2.CAP_PROP_FRAME_COUNT )时,实际上使用的是方法#1,它速度快、效率高,但不准确。在您的第一个示例中,当您试图使用cap.set读取一个确切的框架时,您实际上得到了一个接近所需的X第四帧的“估计”帧,而不是实际的X框架。相反,从您的第二个代码片段中,您将手动逐个遍历每个帧,因此当它降落到X第四帧时,这是绝对正确的。这就是为什么当您尝试使用每个方法读取相同的帧号时,您可能会得到不同的图像。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72053674

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档