2017-11-03 4 views
0

Ich habe ein Problem OpenCv Mat von anderen Thread zu lesen und es in QML anzuzeigen.OpenCV + QML (Rahmen von einem anderen Thread)

Zunächst erstelle ich Mat in anderen Thread und verhindern, dass es aktualisieren, bis QML wird es nicht angezeigt werden:

void DesktopVideoProducer::process(){ 
    while(true){ 
     if(!camera.isOpened()) 
     camera.open("http://192.168.43.1:8080/video"); 
     camera >> mat; 
     if(!frameReady && !mat.empty()){ 
     outMat = cv::Mat(10, 10, 1); 
     qDebug() << "!!!! = " << outMat.data; 
     frameReady = true; 
     } 
    } 
} 

In qDebug() << "!!!! = " << outMat.data; ich sehe, dass outMat Daten hat !!!! = 0x38824980

Hier versuche ich, diese Matte angezeigt werden in QML:

void DesktopVideoProducer::timerEvent(QTimerEvent*) 
{ 
    if (!_surface) return; 

    if(frameReady) 
    qDebug() << "ddd = " << outMat.data; 

    if(frameReady && !outMat.empty()) 
    { 
      cv::cvtColor(outMat, outMat, cv::COLOR_BGR2BGRA); 

      QImage screenImage((uchar*)outMat.data, outMat.cols, outMat.rows, outMat.step, QImage::Format_RGB32); 

      if(QSize(winWidth, winHeight) != _format.frameSize()) 
      { 
       qDebug() << "newSize"; 
       closeSurface(); 
       _format = QVideoSurfaceFormat(QSize(winWidth, winHeight), QVideoFrame::PixelFormat::Format_RGB32); 
       _surface->start(_format); 
      } 

      _surface->present(QVideoFrame(screenImage)); 

      frameReady = false; 
    } 
} 

Aber wenn ich versuche Mat hier zu lesen:

if(frameReady) 
    qDebug() << "ddd = " << outMat.data; 

es zeigt, dass keine Daten in diesem outMat: ddd = 0x0

Und ich kann nicht ohne einen Frame von einem anderen Thread angezeigt werden soll. Hier ist mein Code:

DesktopVideoProducer.h

#include <QQmlApplicationEngine> 
#include <QAbstractVideoSurface> 
#include <QVideoSurfaceFormat> 
#include <QTimer> 
#include <QTime> 
#include <opencv2/opencv.hpp> 

class DesktopVideoProducer : public QObject 
{ 
    Q_OBJECT 
    Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface WRITE setVideoSurface) 
public: 
    explicit DesktopVideoProducer(QObject *parent = 0); 
    ~DesktopVideoProducer(); 

    QAbstractVideoSurface* videoSurface() const; 
    void setVideoSurface(QAbstractVideoSurface* s); 
    void Initialization(); 

public slots: 
void timerEvent(QTimerEvent*); 

private: 
    void closeSurface(); 

private: 
    QAbstractVideoSurface* _surface; 
    QVideoSurfaceFormat _format; 
    QQmlApplicationEngine engine; 
    cv::VideoCapture camera; 
    cv::Mat mat; 
    cv::Mat outMat; 
    QImage screenImage; 
    void process(); 
}; 

DesktopVideoProducer.cpp

#include "DesktopVideoProducer.h" 
#include <QApplication> 
#include <QtConcurrent/QtConcurrent> 
#include <QDebug> 
#include <QMutex> 

QMutex mutex; 
int winWidth, winHeight; 
bool isInit = false; 
bool frameReady = false; 

DesktopVideoProducer::DesktopVideoProducer(QObject *parent) 
    : QObject(parent), _surface(nullptr) 
{ 
    startTimer(1000/15); //15 fps 
} 

DesktopVideoProducer::~DesktopVideoProducer() 
{ 
    closeSurface(); 
} 

QAbstractVideoSurface* DesktopVideoProducer::videoSurface() const 
{ 
    return _surface; 
} 

