重新加载QML画布Imag

2024-10-01 09:40:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用QML画布来绘制图像。映像使用Python、OpenCV和NumPy加载到后端,并通过从QQuickImageProvider继承的自定义映像提供程序提供给QML。要在QML中重新加载图像,请执行以下操作:

unloadImage('image://<providerName>/<ID>')
loadImage('image://<providerName>/<ID>')

只要图像足够大,这种方法就可以很好地工作。但一旦图像大小低于某个阈值(在我的电脑上大约为1.57MB),unloadImage功能似乎就停止工作了。打电话后,我应该不能再画图像了,但这仍然有效。另外,在调用loadImage函数之前,不再调用我的QQuickImageProviderrequestImage函数,如果我不调用unloadImage也是这种情况。你知道吗

有人知道我做错了什么吗?你知道吗

编辑:

下面是一个最小的代码示例,它再现了我的错误:

主.py

import sys
import time

from PySide2 import QtGui, QtQml
from PySide2.QtQuick import QQuickImageProvider
from PySide2.QtGui import QImage
from PySide2.QtCore import QObject, Signal, Slot

import numpy as np
import cv2

class ImageProvider(QQuickImageProvider, QObject):
    def __init__(self):
        # Load images:
        # - The first image is scaled large enough
        self.img1 = np.require(np.flip(cv2.imread("messi5.jpg"), 2), np.uint8, "C")
        self.img1 = cv2.resize(self.img1, (0,0), fx=3, fy=3) 
        # - The second image is too small and won't allow a reload
        self.img2 = np.require(np.flip(cv2.imread("lena.jpg"), 2), np.uint8, "C")

        # Shown image
        self.image = None

        # Initialize parent objects
        QObject.__init__(self)
        QQuickImageProvider.__init__(self, QQuickImageProvider.Image)

    # =======
    # Signals
    # =======
    updateImage = Signal()

    # =====
    # Slots
    # =====
    def requestImage(self, ident, size, requestedSize):
        print("ImageProvider: loading image")

        format = QImage.Format_RGB888
        (h, w) = self.image.shape[:2]
        line_len = self.image.strides[0]

        img = QImage(self.image, w, h, line_len, format)

        return img

    @Slot(result="QVariantList")
    def getImageSize(self):
        h, w = self.image.shape[:2]
        return [w, h]

    @Slot()
    def changeImage(self):
        if np.array_equal(self.image, self.img1):
            self.show(self.img2) 
        else:
            self.show(self.img1) 

    # ==============
    # public methods
    # ==============
    def show(self, Image):
        self.image = Image
        self.updateImage.emit()

if __name__ == "__main__":
    # Create app
    app = QtGui.QGuiApplication(sys.argv)
    engine = QtQml.QQmlApplicationEngine()

    # Create backend
    image_provider = ImageProvider()

    # Register backend
    engine.addImageProvider("CustProv", image_provider)
    engine.rootContext().setContextProperty("CustProv", image_provider)

    # Load window
    engine.load('main.qml')
    win = engine.rootObjects()[0]
    win.show()

    # Show image
    image_provider.show(image_provider.img1)

    sys.exit(app.exec_())

主.qml

import QtQuick 2.0
import QtQuick.Controls 2.0

ApplicationWindow {
    id: root
    visible: true
    width: 800
    height: 480

    // =============
    // Event Handler
    // =============
    onHeightChanged: {
        imagePainter.resize()
    } 

    onWidthChanged: {
        imagePainter.resize()
    } 

    // ========
    // Children
    // ========
    Item {
        anchors {
            top: parent.top
            bottom: button.top
            right: parent.right
            left: parent.left
            bottomMargin: 10
        }

        Canvas {
            id: imagePainter
            anchors {
                horizontalCenter: parent.horizontalCenter
                verticalCenter: parent.verticalCenter
            }

            // =================
            // Custom Properties
            // =================
            property var size: {
                'width': -1,
                'height': -1
            }
            property real scale: 1
            property var image: 'image://CustProv/image'

            // =========
            // Functions
            // =========
            function resize() {
                console.log("Resizing canvas contents")
                var wToH =  size.width/size.height
                if (parent.width/parent.height >= wToH) {
                    // image aspect ratio is narrower than parent 
                    // aspect ratio: Use full height
                    height = parent.height
                    width = wToH * parent.height
                    scale = height/size.height
                }
                else {    
                    // image aspect ratio is wider than parent 
                    // aspect ratio: use full width   
                    width = parent.width          
                    height = parent.width / wToH
                    scale = width/size.width
                }
                // repaint the image
                requestPaint();
            }

            function reload() {
                console.log("Reload triggered")
                // First, get the new image size
                var imSize = CustProv.getImageSize()
                size.width = imSize[0]
                size.height = imSize[1]
                resize()

                // Reload image
                unloadImage(image) <--- Seems to fail for small images
                loadImage(image)
            }

            // =============
            // Event Handler
            // =============
            Component.onCompleted: {
                console.log("connecting external signals")
                CustProv.updateImage.connect(reload)
            }

            onPaint: {
                // Invoked by requestPaint()
                if (!isImageLoaded(image)) {
                    return
                }
                var ctx = getContext('2d')
                ctx.clearRect(0, 0, width, height)
                ctx.scale(scale, scale)
                ctx.drawImage(image, 0, 0)
                ctx.scale(1/scale, 1/scale)
            }

            onImageLoaded: {
                requestPaint()
            }
        }
    }


    Button {
        id: button
        anchors {
            right: parent.right
            bottom: parent.bottom
            bottomMargin: 10
            rightMargin: 10
        }

        width: 200
        height: 25

        text: "Change Image"

        onClicked: {
            CustProv.changeImage()
        }
    }
}

我尽了最大努力把这个例子缩小到绝对最小,但不能再缩小了。对不起的。你知道吗


Tags: 图像imageimportselfsizedefnpwidth
1条回答
网友
1楼 · 发布于 2024-10-01 09:40:29

根据documentation

Images returned by a QQuickImageProvider are automatically cached, similar to any image loaded by the QML engine. When an image with a "image://" prefix is loaded from cache, requestImage() and requestPixmap() will not be called for the relevant image provider. If an image should always be fetched from the image provider, and should not be cached at all, set the cache property to false for the relevant Image, BorderImage or AnimatedImage object.

因此,需要将Image组件的cache属性设置为false。你知道吗

对于重新加载图像,您可以简单地将源路径修饰为null并将其还原为以前的值。你知道吗

相关问题 更多 >