计算出的fps如何大于相机声明的fps?

时间:2019-01-12 00:54:18

标签: c++ opencv camera frame-rate

在处理相机中的帧时,我试图测量每秒的帧数。计算没什么特别的,可以在以下问题中找到:How to write function with parameter which type is deduced with 'auto' word? 我的相机很旧,制造商宣称FPS不超过30,分辨率为640x480。但是,当我运行这些计算时,实时流向我显示40-50。怎么可能?

更新:代码:

#include <chrono>
#include <iostream>

using std::cerr;
using std::cout;
using std::endl;

#include <string>
#include <numeric>

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/imgproc.hpp>

using cv::waitKey;
using cv::Mat;

using time_type = decltype(std::chrono::high_resolution_clock::now());

void showFPS(Mat* frame, const time_type &startTime);

int main(int argc, char** argv) {

    cv::VideoCapture capture;
    std::string videoDevicePath = "/dev/video0";

    if (!capture.open(videoDevicePath)) {
        std::cerr << "Unable to open video capture.";
        return 1;
    }
    //TODO normally through cmd or from cameraParameters.xml
    bool result;
    result = capture.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G'));
    if (result) {
        std::cout << "Camera: PROP_FOURCC: MJPG option set.";
    } else {
        std::cerr << "Camera: PROP_FOURCC: MJPG option was not set.";
    }
    result = capture.set(CV_CAP_PROP_FRAME_WIDTH, 640);
    if (result) {
        std::cout << "Camera: PROP_FRAME_WIDTH option set.";
    } else {
        std::cerr << "Camera: PROP_FRAME_WIDTH option was not set.";
    }
    result = capture.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    if (result) {
        std::cout << "Camera: PROP_FRAME_HEIGHT option set.";
    } else {
        std::cerr << "Camera: PROP_FRAME_HEIGHT option was not set.";
    }
    result = capture.set(CV_CAP_PROP_FPS, 30);
    if (result) {
        std::cout << "Camera: PROP_FPS option set.";
    } else {
        std::cerr << "Camera: PROP_FPS option was not set.";
    }

    Mat frame, raw;
    while (cv::waitKey(5) != 'q') {
        auto start = std::chrono::high_resolution_clock::now();
        capture >> raw;

        if (raw.empty()) {
            return 1;
        }
        if (raw.channels() > 1) {
            cv::cvtColor(raw, frame, CV_BGR2GRAY);
        } else {
            frame = raw;
        }
        showFPS(&raw1, start);
    }
    return 0;
}

void showFPS(Mat* frame, const time_type &startTime) {
    typedef std::chrono::duration<float> fsec_t;

    auto stopTime = std::chrono::high_resolution_clock::now();
    fsec_t duration = stopTime - startTime;

    double sec = duration.count();
    double fps = (1.0 / sec);
    std::stringstream s;
    s << "FPS: " << fps;
    cv::putText(*frame, s.str(), Point2f(20, 20), constants::font,
                constants::fontScale, constants::color::green);
}

3 个答案:

答案 0 :(得分:3)

相机的FPS是相机每秒可提供的帧数。 这意味着相机每33ms提供一次新帧。

另一方面,您要测量的不是FPS。 您正在测量新帧检索和颜色转换功能的倒数时间。 根据您的结果,这一次是20-25毫秒。

这不是测量FPS的正确方法,至少因为您不能保证这两个过程的同步。

如果要正确测量FPS,则可以测量显示最后N帧的时间。

伪代码:

counter = 0;
start = getTime();
N = 100;

while (true) {
  captureFrame();
  convertColor();
  counter++;

  if (counter == N) {
    fps = N / (getTime() - start);
    printFPS(fps);

    counter = 0; 
    start = getTime();
  }
}

答案 1 :(得分:1)

Aleksey Petrov的回答还不错,但是在对最后N帧进行平均时,可以得到更平滑的值,而无需平均就可以相对准确地测量帧速率。修改后的问题代码可以做到这一点:

    // see question for earlier code
    Mat frame, raw;
    time_type prevTimePoint;   // default-initialized to epoch value
    while (waitKey(1) != 'q') {
        capture >> raw;
        auto timePoint = std::chrono::high_resolution_clock::now();

        if (raw.empty()) {
            return 1;
        }
        if (raw.channels() > 1) {
            cv::cvtColor(raw, frame, CV_BGR2GRAY);
        } else {
            frame = raw;
        }

        showFPS(&frame, prevTimePoint, timePoint);

        cv::imshow("frame", frame);
    }
    return 0;
}

void showFPS(Mat* frame, time_type &prevTimePoint, const time_type &timePoint) {
    if (prevTimePoint.time_since_epoch().count()) {
        std::chrono::duration<float> duration = timePoint - prevTimePoint;
        cv::putText(*frame, "FPS: " + std::to_string(1/duration.count()),
            cv::Point2f(20, 40), 2, 2, cv::Scalar(0,255,0));
    }
    prevTimePoint = timePoint;
}

请注意,这测量的是capture >> raw返回后的时间点,该时间点(不打扰OpenCV)是相机发送帧时最接近的时间点,并且每个循环仅测量一次时间并与之前的测量结果进行比较,从而得出了非常精确的当前帧速率。当然,如果处理花费的时间超过1 /(帧速率),则测量将关闭。

问题代码的帧率过高的原因实际上是两次时间测量之间的代码:now()中的showFPS()now()中的while环。我的直觉是此代码包含cv::imshow(),这不是问题所在,它与cv::waitKey(5)cv::putText()一起可能是帧速率计算中大部分“丢失时间”的原因(导致帧速率太高。

答案 2 :(得分:0)

您之间有一个cvtColor,因此它会影响您的时间计算,因为cvtColor的处理时间可能在每个循环中有所不同(可能是由于Windows的其他处理)。

  

考虑以下示例:

     

您在时刻0用capture得到第一帧,然后执行   cvtColor,例如10毫秒,然后您在stopTime   瞬间10毫秒。 23 ms(33-10)之后,您capture第二帧。但   这次cvtColor花费5毫秒(可能会发生),您将   第二stopTime是在第38时刻(33 + 5),所以第一个刻度是在   10,第二个刻度是在38时刻。      

1000 /(38-10)= 35.7