Method 1 of c++ in qt to obtain real-time display of picture qml - inheriting QQuickPaintedItem

Obtain rtsp video stream or video source through c++ opencv, and display real-time video on qml.

1. Dynamically load pictures through QQuickPaintedItem in QML

In QML, you can use QQuickPaintedItemto create custom drawables. By inheriting QQuickPaintedItemthe class, we can dynamically load pictures and draw them in QML. In this blog, we will learn how to use QQuickPaintedItemLoad and draw images.

1. opecv gets video stream picture

.proIntroduce opencv in the file

#windows
INCLUDEPATH +=D:\soft\opencv3.4.0\OpenCV-MinGW-Build-OpenCV-3.4.5\include
              D:\soft\opencv3.4.0\OpenCV-MinGW-Build-OpenCV-3.4.5\include\opencv
              D:\soft\opencv3.4.0\OpenCV-MinGW-Build-OpenCV-3.4.5\include\opencv2


LIBS +=D:\soft\opencv3.4.0\OpenCV-MinGW-Build-OpenCV-3.4.5\x86\mingw\bin\libopencv_*.dll

Create a thread class myThreadfor getting pictures
myThread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H
#include "QThread"
#include <QTimer>
#include <QImage>
#include <QMutex>

#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>

#include<QtNetwork/QNetworkRequest>
#include<QtNetwork/QNetworkReply>
#include<QtNetwork/QNetworkAccessManager>

class myThread : public QThread
{
    
    
    Q_OBJECT

public:
    explicit myThread(QObject *parent = nullptr);
    myThread(QString url);

protected:
    void run() override;


private:

    cv::VideoCapture video;         // 视频抓取
    cv::Mat src_frame;              // mat类用于存储矩阵类型数据,这里用来存储图像
    QString rtsp;                   // rtsp地址
    bool isStop=false;              // 线程是否运行
    QImage image;

    QNetworkAccessManager * manager;


signals:

    void sendArray(QImage qimg); // 发送图片的信号
    void sendImg(QImage qimg);         // 发送空白图片

public slots:

    void getFrame();            // 获取图像
    void closeFrame();          // 关闭画面
    void closeThread();         // 关闭线程
};

#endif // MYTHREAD_H

myThread.cpp

#include "mythread.h"
#include "QDebug"


myThread::myThread(QObject *parent) : QThread(parent)
{
    
    

    manager=new QNetworkAccessManager(this);
}

myThread::myThread(QString url)
{
    
    
    rtsp=url;

}

void myThread::run()
{
    
    

    qDebug() << "线程开始执行:"<< QThread::currentThread()<<rtsp;
    //  rtsp读取网络视频
    video=cv::VideoCapture(rtsp.toStdString());
    if(video.isOpened())
    {
    
    
        while (!isStop) {
    
    
            getFrame();
            msleep(25);
        }
        if(isStop){
    
    
            closeFrame();
            isStop=false;
        }
    }
}

// 关闭线程
void myThread::closeThread(){
    
    

    isStop=true;
    qDebug() << __FUNCTION__;
}

// 关闭画面
void myThread::closeFrame(){
    
    
    qDebug() << __FUNCTION__;
    emit sendImg(QImage(":/Image/Button/013.png"));
}

// 图像处理
void myThread::getFrame()
{
    
    

    video>>src_frame; //从视频取帧
    // mat to qimage
    if(src_frame.rows>0 && src_frame.cols>0){
    
    
        if(src_frame.channels() == 3) {
    
    
            // RGB image
            cvtColor(src_frame,src_frame,CV_BGR2RGB);
            image = QImage((const uchar*)(src_frame.data),  //(const unsigned char*)
                           src_frame.cols,src_frame.rows,
                           src_frame.cols*src_frame.channels(),   //new add
                           QImage::Format_RGB888);
        }

        else {
    
    
            // gray image
            image = QImage((const uchar*)(src_frame.data),
                           src_frame.cols,src_frame.rows,
                           src_frame.cols*src_frame.channels(),
                           QImage::Format_Indexed8);
        }

        // 发送信号
        emit sendArray(image);
    }else{
    
    
        qDebug() << __FUNCTION__<<"null";

    }
}



2. Create a custom drawing item –ShowImage.h

First, we need to create a custom drawable item class. In this class, we will override QQuickPaintedItemthe paintmethods to implement the drawing logic.

ShowImage.h

#ifndef SHOWIMAGE_H
#define SHOWIMAGE_H

#include <QObject>
#include <QQuickPaintedItem>
#include <QImage>
#include <QPainter>

#include <mythread.h>

