[英]How calculated fps can be greater than camera's declared fps?
我正在尝试从相机处理帧时测量每秒帧数。 计算没有什么特别的,可以在以下问题中找到: 如何编写带有参数的函数,该参数的类型由“自动”字推导出? 我的相机很旧,制造商宣称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);
}
相机的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();
}
}
亚历山大·彼得罗夫(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()
可能是导致代码丢失的大部分时间帧速率计算(导致帧速率太高)。
您之间有一个cvtColor
,因此它会影响您的时间计算,因为cvtColor
的处理时间可能在每个循环中有所不同(可能是由于Windows的其他处理)。
考虑以下示例:
您在0时刻获取了
capture
的第一帧,然后执行cvtColor
并花费了10毫秒,然后在10毫秒获取了stopTime
。 23 ms(33-10)之后,您capture
了第二帧。 但是这次cvtColor
需要5毫秒(可能会发生),您在38时刻(33 + 5)设置了第二个stopTime
,所以第一个刻度在第10时刻,第二个刻度在第38时刻。现在,您的fps变为1000 /(38-10)= 35.7
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.