OpenCV 不报告准确的帧速率/计数

Posted

技术标签:

【中文标题】OpenCV 不报告准确的帧速率/计数【英文标题】:OpenCV doesn't report accurate frame rate/count 【发布时间】:2011-05-20 04:06:37 【问题描述】:

我正在尝试使用 OpenCV 处理一个 33 秒的视频。我的目标是确定每一帧对应的时间实例(相对于视频的开始)。我这样做是为了能够比较以不同帧速率录制的同一场景的视频中的帧。

什么工作:

FPS 正确报告为 59.75。这与ffprobe 报告的一致,所以我很高兴相信这是正确的。

我遇到的问题是:

CAP_PROP_POS_MSEC 返回不正确的值。到视频结束时,最长为 557924 毫秒(超过 9 分钟)。对于 33 多岁的视频,这是不对的。 CAP_PROP_FRAME_COUNT 也不正确。它被报告为 33371,以 59.75 fps 的速度可以提供超过 9 分钟的镜头。与上述错误一致,但仍然不正确。 CAP_PROP_POS_FRAME 同样不正确。

可以在here 找到视频(大约 10MB)。

对可能出现的问题有任何想法吗?

ffprobe 输出:

FFprobe version SVN-r20090707, Copyright (c) 2007-2009 Stefano Sabatini
  libavutil     49.15. 0 / 49.15. 0
  libavcodec    52.20. 0 / 52.20. 1
  libavformat   52.31. 0 / 52.31. 0
  built on Jan 20 2010 00:13:01, gcc: 4.4.3 20100116 (prerelease)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/misha/Dropbox/Public/sequence.mp4':
  Duration: 00:00:33.37, start: 0.000000, bitrate: 2760 kb/s
    Stream #0.0(und): Video: h264, yuv420p, 1920x1080, 59.75 tbr, 1k tbn, 2k tbc
    Stream #0.1(und): Audio: aac, 44100 Hz, stereo, s16

完整代码:

#include <iostream>
#include <assert.h>

#include <cv.h>    
#include <highgui.h>

#include <cmath>
#include <iostream>
#include <string.h>
#include <stdio.h>

extern "C"

#include "options.h"


using namespace std;

#define DEBUG 0

static void
print_usage(char *argv0)

    cerr << "usage: " << argv0 << " video.avi [options]" << endl;


int main(int argc, char** argv)

    if (argc < 2)
    
        print_usage(argv[0]);
        return -1;
    

    int           step      = 30;
    struct Option options[] =
    
         "step",        1, &step ,
         NULL,          0, NULL 
    ;

    int ret = parse_options(2, argc, argv, options);
    if (ret == 0)
    
        print_usage(argv[0]);
        return -1;
    

    CvCapture *capture = cvCaptureFromFile(argv[1]);
    int counter = 0;
    while (cvGrabFrame(capture))
    
        ++counter;

        IplImage *frame = cvRetrieveFrame(capture);
        double millis   = cvGetCaptureProperty(capture, CV_CAP_PROP_POS_MSEC);
        double current  = cvGetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES);
        double total    = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT);
        printf("%d %d/%d %f\n", counter, (int)current, (int)total, millis);
        int min = (int)(millis/1000/60);
        millis -= min*60000;
        int sec = (int)(millis/1000);
        millis -= sec*1000;

        printf("%d %02d:%02d:%f\n", counter, min, sec, millis);
    
    cvReleaseCapture(&capture);

    return 0;

【问题讨论】:

你使用的是哪一个:Windows/Linux/Mac? Linux (Ubuntu 10.04 LTS) 这解释了很多。 OpenCV 仍在努力改进对 Linux 下视频文件的支持,抱歉。 【参考方案1】:

始终告知您正在使用的软件版本:您为此使用的是哪个 OpenCV 版本?您的可能是旧版本,因此请尽可能更新到最新版本。

如果您的视频文件是其他较大视频的一部分,则此信息实际上可能是正确的,因为:

CV_CAP_PROP_POS_MSEC - film current position in milliseconds or video capture timestamp

OpenCV 可能只是从文件头中读取所有这些内容,这显然是错误的。如果有人使用斧头(或其他中世纪工具)从原始视频中删除该片段,则可能会发生这种情况。

您应该尝试使用您制作的视频,并且您知道它们没有被篡改。

在最坏的情况下,您必须自己实现这些功能。没什么大不了的。

编辑: @misha 我一开始并没有注意到你在使用:

CvCapture *capture = cvCaptureFromFile(argv[1]);

如果可以,请将其替换为 cvCaptureFromAVI(),并始终检查 OpenCV 调用的返回值:

CvCapture *capture = cvCaptureFromAVI(argv[1]);
if(!capture) 

    printf("!!! cvCaptureFromAVI failed (file not found?)\n");
    return -1; 

几天前我分享了一个代码uses OpenCV to read a video file and then save the frames as JPG images on the disk。它还使用传统的cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); 报告当前的 FPS,因此您可能会感兴趣看看它。去看看吧。

编辑:

您还应该检查this thread 使用 OpenCV 的帧数;

顺便说一句,我刚刚更新了我的 Ubuntu 系统上的一些库并重新编译了 OpenCV-2.1.0.tar.bz2(使用 cmake)。我更改了我的源代码(使用 cvCaptureFromAVI())以在每一帧上使用您的调试方法打印内容。似乎有效:

* Filename: sequence.mp4
* FPS: 59
...
...
...
17 00:00:567.000000
18 601/33371 601.000000
18 00:00:601.000000
19 634/33371 634.000000
19 00:00:634.000000
20 668/33371 668.000000
20 00:00:668.000000
21 701/33371 701.000000
21 00:00:701.000000
22 734/33371 734.000000
22 00:00:734.000000
23 768/33371 768.000000
23 00:00:768.000000
24 801/33371 801.000000
24 00:00:801.000000
25 835/33371 835.000000
25 00:00:835.000000
26 868/33371 868.000000
26 00:00:868.000000
27 901/33371 901.000000
27 00:00:901.000000
28 935/33371 935.000000
... 

【讨论】:

啊,我知道我忘记了什么。 cout &lt;&lt; "OpenCV version: " &lt;&lt; CV_VERSION &lt;&lt; endl;OpenCV version: 2.0.0 我使用的是 OpenCV 2.1(它不是最新的),它工作得很好。在您的机器上更新 OpenCV,然后重试。 我安装了 2.1。结果还是一样的:(我不介意重写这个功能来解决这个问题——正如你所说,这没什么大不了的。我的问题是:我怎么知道我可以信任标头中的 fps 值? 可变 fps 视频呢? 感谢您的更新。我试过cvCaptureFromAVI——结果和以前一样。奇怪的是,这个函数不在我的 2.1.0 API 文档中,但它似乎编译和链接很好。似乎没有太多关于它的文档(至少在 opencv 页面上,谷歌吐出了几个链接,不过)。它是某种复活节彩蛋功能还是什么?在接下来的几天里,我将尝试编写自己的方法来解决主题问题,并在我有东西要展示(或更多问题要问:))时发回这里。同时,感谢您的帮助,+1 的努力。 @misha 我的答案的新信息。用 sequence.mp4 测试过。

以上是关于OpenCV 不报告准确的帧速率/计数的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV 对象检测 - 中心点

OpenCV,从相机捕获并保存到文件

浏览器如何计算 HTML5 <video> 的帧速率 (fps) 以实现准确的帧搜索?

opencv 视频处理(python)

opencv中如何将从视频中抓取的帧释放掉

如何减少OpenCV python中的帧数?