OpenCV + QML(从另一个线程获取框架) [英] OpenCV + QML (grabbing frame from another thread)

查看:117
本文介绍了OpenCV + QML(从另一个线程获取框架)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在从其他线程读取OpenCv Mat并将其显示在QML中时遇到问题.

I have a problem to read OpenCv Mat from other thread and display it in QML.

首先,我在其他线程中创建Mat,并阻止对其进行更新,直到QML将其显示出来为止:

Firstly I create Mat in other thread and prevent update it until QML will not display it:

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;
        }
    }
}

qDebug() << "!!!! = " << outMat.data;中,我看到outMat有数据!!!! = 0x38824980

In qDebug() << "!!!! = " << outMat.data; I see that outMat has data !!!! = 0x38824980

在这里,我尝试在QML中显示此Mat:

Here I try to display this Mat 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;
    }
}

但是当我尝试在此处阅读Mat时:

But when I try to read Mat here:

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

它表明没有数据在垫子中:ddd = 0x0

it show that no data in this outMat: ddd = 0x0

我无法显示来自另一线程的一帧图像. 这是我的代码:

And I can't to display no one frame from another thread. Here is my code:

DesktopVideoProducer.h

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

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;
    }
}

我该怎么办?

推荐答案

这段代码可能不正确,并且暗示在执行转换时源将被覆盖:

This piece of code is likely incorrect and implies the source overridden while conversion performed:

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

我应该更喜欢这种转换:

The conversion should me more like:

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

这篇关于OpenCV + QML(从另一个线程获取框架)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