我正在使用QML画布来绘制图像。映像使用Python、OpenCV和NumPy加载到后端,并通过从QQuickImageProvider继承的自定义映像提供程序提供给QML。要在QML中重新加载图像,请执行以下操作:
unloadImage('image://<providerName>/<ID>')
loadImage('image://<providerName>/<ID>')
只要图像足够大,这种方法就可以很好地工作。但一旦图像大小低于某个阈值(在我的电脑上大约为1.57MB),unloadImage功能似乎就停止工作了。打电话后,我应该不能再画图像了,但这仍然有效。另外,在调用loadImage函数之前,不再调用我的QQuickImageProvider的requestImage函数,如果我不调用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()
}
}
}
我尽了最大努力把这个例子缩小到绝对最小,但不能再缩小了。对不起的。你知道吗
根据documentation:
因此,需要将
Image
组件的cache
属性设置为false
。你知道吗对于重新加载图像,您可以简单地将源路径修饰为null并将其还原为以前的值。你知道吗
相关问题 更多 >
编程相关推荐