void DesktopVideoProducer::Initialization(){ 
    engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); 

    QtConcurrent::run(this, DesktopVideoProducer::process); 

    winWidth = engine.rootObjects()[0]->property("width").toInt(); 
    winHeight = engine.rootObjects()[0]->property("height").toInt(); 
} 

void DesktopVideoProducer::process(){ 

    while(true){ 
     if(!camera.isOpened()) 

     camera.open("http://192.168.43.1:8080/video"); 

     camera >> mat; 

     if(!frameReady && !mat.empty()){ 
     outMat = cv::Mat(10, 10, 1); 
     qDebug() << "!!!! = " << outMat.data; 
     frameReady = true; 

     } 
    } 
} 

void DesktopVideoProducer::setVideoSurface(QAbstractVideoSurface* s) 
{ 
    closeSurface(); 
    _surface = s; 
} 

void DesktopVideoProducer::closeSurface() 
{ 
    if(_surface && _surface->isActive()) 
     _surface->stop(); 
} 

void DesktopVideoProducer::timerEvent(QTimerEvent*) 
{ 
    if (!_surface) return; 

    if(frameReady) 
    qDebug() << "ddd = " << outMat.data; 

    if(frameReady && !outMat.empty()) 
    { 
      cv::cvtColor(outMat, outMat, cv::COLOR_BGR2BGRA); 

      QImage screenImage((uchar*)outMat.data, outMat.cols, outMat.rows, outMat.step, QImage::Format_RGB32); 

      if(QSize(winWidth, winHeight) != _format.frameSize()) 
      { 
       qDebug() << "newSize"; 
       closeSurface(); 
       _format = QVideoSurfaceFormat(QSize(winWidth, winHeight), QVideoFrame::PixelFormat::Format_RGB32); 
       _surface->start(_format); 
      } 

      _surface->present(QVideoFrame(screenImage)); 

      frameReady = false; 
    } 
} 

Main.cpp

#include <QApplication> 
#include <QQmlApplicationEngine> 

#include"DesktopVideoProducer.h" 

int main(int argc, char *argv[]) 
{ 
    QApplication app(argc, argv); 

    qmlRegisterType<DesktopVideoProducer>("DesktopVideoProducer", 0, 1, "DesktopVideoProducer"); 

    DesktopVideoProducer videoProvider; 

    videoProvider.Initialization(); 

    return app.exec(); 
} 

main.qml

import QtQuick 2.2 
import QtQuick.Window 2.1 
import QtMultimedia 5.0 
import DesktopVideoProducer 0.1 

Window { 
    visible: true 
    visibility: "Maximized" 
    id: root 

    DesktopVideoProducer { 
     id: videoProducer; 
    } 

    VideoOutput { 
     anchors.fill: parent 
     source: videoProducer; 
    } 
} 

Was soll ich tun?

Antwort

1

Dieses Stück Code wahrscheinlich falsch ist und impliziert die außer Kraft gesetzt Quelle während Konvertierung durchgeführt:

cv::cvtColor(outMat, outMat, cv::COLOR_BGR2BGRA); 

Die Umwandlung sollte mich mehr wie:

cv::Mat outFrame; 
cvtColor(inFrame, outFrame, conversionType); // cvtColor makes copy 
+0

Natürlich kann es die Debug-Sitzung usw. wert Der Zweck von SO besteht jedoch darin, Codierungshinweise zu finden. Versuchen Sie ein funktionierendes Beispiel und führen Sie es aus und beginnen Sie, es Stück für Stück zu ändern, schätze ich. 'QtConcurrent' wird hier vielleicht nicht benötigt. Es ist keine massive Parallelverarbeitung. Verwende 'QThread'. – AlexanderVX

+0

Wirklich, ich fand, dass diese Methode 'cv :: Mat outFrame; cvtColor (inFrame, outFrame, conversionType); 'arbeiten schneller als das' cv :: cvtColor (outMat, outMat, cv :: COLOR_BGR2BGRA); '. Vielen Dank! – DYY

+0

M ... also nicht sicher, wie die Konvertierung dieses "in-place" outMat -> outMat überhaupt überhaupt funktioniert hat. Das ist ein Geheimnis. – AlexanderVX

Verwandte Themen