测量OpenCV的帧率

10
我正在寻找一种正确的测量openCV FPS的方法。我已经尝试了几种方法,但是没有一种对我来说看起来是正确的。
第一个我测试的方法使用time_t start和time_t end。我认为这种方法是错误的,因为它返回给我一个作为fps x时间图的转储函数(我真的无法想象fps图如何成为一个转储函数)。
以下是该图像的图片。
第二个我测试的方法使用t = (double)cvGetTickCount()来测量fps。这种方法是错误的,因为它返回120 fps作为结果,但是对于使用120 fps拍摄的30秒长视频,处理时间不应超过1分钟。所以这是一种错误的测量FPS的方法。
有人知道在openCV中测量FPS的另一种方法吗?
附注:我正在尝试在视频的每个帧中查找圆。视频帧大小为320x240像素。
更新2:我尝试测量FPS的代码。
for(;;)
    {

        clock_t start=CLOCK();

        Mat frame, finalFrame;
        capture >> frame; 

        finalFrame = frame;

        cvtColor(frame, frame, CV_BGR2GRAY);

        GaussianBlur(frame, frame, Size(7,7), 1.5, 1.5);
        threshold(frame, frame, 20, 255, CV_THRESH_BINARY);

        dilate(frame, frame, Mat(), Point(-1, -1), 2, 1, 1);
        erode(frame, frame, Mat(), Point(-1, -1), 2, 1, 1);

        Canny(frame, frame, 20, 20*2, 3 );

        vector<Vec3f> circles;

        findContours(frame,_contours,_storage,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE );

        vector<vector<Point> > contours_poly( _contours.size() );
        vector<Rect> boundRect( _contours.size() );
        vector<Point2f>center( _contours.size() );
        vector<float>radius( _contours.size() );


        int temp = 0;

        for( int i = 0; i < _contours.size(); i++ )
        { 
            if( _contours[i].size() > 100 )
            {
               approxPolyDP( Mat(_contours[i]), contours_poly[i], 3, true );
               boundRect[i] = boundingRect( Mat(_contours[i]) );
               minEnclosingCircle( (Mat)_contours[i], center[i], radius[i] );
               temp = i;
               break;
            }
        }



        double dur = CLOCK()-start;
            printf("avg time per frame %f ms. fps %f. frameno = %d\n",avgdur(dur),avgfps(),frameno++ );

        frameCounter++;

        if(frameCounter == 3600)
        break;

        if(waitKey(1000/120) >= 0) break;
    }

更新

采用Zaw Lin方法执行程序! enter image description here


1
你想测量视频的帧率还是当前运行时的帧率(以了解算法运行的速度)? - Zaw Lin
我正在寻找一种测量运行时帧速率的方法! - MSO
getTickCount() 返回的是一个时钟周期数,而不是秒数。你需要使用 getTickFrequency() 将时钟周期数转换为秒数。请参考 http://docs.opencv.org/modules/core/doc/utility_and_system_functions_and_macros.html?highlight=gettickcount#gettickfrequency。 - BConic
4个回答

10
我已经在Getting current FPS of OpenCV发布了一个方法来实现这个目标。需要做一些平均才能避免fps跳动太大。

编辑

我在process()函数中加入了Sleep,这样可以得到正确的fps和持续时间(+/- 1ms)。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv/cv.h>
#include <sys/timeb.h>
using namespace cv;

#if defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) \
    || defined(WIN64)    || defined(_WIN64) || defined(__WIN64__) 

#include <windows.h>
bool _qpcInited=false;
double PCFreq = 0.0;
__int64 CounterStart = 0;
void InitCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
    {
        std::cout << "QueryPerformanceFrequency failed!\n";
    }
    PCFreq = double(li.QuadPart)/1000.0f;
    _qpcInited=true;
}
double CLOCK()
{
    if(!_qpcInited) InitCounter();
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart)/PCFreq;
}

#endif

#if defined(unix)        || defined(__unix)      || defined(__unix__) \
    || defined(linux)       || defined(__linux)     || defined(__linux__) \
    || defined(sun)         || defined(__sun) \
    || defined(BSD)         || defined(__OpenBSD__) || defined(__NetBSD__) \
    || defined(__FreeBSD__) || defined __DragonFly__ \
    || defined(sgi)         || defined(__sgi) \
    || defined(__MACOSX__)  || defined(__APPLE__) \
    || defined(__CYGWIN__) 
double CLOCK()
{
    struct timespec t;
    clock_gettime(CLOCK_MONOTONIC,  &t);
    return (t.tv_sec * 1000)+(t.tv_nsec*1e-6);
}
#endif

double _avgdur=0;
double _fpsstart=0;
double _avgfps=0;
double _fps1sec=0;

double avgdur(double newdur)
{
    _avgdur=0.98*_avgdur+0.02*newdur;
    return _avgdur;
}

