首页 > 其他分享 >【QML】用 Image(QQuickPaintedItem) 显示图片

【QML】用 Image(QQuickPaintedItem) 显示图片

时间:2024-06-23 17:56:38浏览次数:23  
标签:name parent Image void QML inMat include image QQuickPaintedItem

  1. 大体功能:
  • 频繁地往界面推送图片,帧率达到视频效果。
  • 捕获画布上的鼠标事件和键盘事件。
  1. 代码如下:
// DrawImageInQQuickPaintedItem.pro 代码如下:
QT += quick

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        drawimagectrl.cpp \
        imagepainter.cpp \
        main.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    drawimagectrl.h \
    imagepainter.h

LIBS += -lopencv_core \
        -lopencv_imgcodecs


// imagepainter.h 代码如下:
#ifndef IMAGEPAINTER_H
#define IMAGEPAINTER_H

#include <QQuickPaintedItem>
#include <QImage>

#define QML_WRITABLE_PROPERTY(type, name) \
    protected: \
        Q_PROPERTY (type name READ get_##name WRITE set_##name NOTIFY name##Changed) \
        type m_##name; \
    public: \
        type get_##name () const { \
            return m_##name ; \
        } \
    public Q_SLOTS: \
        bool set_##name (type name) { \
            bool ret = false; \
            if ((ret = m_##name != name)) { \
                m_##name = name; \
                emit name##Changed (m_##name); \
            } \
            return ret; \
        } \
    Q_SIGNALS: \
        void name##Changed (type name); \
    private:

class MyQImage : public QObject
{
    Q_OBJECT
public:
    explicit MyQImage(QObject *parent = nullptr) : QObject(parent) {}
    ~MyQImage() = default;

    void setImage(const QImage &img) { m_img = img; }
    const QImage &getImage() const { return m_img; }

private:
    QImage m_img;
};

class ImagePainter : public QQuickPaintedItem
{
    Q_OBJECT
    QML_WRITABLE_PROPERTY(MyQImage*, pImage)
    QML_WRITABLE_PROPERTY(int, nFillMode)

public:
    explicit ImagePainter(QQuickItem *parent = nullptr);

    void paint(QPainter *painter) override;
};

#endif // IMAGEPAINTER_H


// imagepainter.cpp 代码如下:
#include "imagepainter.h"
#include <QPainter>

ImagePainter::ImagePainter(QQuickItem *parent)
    : QQuickPaintedItem(parent)
    , m_pImage(nullptr)
    , m_nFillMode(0)
{
    connect(this, &ImagePainter::pImageChanged,
            [this]{
        if(m_pImage) {
            setImplicitWidth(m_pImage->getImage().width());
            setImplicitHeight(m_pImage->getImage().height());
        }
        else {
            setImplicitWidth(0);
            setImplicitHeight(0);
        }

        update();
    });
}

void ImagePainter::paint(QPainter *painter)
{
    if(m_pImage) {
        const QImage &image = m_pImage->getImage();
        if (image.isNull()) {
            return;
        }
        switch (m_nFillMode) {
        case 1 /* PreserveAspectFit */: {
            QImage scaledImage = image.scaled(width(), height(), Qt::KeepAspectRatio);
            double x = (width() - scaledImage.width()) / 2;
            double y = (height() - scaledImage.height()) / 2;
            painter->drawImage(QPoint(x, y), scaledImage);
            break;
        }
        case 0 /* Stretch */:
        default: {
            painter->drawImage(QPoint(0, 0), image.scaled(width(), height()));
        }
        }
    }
}


// drawimagectrl.h 代码如下:
#ifndef DRAWIMAGECTRL_H
#define DRAWIMAGECTRL_H

#include <QObject>
#include "opencv2/opencv.hpp"
#include "imagepainter.h"

#define SINGLETON(x)     \
private: \
    x(x const&); \
    void operator=(x const&); \
public: \
static x* getInstance(QObject *parent = 0) \
{ \
   static bool first=true; \
   if ((parent == 0) && (first == true)) { qCritical("Incorrect Initialisation - no parent and first"); } \
   if ((parent != 0) && (first == false)) { qCritical("Incorrect Initialisation - parent and not first"); } \
   first = false; \
   static x *instance = new x(parent); \
   return instance; \
} \
private:

#define QML_CONSTANT_PROPERTY(type, name) \
    protected: \
        Q_PROPERTY (type name READ get_##name CONSTANT) \
        type m_##name; \
    public: \
        type get_##name () const { \
            return m_##name ; \
        } \
    private:

class DrawImageCtrl : public QObject
{
    Q_OBJECT
    SINGLETON(DrawImageCtrl)
    QML_CONSTANT_PROPERTY(MyQImage*, pSceneImage)

public:
    explicit DrawImageCtrl(QObject *parent = nullptr);
    ~DrawImageCtrl();

public slots:
    void sltTestDrawImage();

    // 辅助事件
    void sltWindowWidthChanged(qreal lfWindowWidth);
    void sltWindowHeightChanged(qreal lfWindowHeight);

    // 鼠标事件
    void sltMousePressed(qreal lfX, qreal lfY, quint32 nButtonValue);
    void sltMouseReleased(qreal lfX, qreal lfY, quint32 nButtonValue);

    // 键盘事件
    void sltKeyPressed(int nKey);
    void sltKeyReleased(int nKey);

signals:
    void sigImageUpdate();

private:
    void showImage(const cv::Mat &mat);

private:
    // 界面属性
    qreal m_lfWindowWidth;
    qreal m_lfWindowHeight;
    double m_lfLastMouseX;
    double m_lfLastMouseY;

    // 快照属性
    double m_lfZoomFactor;
    double m_lfImgX;
    double m_lfImgY;
};

#endif // DRAWIMAGECTRL_H


// drawimagectrl.cpp 代码如下:
#include "drawimagectrl.h"
#include <QTimer>
#include <QDebug>

DrawImageCtrl::DrawImageCtrl(QObject *parent)
    : QObject(parent)
    , m_pSceneImage(new MyQImage(this))
    , m_lfWindowWidth(0.0)
    , m_lfWindowHeight(0.0)
    , m_lfLastMouseX(-1)
    , m_lfLastMouseY(-1)
    , m_lfZoomFactor(1.0)
    , m_lfImgX(0.0)
    , m_lfImgY(0.0)
{

}

DrawImageCtrl::~DrawImageCtrl()
{
    if(nullptr != m_pSceneImage)
    {
        delete m_pSceneImage;
        m_pSceneImage = nullptr;
    }
}

void DrawImageCtrl::sltTestDrawImage()
{
    static int i = 0;
    QString sPicFileName = QString::fromUtf8("/home/xiaohuamao/mycode/DrawImageInQQuickPaintedItem/TestPic/%1.png").arg(i);
    if(++i >= 100)
        i = 0;
    cv::Mat image = cv::imread(sPicFileName.toStdString());
    showImage(image);
    QTimer::singleShot(10, this, &DrawImageCtrl::sltTestDrawImage);
}

void DrawImageCtrl::sltWindowWidthChanged(qreal lfWindowWidth)
{
    m_lfWindowWidth = lfWindowWidth;
}

void DrawImageCtrl::sltWindowHeightChanged(qreal lfWindowHeight)
{
    m_lfWindowHeight = lfWindowHeight;
}

void DrawImageCtrl::sltMousePressed(qreal lfX, qreal lfY, quint32 nButtonValue)
{
    qDebug() << QString::fromUtf8("sltMousePressed x:%1,y:%2,btn:%3")
                .arg(lfX).arg(lfY).arg(nButtonValue);
}

void DrawImageCtrl::sltMouseReleased(qreal lfX, qreal lfY, quint32 nButtonValue)
{
    qDebug() << QString::fromUtf8("sltMouseReleased x:%1,y:%2,btn:%3")
                .arg(lfX).arg(lfY).arg(nButtonValue);
}

void DrawImageCtrl::sltKeyPressed(int nKey)
{
    qDebug() << QString::fromUtf8("sltKeyPressed nKey:%1").arg(nKey);
}

void DrawImageCtrl::sltKeyReleased(int nKey)
{
    qDebug() << QString::fromUtf8("sltKeyReleased nKey:%1").arg(nKey);
}

