10

I'm looking for a correct way to measure openCV FPS. I've found several ways to do it. but none of them looks right for me.

The first one I've tested, uses time_t start and time_t end. I think that one is wrong once it returns me a dumped function as fps x time plot (I really can't imagine how a fps plot could be a dumped function).

Here the image of this plot.

FPS PLOT

The second I've tested uses t = (double)cvGetTickCount() to measure fps. This way is wrong once it returns 120 fps as result, but, for a 30 seconds length video captured with 120 fps shouldn't take more than 1 minute to be processed. so this is a wrong way to measure FPS.

Someone knows another way to measure FPS in openCV?

Ps. I'm trying to find circles in each frame of the video. The video frame size is 320x240 pixels.

Update 2 The code that I'm trying to measure 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;
    }

Update

Program execution using the Zaw Lin method! enter image description here

KansaiRobot
  • 7,564
  • 11
  • 71
  • 150
MSO
  • 409
  • 1
  • 9
  • 22
  • 1
    do you want to measure the fps of the video or the current runtime fps(to know how fast your algorithm can run)? – Zaw Lin Mar 03 '14 at 14:13
  • I'm looking for a way to measure runtime fps! – MSO Mar 03 '14 at 14:16
  • `getTickCount()` returns a number of ticks, not a duration in seconds. You have to use `getTickFrequency()` to convert ticks into seconds. See http://docs.opencv.org/modules/core/doc/utility_and_system_functions_and_macros.html?highlight=gettickcount#gettickfrequency. – BConic Mar 03 '14 at 14:22

4 Answers4

10

I have posted a way to do that @ Getting current FPS of OpenCV. It is necessary to do a bit of averaging otherwise the fps will be too jumpy.

edit

I have put a Sleep inside process() and it gives correct fps and duration(+/- 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;
}    
Community
  • 1
  • 1
Zaw Lin
  • 5,629
  • 1
  • 23
  • 41
  • Zaw Lin Thanks for ur reply. I've tested ur method to measure the FPS. the problem is: the avgfps() is always increasing it's value up 220 fps and the average time for each frame keeps on 7 or 8 ms per frame ! What's wrong with it? – MSO Mar 03 '14 at 14:26
  • Is this something unexpected? May I know what's expected? – Zaw Lin Mar 03 '14 at 14:31
  • I think this is unexpected once the time to process each frame remains the same, never decreases. to achieve 220 fps the time to process each frame should be less than 7 ms, maybe 3 or 4, and that is not what's happening. I've got a pic of the program execution. I'll update the main thread with it. Please check it! – MSO Mar 03 '14 at 14:35
  • hi, I believe this behaviour occurs because clock()'s smallest sensitivity is 1ms. If each frame takes less than one ms, some rounding should occur and you will still get 1ms. When they are averaged out, the duration is higher than expected due to accumulation of rounding errors. You can test by outputting the instantaneous duration instead of average duration. You will notice a lot of 1ms(which are probably less than 1ms). But since fps is really counting in 1 second intervals, it should be more accurate. – Zaw Lin Mar 03 '14 at 14:41
  • I realized I was explaining my situation instead of yours, the problem should be less severe if the frames take more than 1ms.But it's best to output the instantaneous duration to see what's happening. – Zaw Lin Mar 03 '14 at 14:48
  • Yes! Mine will take more than 1 ms to be processed. So the instantaneous duration is the time took to process each frame (in ms)? – MSO Mar 03 '14 at 14:57
  • hi, i have posted a different way to measure duration, can you check to see if it gives a more reasonable output? For me, the previous method gives a slightly higher duration. afaik, this is the best way to measure time in windows. fps calculation remains the same, as the small inaccuracies would not do much to offset the final fps. – Zaw Lin Mar 03 '14 at 15:21
  • best is to post a small sample code that reproduce the problem as where you put start and end code can affect what's happening – Zaw Lin Mar 03 '14 at 15:26
  • Zaw Lin! Thanks for ur reply! I'll update the main thread with the code that I'm trying to measure FPS. – MSO Mar 03 '14 at 16:17
  • Zaw Lin! I've tested the different wat to measure the duration. About the duration it looks more resonable for me. It have less fluctuations between 8 and 7 ms. Definetly looks better than the first one. About the avg fps, it still increasing up to 220 fps, and it obviously not processing at this rate. Any idea? Thank you so much for helping me with this issue! – MSO Mar 03 '14 at 16:26
  • Hello Zaw Lin. I'm now using avgdur(dur) as my fps metric and it's giving me a much more real output. Once finished, I'm dividing all avgdur(dur) values by 1000 resulting a indirect fps value. In average, it results 130 fps, what is a really acceptable result. I've got the time spent by my computer to process 30 secons AVI with 120 fps. The time spent to process the video was 32.02 seconds what is a really acceptable result. Do you think using avgdur to compute a indirect fps value is plausible? – MSO Mar 03 '14 at 17:11
  • Hi, I am doing some tests locally to see what could be going on, so far avgdur and avgfps always corresponds for me, so I am a bit at a loss. In my opinion, best way to measure fps is by counting in 1 second intervals as there is no derivation involved and cannot possibly have a better method. Using avgdur is fine but avgfps should be a more "real" fps than division by 1000 – Zaw Lin Mar 03 '14 at 17:12
  • I think it's possible that on your computer `clock()` function has a large error margin. I will update the method to use qpc – Zaw Lin Mar 03 '14 at 17:14
  • Hi, I have updated the code, please check and let me know. Firstly, I suggest you run the code as is. It will simply sleeps for 3 milliseconds without doing anything. It gave correct duration(with ~1ms from function/calling printing overhead) and correct fps (250 fps). Please check if this is correct before adding in video processing code – Zaw Lin Mar 03 '14 at 17:24
  • Hello Zaw! Without my processing code, everything gone really fine, acctually, in my case the fps is up to 320!!! When I'm using the new functions on my processing procedure, the avgdur(dur) returns me -1.#IND (indeterminate) and the avgfps is 0. I'm trying to figure out why is it happening. Any idea? – MSO Mar 03 '14 at 17:37
  • 2
    did you call `InitCounter();` before anything? – Zaw Lin Mar 03 '14 at 17:43
  • I've figure out why. I haven't called initcounter(). Sorry, Testing the now – MSO Mar 03 '14 at 17:44
  • Oh exactly what you said! – MSO Mar 03 '14 at 17:45
  • Zaw Lin! I think now it worked perfectly! This time the avgfps is fixed in 117 and it makes sense once the time spent by my computer to process the 30 seconds AVI at 120 fps was 31.175 seconds. Thank you so much! YOU'RE A LEGEND! – MSO Mar 03 '14 at 17:54
4

You can use opencv helper 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;
}
d00d
  • 514
  • 10
  • 20
1

You can use OpenCV's API to get the original FPS if you are dealing with video files. The following method will not work when capturing from a live stream:

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;

To get the actual FPS after the processing, you can try Zaw's method.

karlphillip
  • 92,053
  • 36
  • 243
  • 426
0

I would just measure the walltime and simply divide the frames by time elapsed. On 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;
}

Wall Time = 43.9243 FPS = 11.3832

Lightsout
  • 3,454
  • 2
  • 36
  • 65