OpenCV 中的非整数帧数?

Non-integer frame numbers in OpenCV?

我在 OSX(10.10.5) 上的 python 中使用 OpenCV。我是 OpenCV 的新手。现在我只是想找到视频中某个事件发生的帧号。我正在使用轨迹栏浏览视频。

我遇到的问题是 OpenCV 报告的是非整数帧数。我的程序应该将帧号设置为轨迹栏位置。轨迹栏位置始终是整数,但帧编号不是。对于较长的视频,问题似乎更严重:对于较短的视频,当轨迹栏位置为 254 时,帧数(如果不是整数)类似于 253.99999999999994。但是,对于较长的视频,帧数与整数的距离越来越远值(例如,当轨迹栏位置为 11212 时为 11212.20588235294,或当轨迹栏位置为 26631 时为 26631.529411764703。)请注意,这些数字并不总是四舍五入或截断为与轨迹栏位置相同的整数。

每个视频的总帧数也不是整数:我测试的较短视频为 1547.9999999999998,我测试的长视频为 92651.38235294117。较短的视频是 .mov 文件,较长的是 .mp4,我使用 ffmpeg 从 .mpg 转码而来。

为什么会这样?我怎样才能找出帧数?谢谢你的帮助!这是我一直在使用的测试代码(请注意,它基于来自 http://giusedroid.blogspot.com/2015/05/python-opencv-frame-grabber.html 的图像采集卡):

import numpy as np
import cv2

video_path = '#set video path here'

# grab a VideoCapture object
cap = cv2.VideoCapture(video_path)

#set some shorthand names
current_frame_flag = cv2.cv.CV_CAP_PROP_POS_FRAMES
total_frames_flag = cv2.cv.CV_CAP_PROP_FRAME_COUNT
win_name = "Frameshift calculator"
pos_trackbar='pos_trackbar'

cv2.namedWindow(win_name)


def seek_callback(x): 

    # we want to change the value of the frame variable globally
    global frame
    # by getting the position of the trackbar
    i = cv2.getTrackbarPos(pos_trackbar, win_name)
    # and skipping to the selected frame
    cap.set(current_frame_flag, i)
    _, frame = cap.read()
    # and then update the window
    cv2.imshow(win_name, frame)
    #print out the current frame flag and the trackbar position
    print(cap.get(current_frame_flag), i)

cv2.createTrackbar(pos_trackbar, win_name, 0, int(cap.get(total_frames_flag)), seek_callback)

while True:
    # shows the image
    cv2.imshow(win_name, frame)
    # waits for keystroke
    if cv2.waitKey(0) & 0xFF == ord('q'):
        break
    key = cv2.waitKey(0)

cap.release
cv2.destroyAllWindows()

一些样本(帧号,轨迹栏位置)对:

较短的视频 (.mov): (1.0, 0) (171.99999999999997, 172) (842.9999999999999, 843) (1141.0, 1141) (1330.0, 1330) (111.99999999999999, 112) (235.99999999999997, 236) (590.9999999999999, 591) (1546.9999999999998, 1547)

更长的视频 (.mp4): (1.0, 0) (6642.911764705882, 6642) (27496.11764705882, 27496) (49707.529411764706, 49707) (64786.294117647056, 64786) (84065.38235294117, 84065)

这很可能是因为您的帧率不是整数。对于每个视频,调查视频的实际帧速率是多少:

frame_rate = cv2.cv.CV_CAP_PROP_FPS

事实上,对于某些视频,有一个 浮点 帧速率。通常在电视中……至少在北美标准中,预期帧速率为 30 FPS。但是,您很可能拥有 29.97 FPS。本文对此进行了更详细的解释:http://theautomaticfilmmaker.com/blog/2009/2/23/about-frame-rates-or-why-2997.html.

但是,如果我能总结一下,早在 1970 年代,先进的电子技术还没有处理这个问题,在电视引入彩色之前,广播实际上以 30 FPS 的速度运行,但由于发送彩色信息需要额外的信息, 这个信息实际上干扰了声音信息,所以他们不得不将 FPS 延迟 0.03 FPS 来补偿和移动声音信息和颜色信息稍微不同相。

但这不是重点。一个视频的浮点帧数超过另一个视频的原因完全取决于帧速率。因此,通过尝试获取所需位置的帧号,可能会出现所需的帧号与视频中的实际帧号不完全一致的情况,因此它会为您提供所需的帧号bests 对应于浮点帧速率,这就是您获得浮点结果的原因。

当您开始使帧索引变大时也会出现漂移的原因再次仅仅是因为帧速率。当您开始指定更高的帧数时,请记住对于 30 / 29.97 场景的情况,您希望在索引处抓取的帧是您想要的,但是因为每 30 FPS,您就落后 0.03,对于较大的帧索引,这种差异会加剧,因为每 30 帧的差异为 0.03。


关于获取确切的帧数,我在这里真的没有建议给你。但是,您也许可以提取出所需设置帧索引之前的一帧和之后的一帧,然后您可以从那里查看内容。指定实际帧索引本身(至少从我所看到的)在实践中很少使用,这就是为什么。