Problem z uzyskaniem więceij niż 25FPS z kamery internetowej

0

Tak jak w temacie pisze program korzystając z OpenCV oraz Qt C++. W tym momencie próbuje uzyskać większą płynność wyświetlanego obrazu z kamery internetowej Logitech C920. Kamera pozwala na wyświetlanie obrazu Full HD z 30FPS co potwierdza komenda v4l2-ctl -d /dev/video0 --list-formats-ext. Jednak w mojej sytuacji bardzo często występuje sytuacja że pobranie ramki zajmuje więcej niż 33ms (1000ms/30FPS=33ms), inna sprawa to znaczne obciążenie procesora (rdzeni).

Plik main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

Plik mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(&processor, SIGNAL(inDisplay(QPixmap)), ui->inVideo, SLOT(setPixmap(QPixmap)));
    processor.start(QThread::HighestPriority);
}

MainWindow::~MainWindow()
{
    processor.requestInterruption();
    processor.wait();
    delete ui;
}

Plik videoprocessorthread.cpp

#include "videoprocessorthread.h"

#include <iostream>
#include <string>

VideoProcessorThread::VideoProcessorThread()
{
    
}

void VideoProcessorThread::run()
{
    using namespace cv;
    VideoCapture camera(0 + CAP_ANY);
    camera.set(CV_CAP_PROP_FRAME_WIDTH, 1920);
    camera.set(CV_CAP_PROP_FRAME_HEIGHT, 1080);
    camera.set(CV_CAP_PROP_FPS,30);
    //    camera.set(CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G'));
    //    camera.set(CAP_PROP_FOURCC, CV_FOURCC('H', '2', '6', '4'));
    
    Mat inFrame;
    while (camera.isOpened() && !isInterruptionRequested()) {
        myTimer1.start();
        playFrameFPS = camera.get(CV_CAP_PROP_FPS);
        //        camera >> inFrame;
        camera.read(inFrame);
        if(inFrame.empty())
            continue;
        
        emit inDisplay(QPixmap::fromImage(QImage(inFrame.data, inFrame.cols, inFrame.rows, inFrame.step, QImage::Format_RGB888).rgbSwapped()));
        
        timeReadFrame = myTimer1.elapsed();
        timeSleepThread = (static_cast<int>(1000.0/playFrameFPS) - timeReadFrame);
        
        qDebug() << "FPS:" << playFrameFPS << "|| t odczyt:" << static_cast<int>(1000.0/playFrameFPS) << "ms" << "|| t odczytu z kamery:" << timeReadFrame << "ms" << timeSleepThread;
        
        if (timeSleepThread>0) {
            qDebug() << "odpoczywam :P";
            this->msleep(timeSleepThread);
        }
    }
}

Ważne informacje:

  • program piszę po linuxem zatem obsługa kamery jest realizowana poprzez v4l2
  • główne opóźnienie bo wynoszące nawet 90% przewidzianego czasu na odczyt zajmuje camera.read(inFrame). Stwierdzone po wykomentowaniu wszystkiego co zbędne łącznie z samym wyświetlaniem obrazu.
  • zwiększenie czasu odczytu występuje wówczas gdy obraz jest niedoświetlony

Moje pytania:

  • jak zmusić kamerę aby był możliwy odczyt z wykorzystaniem MJPG lub H264 bo poleceni camera.set(CAP_PROP_FOURCC, CV_FOURCC('H', '2', '6', '4')) nic nie zmienia
  • czy jest możliwość uzyskania płynnych 30FPS z Full HD na USB2.0 bez znacznego obciążania procesora
  • a jaki wam się udało uzyskać wskaźnik FPS przy Full HD
  • może ma ktoś jakiś pomysł jak poprawić kod aby przetwarzanie było bardziej płynne oraz mnie obciążające CPU
0

Tutaj jest błąd:

    while (camera.isOpened() && !isInterruptionRequested()) {
        myTimer1.start();
        playFrameFPS = camera.get(CV_CAP_PROP_FPS);
        //        camera >> inFrame;
        camera.read(inFrame);
        if(inFrame.empty())
            continue;

Czy wywołania read oraz get są blokujące?

Sleep jest nie w tym miejscu co trzeba. Powinien być pomiędzy while a continue.
Druga sprawa to timer.

0

Co masz na myśli pytając czy read oraz get są blokujące? Jeśli chodzi o blokowanie programu to oczywiście program a dokładniej wątek w którym odczyt jest realizowany blokuje się czekając na informacje zwrotną z get czy read.
Sleep jest na samym końcu whila bo ma na celu usypiać wątek w momencie gdy odczyt został zrealizowany szybciej niż kolejna ramka będzie gotowa do odczytu z kamery.
Natomiast timer jest używany tylko do określania jak długo wykonywał się dany fragment kodu aby następnie wiedzieć na ile czasu wątek może być uśpiony.

Na przykład jeśli kamera pracuje z 30FPS to nowa ramka z obrazem jest co 33ms, jeśli odczyt zajął nam 25ms zatem wątek może być uśpiony na 8ms.

2
zwiększenie czasu odczytu występuje wówczas gdy obraz jest niedoświetlony

To jest zdaje się normalne. Jeśli nie ma światła to kamera to rekompensuje dłuższym czasem naświetlania.

https://www.sighthound.com/support/video-jerky-low-frame-rate-was-detected-camera

Cameras sometimes adjust to very dark scenes by lowering the frame rate in order to maximize light entering the camera. Additional light at night can help this.

Dlatego bez oświetlenia możesz nie mieć 30 fpsów. Ewentualnie możesz zmienić ustawienia kamery, tylko wtedy przez brak światła nic nie będzie widać.

1 użytkowników online, w tym zalogowanych: 0, gości: 1