【问题标题】:How calculated fps can be greater than camera's declared fps?如何计算出的 fps 可以大于相机声明的 fps?
【发布时间】:2019-06-06 22:15:30
【问题描述】:

在处理来自相机的帧时,我正在尝试测量每秒帧数。计算没什么特别的,可以在这个问题中找到: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);
}

【问题讨论】:

  • 如果没有看到从相机读取帧的代码就很难回答。

标签: c++ opencv camera frame-rate


【解决方案1】:

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

另一方面,您测量的不是 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();
  }
}

【讨论】:

    【解决方案2】:

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

    考虑这个例子:

    您在时刻 0 获得带有 capture 的第一帧,然后执行 cvtColor 这需要例如10 毫秒,然后你在stopTime 时刻 10 毫秒。 23 毫秒后 (33-10) 你capture 第二帧。但 这次cvtColor 需要 5 毫秒(它可能会发生),然后你 第二个 stopTime 在 38 (33+5) 时刻,所以第一个刻度是在那个时刻 10,第二个刻度是在 38 时刻。现在你的 fps 变成了

    1000/(38-10) = 35.7

    【讨论】:

    • 那么如何准确测量FPS呢?阿列克谢·彼得罗夫的写作方式?
    • 答案是错误的。如果继续该示例,假设时间 cvtColor 在 10 到 5 毫秒之间交替,您会看到 fps 值在 36 (1/.028) 和 26 (1/0.038) 之间交替,但不是始终高于30 如问题所述。
    • @UlrichStern 好吧,他并没有说它经常发生,我认为它有一些高峰!
    • 如果 fps 计算中的关键问题是时间变化cvtColor,我认为不会使用“在实时流中显示 40-50 [fps]”来描述观察到的 fps 值需要。可以将其描述为,例如,“在 30 fps 左右存在一些变化。”
    【解决方案3】:

    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 &gt;&gt; raw 返回后立即测量时间点,该时间点(不会与 OpenCV 混淆)是相机发送帧时最接近的时间点,并且每个循环仅测量一次时间并进行比较与之前的测量相比,它给出了非常精确的当前帧速率。当然,如果处理时间超过 1/(帧速率),则测量将关闭。

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

    【讨论】:

    • 函数调用会是什么样子?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多