利用QQuickImageProvider发送cv::Mat及QImage图片至qml上显示
第一步,继承QQuickImageProvider
新建一个类继承QQuickImageProvider,并重写函数 requestImage 及 requestPixmap。
class ImageProvider : public QQuickImageProvider
{
public:
ImageProvider();
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize);
QImage img;
};
ImageProvider::ImageProvider() : QQuickImageProvider(QQuickImageProvider::Image)
{
}
QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
return this->img;
}
QPixmap ImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
return QPixmap::fromImage(this->img);
}
第二步,新建一个类用来调用QQuickImageProvider继承类
这里主要是调用第一步创建的继承类ImageProvider ,创建三个函数用来处理Mat、QImage、QString图片路径。
class ShowImage : public QObject
{
Q_OBJECT
public:
ShowImage();
~ShowImage();
ImageProvider *m_pImgProvider;
QImage cvMat2QImage(cv::Mat mat);
public slots:
void sendimage(QImage);
void sendimage(cv::Mat);
void sendimage(QString);
private:
signals:
void callQmlRefreshImg();
};
第三步,写一个Demo用来测试
创建一个线程,循环显示三张图片,分别用三种格式向qml发送图片。
void Demo::run()
{
// 拿三张图片用来测试
QStringList imageList;
imageList << "E:/work/Image/Dog/1.jpg"
<< "E:/work/Image/Dog/2.jpeg"
<< "E:/work/Image/Dog/3.jpeg";
int currentIndex = 0;
while(demoRunning){
if(currentIndex == 0){
currentIndex = 1;
showImage->sendimage(imageList[0]);
} else if(currentIndex == 1){
currentIndex = 2;
cv::Mat mat = cv::imread(imageList[1].toStdString().data());
showImage->sendimage(mat);
} else {
currentIndex = 0;
QImage image(imageList[2]);
showImage->sendimage(image);
}
sleep(4);
}
}
源码
ImageToQml.h
#ifndef IMAGETOQML_H
#define IMAGETOQML_H
#include <QObject>
#include <QDebug>
#include <QPixmap>
#include <QImage>
#include <QQuickImageProvider>
#include <opencv.hpp>
class ImageProvider : public QQuickImageProvider
{
public:
ImageProvider();
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize);
QImage img;
};
class ShowImage : public QObject
{
Q_OBJECT
public:
ShowImage();
~ShowImage();
ImageProvider *m_pImgProvider;
QImage cvMat2QImage(cv::Mat mat);
public slots:
void sendimage(QImage);
void sendimage(cv::Mat);
void sendimage(QString);
private:
signals:
void callQmlRefreshImg();
};
#endif // IMAGETOQML_H
ImageToQml.cpp
#include "ImageToQml.h"
ImageProvider::ImageProvider() : QQuickImageProvider(QQuickImageProvider::Image)
{
}
QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
return this->img;
}
QPixmap ImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
return QPixmap::fromImage(this->img);
}
ShowImage::ShowImage()
{
m_pImgProvider = new ImageProvider();
}
ShowImage::~ShowImage()
{
if(m_pImgProvider != nullptr){
delete m_pImgProvider;
m_pImgProvider = nullptr;
}
}
void ShowImage::sendimage(QImage img)
{
m_pImgProvider->img = img;
emit callQmlRefreshImg();//告诉qml刷新一下。
}
void ShowImage::sendimage(cv::Mat mat)
{
QImage img = cvMat2QImage(mat);
sendimage(img);
}
void ShowImage::sendimage(QString imgFile)
{
QImage img(imgFile);
sendimage(img);
}
QImage ShowImage::cvMat2QImage(cv::Mat mat)
{
switch(mat.type()){
case CV_8UC1:{
QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
image.setColorCount(256);
for(int i = 0; i < 256; i++){
image.setColor(i,qRgb(i,i,i));
}
uchar *pSrc = mat.data;
for(int row = 0; row < mat.rows; row++){
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc,mat.cols);
pSrc += mat.step;
}
return image;
}
case CV_8UC3:{
const uchar *pSrc = (const uchar*)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
case CV_8UC4:{
const uchar *pSrc = (const uchar*)mat.data;
QImage image(pSrc,mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
return image.copy();
break;
}
default:
return QImage();
}
}
Demo.h
#ifndef DEMO_H
#define DEMO_H
#include <QObject>
#include <QThread>
#include <opencv.hpp>
#include "ImageToQml.h"
class Demo : public QThread
{
Q_OBJECT
public:
explicit Demo(QObject *parent = nullptr);
~Demo();
void startDemo();
ShowImage *getShowImage() { return showImage; }
protected:
void run();
private:
ShowImage *showImage = NULL;
bool demoRunning = false;
signals:
void sigRefreshImage();
};
#endif // DEMO_H
Demo.cpp
#include "Demo.h"
Demo::Demo(QObject *parent) : QThread(parent)
{
showImage = new ShowImage();
connect(showImage, SIGNAL(callQmlRefreshImg()), this, SIGNAL(sigRefreshImage()));
}
Demo::~Demo()
{
showImage->deleteLater();
showImage = NULL;
demoRunning = false;
this->quit();
this->wait();
}
void Demo::startDemo()
{
demoRunning = true;
this->start();
}
void Demo::run()
{
// 拿三张图片用来测试
QStringList imageList;
imageList << "E:/work/Image/Dog/1.jpg"
<< "E:/work/Image/Dog/2.jpeg"
<< "E:/work/Image/Dog/3.jpeg";
int currentIndex = 0;
while(demoRunning){
if(currentIndex == 0){
currentIndex = 1;
showImage->sendimage(imageList[0]);
} else if(currentIndex == 1){
currentIndex = 2;
cv::Mat mat = cv::imread(imageList[1].toStdString().data());
showImage->sendimage(mat);
} else {
currentIndex = 0;
QImage image(imageList[2]);
showImage->sendimage(image);
}
sleep(4);
}
}
main.cpp
#include <QQmlContext>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <Demo.h>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
Demo demo;
demo.startDemo();
engine.rootContext()->setContextProperty("Demo", &demo);
engine.addImageProvider(QLatin1String("MyImg"), demo.getShowImage()->m_pImgProvider);
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();
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Image {
id: image
anchors.fill: parent
anchors.centerIn: parent
fillMode: Image.PreserveAspectFit
cache: false
}
Connections {
target: Demo
function onSigRefreshImage() {
image.source = ""
image.source = "image://MyImg"
}
}
}