Насколько рассчитанный fps может быть больше, чем заявленный fps камеры? - PullRequest
0 голосов
/ 12 января 2019

Я пытаюсь измерить число кадров в секунду при обработке кадра с камеры. Вычисления не являются чем-то особенным и могут быть найдены в этом вопросе: Как написать функцию с параметром, тип которого выводится с помощью слова 'auto'? Моя камера довольно старая, и заявленный производителем 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 голосов
/ 16 января 2019

У вас есть cvtColor между ними, так что это влияет на ваши вычисления времени, потому что время процесса cvtColor может варьироваться в каждом цикле (возможно, из-за других процессов окон).

Рассмотрим этот пример:

Вы получите первый кадр с capture в момент 0, затем выполните cvtColor и это занимает, например, 10 мс, затем вы делаете stopTime в момент 10 мс. Через 23 мс (33-10) вы capture второй кадр. Но на этот раз cvtColor занимает 5 мс (это может произойти), и вы делаете второй stopTime в момент 38 (33 + 5), поэтому первый тик был в момент 10 и второй тик в момент 38. Теперь ваш fps становится

1000 / (38-10) = 35,7

0 голосов
/ 18 января 2019

Ответ Алексея Петрова неплохой, но, хотя усреднение по последним 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(), вероятно, ответственен за большую часть "пропущенного времени" в расчете частоты кадров (вызывая слишком высокую частоту кадров ).

0 голосов
/ 15 января 2019

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();
  }
}
...