double avgfps()
{
    if(CLOCK()-_fpsstart>1000)      
    {
        _fpsstart=CLOCK();
        _avgfps=0.7*_avgfps+0.3*_fps1sec;
        _fps1sec=0;
    }
    _fps1sec++;
    return _avgfps;
}

void process(Mat& frame)
{
    Sleep(3);
}
int main(int argc, char** argv)
{
    int frameno=0;
    cv::Mat frame;
    cv::VideoCapture cap(0);
    for(;;)
    {
        //cap>>frame;
        double start=CLOCK();
        process(frame);
        double dur = CLOCK()-start;
        printf("avg time per frame %f ms. fps %f. frameno = %d\n",avgdur(dur),avgfps(),frameno++ );
        if(waitKey(1)==27)
            exit(0);
    }
    return 0;
}    

嗨,我相信这种行为是由于clock()的最小灵敏度为1ms所导致的。如果每个帧的持续时间少于1毫秒,则会发生一些舍入,并且您仍将得到1毫秒。当它们平均起来时,由于舍入误差的积累,持续时间高于预期。您可以通过输出瞬时持续时间而不是平均持续时间进行测试。您会注意到很多1ms(可能少于1ms)。但是因为fps实际上是在1秒间隔内计数,所以应该更准确。 - Zaw Lin
我意识到我在解释我的情况而不是你的情况,如果帧花费超过1毫秒,问题应该会减轻一些。但最好输出瞬时持续时间以查看发生了什么。 - Zaw Lin
你好,Zaw Lin。我现在正在使用avgdur(dur)作为我的fps指标,并且它给出了更真实的输出。完成后,我将所有avgdur(dur)值除以1000,得到一个间接的fps值。平均而言,结果是130 fps,这是一个非常可接受的结果。我已经计算出了我的电脑处理120 fps的30秒AVI所花费的时间。处理视频所花费的时间为32.02秒,这也是一个非常可接受的结果。你认为使用avgdur来计算间接fps值是否可行? - MSO
嗨,我正在本地进行一些测试,看看可能出了什么问题,目前为止,对我来说,avgdur 和 avgfps 总是相符的,所以我有点不知所措。在我看来,衡量 fps 最好的方法是按照 1 秒间隔计数,因为这样没有涉及推导,并且可能没有更好的方法。使用 avgdur 是可以的,但平均 fps 应该比除以1000更“真实”。 - Zaw Lin
2
在执行任何操作之前,你调用了 InitCounter(); 吗? - Zaw Lin
显示剩余14条评论

4
你可以使用 OpenCV 的辅助功能 cv::getTickCount() 来帮助你。
#include <iostream>
#include <string>

#include "opencv2/core.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/video.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;


int main(int ac, char** av) {

    VideoCapture capture(0);
    Mat frame;

    for (;;) {

        int64 start = cv::getTickCount();

        capture >> frame;
        if (frame.empty())
            break;

        /* do some image processing here */

        char key = (char)waitKey(1);

        double fps = cv::getTickFrequency() / (cv::getTickCount() - start);
        std::cout << "FPS : " << fps << std::endl;
    }
    return 0;
}

1
如果你正在处理视频文件,可以使用OpenCV的API来获取原始FPS。当从实时流中捕获时,以下方法将无法工作:
cv::VideoCapture capture("C:\\video.avi");
if (!capture.isOpened())
{
    std::cout  << "!!! Could not open input video" << std::endl;
    return;
}

std::cout << "FPS: " << capture.get(CV_CAP_PROP_FPS) << std::endl;

要在处理后获得实际FPS,您可以尝试使用Zaw的方法。

0

我会只测量墙上时间,然后将帧数除以经过的时间。 在Linux上:

/*
* compile with:
*   g++ -ggdb webcam_fps_example2.cpp -o webcam_fps_example2 `pkg-config --cflags --libs opencv`
*/

#include "opencv2/opencv.hpp"
#include <time.h>
#include <sys/time.h>


using namespace cv;
using namespace std;

double get_wall_time(){
    struct timeval time;
    if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }
    return (double)time.tv_sec + (double)time.tv_usec * .000001;
}


int main(int argc, char** argv)
{
    VideoCapture cap;
    // open the default camera, use something different from 0 otherwise;
    // Check VideoCapture documentation.
    if(!cap.open(0))
        return 0;

    cap.set(CV_CAP_PROP_FRAME_WIDTH,1920);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT,1080);

    double wall0 = get_wall_time();
    for(int x = 0; x < 500; x++)
    {
          Mat frame;
          cap >> frame;
          if( frame.empty() ) break; // end of video stream
          //imshow("this is you, smile! :)", frame);
          if( waitKey(10) == 27 ) break; // stop capturing by pressing ESC 
    }
    double wall1 = get_wall_time();
    double fps = 500/(wall1 - wall0);
    cout << "Wall Time = " << wall1 - wall0 << endl;
    cout << "FPS = " << fps << endl;
    // the camera will be closed automatically upon exit
    // cap.close();
    return 0;
}

墙上时间 = 43.9243 FPS = 11.3832


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