QImage cvMatToQImage( const cv::Mat &inMat )
{
   switch ( inMat.type() )
   {
      // 8-bit, 4 channel
      case CV_8UC4:
      {
         QImage image( inMat.data,
                       inMat.cols, inMat.rows,
                       static_cast<int>(inMat.step),
                       QImage::Format_ARGB32 );

         return image;
      }

      // 8-bit, 3 channel
      case CV_8UC3:
      {
         QImage image( inMat.data,
                       inMat.cols, inMat.rows,
                       static_cast<int>(inMat.step),
                       QImage::Format_RGB888 );

         return image.rgbSwapped();
      }

      // 8-bit, 1 channel
      case CV_8UC1:
      {
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
         QImage image( inMat.data,
                       inMat.cols, inMat.rows,
                       static_cast<int>(inMat.step),
                       QImage::Format_Grayscale8 );
#else
         static QVector<QRgb>  sColorTable;

         // only create our color table the first time
         if ( sColorTable.isEmpty() )
         {
            sColorTable.resize( 256 );

            for ( int i = 0; i < 256; ++i )
            {
               sColorTable[i] = qRgb( i, i, i );
            }
         }

         QImage image( inMat.data,
                       inMat.cols, inMat.rows,
                       static_cast<int>(inMat.step),
                       QImage::Format_Indexed8 );

         image.setColorTable( sColorTable );
#endif

         return image;
      }

      default:
         qWarning() << "cvMatToQImage() - cv::Mat image type not handled in switch:" << inMat.type();
         break;
   }

   return QImage();
}

void DrawImageCtrl::showImage(const cv::Mat &mat)
{
    cv::Mat image = mat.clone();
    m_pSceneImage->setImage(cvMatToQImage(mat));

    auto lfAspectRatio = 1. * image.cols / image.rows;
    auto lfAspectRatio2 = 1. * m_lfWindowWidth / m_lfWindowHeight;
    auto lfFactor = 1.0;
    if (lfAspectRatio > lfAspectRatio2)
        lfFactor = 1. * m_lfWindowWidth / image.cols;
    else
        lfFactor = 1. * m_lfWindowHeight / image.rows;
    double lfImgX = (m_lfWindowWidth / lfFactor - image.cols) / 2;
    double lfImgY = (m_lfWindowHeight / lfFactor - image.rows) / 2;

    emit sigImageUpdate();

    m_lfZoomFactor = lfFactor;
    m_lfImgX = lfImgX;
    m_lfImgY = lfImgY;
}


// main.cpp 代码如下:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "drawimagectrl.h"
#include "imagepainter.h"

void initDrawImage(QQmlApplicationEngine &engine)
{
    qmlRegisterType<ImagePainter>("MyItem", 1, 0, "ImagePainter");
    engine.rootContext()->setContextProperty(QLatin1String("drawImageCtrl"), DrawImageCtrl::getInstance());
}

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;
    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);
    initDrawImage(engine);
    engine.load(url);

    return app.exec();
}


// main.qml 代码如下:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    DrawImage {
        anchors.fill: parent
    }

    Button {
        text: "draw"

        onClicked: {
            drawImageCtrl.sltTestDrawImage();
        }
    }
}


// DrawImage.qml 代码如下:
import QtQuick 2.0
import MyItem 1.0

Rectangle {
    id : canvasRect

    Connections{
        target: drawImageCtrl

        function onSigImageUpdate(){
            idSceneImage.update();
        }
    }

    Image {
        id: imgCanvas
        width: parent.width
        height: parent.height
        anchors.fill: parent

        ImagePainter {
            id: idSceneImage
            anchors.fill: parent
            nFillMode: Image.PreserveAspectFit
            pImage: drawImageCtrl.pSceneImage
            visible: true
        }

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            propagateComposedEvents: true
            acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MidButton

            onEntered: {
                imgCanvas.forceActiveFocus();
            }

            onPressed: {
                drawImageCtrl.sltMousePressed(mouse.x, mouse.y, mouse.button);
            }

            onReleased: {
                drawImageCtrl.sltMouseReleased(mouse.x, mouse.y, mouse.button);
            }
        }

        Keys.onPressed: {
            drawImageCtrl.sltKeyPressed(event.key);
        }
        Keys.onReleased: {
            drawImageCtrl.sltKeyReleased(event.key);
        }

        onWidthChanged: {
            drawImageCtrl.sltWindowWidthChanged(imgCanvas.width);
        }

        onHeightChanged: {
            drawImageCtrl.sltWindowHeightChanged(imgCanvas.height);
        }
    }

    onVisibleChanged: {
        if(canvasRect.visible) {
            imgCanvas.focus = true;
        }
        else {
            imgCanvas.focus = false;
        }
    }

    onFocusChanged: {
        if(canvasRect.focus)
            imgCanvas.focus = true;
    }
}