// qml 实时加载图片第一种方式--继承QQuickPaintedItem,自定义绘制
class ShowImage : public QQuickPaintedItem
{
    
    
    Q_OBJECT
public:
    explicit ShowImage(QQuickItem *parent = nullptr);

public slots:
    void updateImage(const QImage &);
    void start_camera(QString rtsp);
    void close_camera();

signals:
    void close_thread();

protected:
    void paint(QPainter *painter);

private:
    QImage m_imageThumb;
    QImage image_null=QImage(":/image/test.png");  // 默认图片
    myThread *m_thread=nullptr;  

};

#endif // SHOWIMAGE_H

3. Implement custom drawing items

Next, we need to implement the logic for custom drawing items.
ShowImage.cpp

#include "showimage.h"

ShowImage::ShowImage(QQuickItem *parent)
{
    
    
    //默认图片
    m_imageThumb = image_null;
}

// 更新图片
void ShowImage::updateImage(const QImage &image)
{
    
    
    m_imageThumb = image;
    update();
}
// 开启视频捕获
void ShowImage::start_camera(QString rtsp)
{
    
    
    if(m_thread!=nullptr){
    
    
        close_camera();
    }
    m_thread=new myThread(rtsp);
    connect(m_thread,&myThread::sendArray,this,&ShowImage::updateImage);
    connect(m_thread,&myThread::sendImg,this,&ShowImage::updateImage);
    connect(this,&ShowImage::close_thread,m_thread,&myThread::closeThread);
    m_thread->start();

}
// 关闭视频捕获
void ShowImage::close_camera()
{
    
    
    qDebug() <<__FUNCTION__;
    emit close_thread();
    if(m_thread!=nullptr){
    
    
        m_thread->quit();
        m_thread->wait();
        delete m_thread;
        m_thread=nullptr;
    }
}

// 图片绘制
void ShowImage::paint(QPainter *painter)
{
    
    
    if(!m_imageThumb.isNull()){
    
    
        painter->drawImage(this->boundingRect(), m_imageThumb);
    }else{
    
    
        painter->drawImage(this->boundingRect(), QImage(image_null));
    }
}




4. Register the custom drawing class in main.cpp

main.cppRegister custom classes in qml for use

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include <showimage.h>
#include "myimageprovider.h"

int main(int argc, char *argv[])
{
    
    
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    // 获取上下文对象
    QQmlContext *context=engine.rootContext();
    // 注册自定义类
    qmlRegisterType<ShowImage>("ShowImage",1,0,"ShowImage");

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
    
    
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    
    return app.exec();
}

5. Use custom drawing class in qml

main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.0

import ShowImage 1.0  // 导入自定义模块
Window {
    
    
    visible: true
    width: screenW
    height: 480
    title: qsTr("Hello World")

    // 第一种方式--使用自定义模块
    ShowImage{
    
    
        anchors.fill: parent
        id : showimg
        transformOrigin: Item.Center
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
    }

    Button {
    
    
        id:ok
        text: "相机"
        anchors.left: parent.left
        anchors.leftMargin: 20
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 50
        width: parent.width*0.2
        height: 50

        signal start_time_qml()   // 定义信号
        Connections {
    
    			  // 连接信号与槽
            target: ok
            onStart_time_qml: {
    
    
                showimg.start_camera("rtsp://admin:[email protected]/smart265/ch1/main/av_stream")
            }
        }
        onClicked: {
    
    
            ok.start_time_qml()
        }
    }

    Button {
    
    
        id:video
        text: "视频源"
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 50
        width: parent.width*0.2
        height: 50
        x:parent.width*0.32

        signal start_video_qml()
        Connections {
    
    
            target: video
            onStart_video_qml: {
    
    
                showimg.start_camera("H:\\360MoveData\\Users\\Administrator\\Desktop\\11.mp4")
            }
        }
        onClicked: {
    
    
            video.start_video_qml()
        }
    }

    Button {
    
    
        id:clear
        text: "关闭"
        anchors.right: parent.right
        anchors.rightMargin: 20
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 50
        width: parent.width*0.2
        height: 50
        x:parent.width*0.62

        signal clear_time_qml()
        Connections {
    
    
            target: clear
            onClear_time_qml: {
    
    
                showimg.close_camera()
            }
        }
        onClicked: {
    
    
            clear.clear_time_qml()
        }
    }
}

6. Run the program

Now, you can run the application and click the corresponding button to dynamically load and display the image. When you click the button, the method ShowImagewill be used updateImageto load the picture with the specified path and draw it on the interface.

insert image description here

Take playing a video as an example:

qml real-time display

QQuickPaintedItemThis is the basic step of dynamically loading pictures in QML . You can further customize the functionality and appearance of custom draw items as needed.

Hope this blog is helpful to you! If you have any questions, please feel free to ask.

source code

Guess you like

Origin blog.csdn.net/ljn1046016768/article/details/131332297