计算出的 fps 如何大于相机声明的 fps?
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);
}
Camera's 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();
}
}
你中间有一个cvtColor
,所以它会影响你的时间计算,因为cvtColor
的过程时间在每个循环中可能会有所不同(可能是因为windows的其他过程).
Consider this example:
You get the first frame with capture
at moment 0, then do a
cvtColor
and that takes e.g. 10 ms, then you make a stopTime
at
moment 10 ms. 23 ms later (33-10) you capture
the second frame. But
this time cvtColor
takes 5 ms (It could happen) and you make the
second stopTime
at moment 38 (33+5), so the first tick was at moment
10 and the second tick is at moment 38. Now your fps becomes
1000/(38-10) = 35.7
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
returns 之后的时间点,这(不影响 OpenCV)是相机发送帧时最接近的时间点,并且时间每个循环仅测量一次并与之前的测量结果进行比较,这给出了非常精确的当前帧速率。当然,如果处理时间超过1/(帧率),测量将关闭。
问题的代码给出过高帧率的原因实际上是两次时间测量之间的代码:showFPS()
中的 now()
和 [=15 中的 now()
=] 循环。我的预感是这个代码包含 cv::imshow()
,它不在问题中,并且与 cv::waitKey(5)
和 cv::putText()
一起可能负责帧速率计算中的大部分 "missing time" (导致帧率过高)。
我正在尝试测量处理来自相机的帧时的每秒帧数。计算没什么特别的,可以在这个问题中找到:
更新:代码:
#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);
}
Camera's 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();
}
}
你中间有一个cvtColor
,所以它会影响你的时间计算,因为cvtColor
的过程时间在每个循环中可能会有所不同(可能是因为windows的其他过程).
Consider this example:
You get the first frame with
capture
at moment 0, then do acvtColor
and that takes e.g. 10 ms, then you make astopTime
at moment 10 ms. 23 ms later (33-10) youcapture
the second frame. But this timecvtColor
takes 5 ms (It could happen) and you make the secondstopTime
at moment 38 (33+5), so the first tick was at moment 10 and the second tick is at moment 38. Now your fps becomes1000/(38-10) = 35.7
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
returns 之后的时间点,这(不影响 OpenCV)是相机发送帧时最接近的时间点,并且时间每个循环仅测量一次并与之前的测量结果进行比较,这给出了非常精确的当前帧速率。当然,如果处理时间超过1/(帧率),测量将关闭。
问题的代码给出过高帧率的原因实际上是两次时间测量之间的代码:showFPS()
中的 now()
和 [=15 中的 now()
=] 循环。我的预感是这个代码包含 cv::imshow()
,它不在问题中,并且与 cv::waitKey(5)
和 cv::putText()
一起可能负责帧速率计算中的大部分 "missing time" (导致帧率过高)。