标签:name,parent,Image,void,QML,inMat,include,image,QQuickPaintedItem
From: https://blog.csdn.net/github_38647413/article/details/139903681

相关文章

  • docker拉取镜像失败error pulling image configuration: download failed after attem
    最近很多朋友遇到docker拉取镜像失败的问题因为一些网络问题,无法访问docker官方镜像仓库,我们可以通过设置阿里云镜像加速器的方式解决该问题。解决方法:1.访问阿里云官网,并登录https://www.aliyun.com/2.搜索容器镜像服务3.点击立即开通4.根据提示免费开通个人版,开通......
  • image-classification-dataset
    importtorchtextfromtorchvisionimporttransformsfromtorch.utilsimportdatafromd2limporttorchasd2limporttorchvisiontrans=transforms.ToTensor()fashion_mnist_train=torchvision.datasets.FashionMNIST("../data",......
  • 点云处理中阶 RangeImages
    目录一、什么是深度图1、深度图的特点与生成二、深度图的应用1、深度图的应用三、深度图前沿应用四、PCL中定义的RangeImage1、从点云创建深度图从深度图中提取边界四、资料补充1、什么是莫尔条纹法莫尔条纹法的原理莫尔条纹法的应用莫尔条纹法的优势和局限优势......
  • Android开发系列(五)Jetpack Compose之Icon & Image
      Icon是用于在界面上显示矢量图标的组件。它提供了很多内置的矢量图标,也支持自定义图标。要使用Icon组件,可以通过指定图标资源的名称或引用来创建一个Icon对象。例如,使用Icons.Default.Home来创建一个默认风格的首页图标。可以通过设置图标的大小、颜色、和点击事件等属性......
  • 准入控制器(Admission Controller):ResourceQuota,ImagePolicyWebhook
    目录一.系统环境二.前言三.准入控制器简介四.为什么需要准入控制器五.启用/禁用ResourceQuota资源配额5.1查看默认启用/禁用的准入控制器插件5.2ResourceQuota资源配额示例5.3禁用ResourceQuota六.配置ImagePolicyWebhook准入控制器禁止使用后缀为latest的镜像6.1搭建Webhook......
  • 阅读笔记:DualGAN: Unsupervised Dual Learning for Image-to-Image Translation
    以下是原论文分析,欢迎指正~DualGAN:用于图像转换的无监督双向学习作者:ZiliYi、Hao(Richard)Zhang、PingTan和MinglunGong纽芬兰纪念大学西蒙弗雷泽大学摘要  使用条件生成对抗网络(conditionalGAN)进行跨域图像转换在过去一年中取得了重大改进.根据任务的复杂程度......
  • 【SkiaSharp绘图05】SKPaint详解(三)之ImageFilter(颜色、组合、膨胀、移位、光照、反射
    文章目录ImageFilterCreateColorFilter颜色滤镜CreateCompose滤镜组合CreateDilate膨胀滤镜CreateDisplacementMapEffect移位映射CreateDistantLitDiffuse光照CreateDistantLitSpecular反射光照CreateDropShadow阴影效果CreateDropShadowOnly只阴影效果CreateErod......
  • [论文阅读] BBDM@ Image-to-Image Translation With Brownian Bridge Diffusion Model
    Pretitle:BBDM:Image-to-ImageTranslationWithBrownianBridgeDiffusionModelssource:CVPR2023paper:https://arxiv.org/abs/2205.07680code:https://github.com/xuekt98/BBDM关键词:I2I,BrownianBridge,Diffusion阅读理由:挺新奇的MotivationGAN-based......
  • No connection adapters were found for 'data:image/png;base64
    Noconnectionadapterswerefoundfor'data:image/png;base64,...' 这个错误通常发生在尝试使用像requests这样的HTTP库去访问一个DataURIscheme时。DataURIscheme(如data:image/png;base64,...)不是一个有效的URL,而是一个嵌入在文档或网页中的二进制数据的直接表示,通常用于......
  • html2canvas插件 线上image转base64
    UncaughtDOMException:Failedtoexecute'toDataURL'on'HTMLCanvasElement':Taintedcanvasesmaynotbeexported.html2canvas,如果html中有image,需要转base64才能正常转换image。本地调试可能存在跨域访问图片问题。由于图片服务器未开启跨域允许权限。Access-Control-A......