首页 > 解决方案 > 如何使用 wheelEvent 将调整大小的 QGraphicPixmap 放置到 QGraphicsScene 中,同时保持光标下的相同像素

问题描述

我想使用wheelEvent来调整图像大小并将 aQGraphicPixmap放入QGraphicsScene.

在添加原始图像之前,将其大小调整为原始大小的 1/3 左右。在 wheelEvent 中,我正在调用一个函数,该函数将调整原始图像的大小并创建一个QImage来设置QGraphicsPixmap.

将调整大小的像素图添加到场景后,缩放前光标下的像素发生了偏移。我不确定我需要映射到场景/从场景映射到哪些位置才能实现这一点。

我尝试过缩放 graphicsPixmap、缩放和转换 graphicsPixmap、缩放视图和转换 graphicsPixmap/设置偏移量。

我显然不知道发生了什么,但我不确定那是什么..

下面的 WheelEvent 可以完美运行,直到maybe_resize被调用。

根据查看器中当前图像的大小,该maybe_resize方法将调整当前 ndarray 图像的大小,创建一个新的 qimage 并在 graphicsPixmap 中设置一个新的像素图,或者退出该方法而不调整大小。

如果按原样运行代码,则像素图位于光标下的同一位置,但如果取消注释,maybe_resize则不再是这种情况。

from PyQt5.QtCore import QRectF, QSize, Qt, pyqtSignal
import cv2
import numpy as np
from PyQt5.QtCore import QRectF, QSize, Qt, pyqtSignal
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import (QApplication,
                             QFrame,
                             QGraphicsPixmapItem,
                             QGraphicsScene,
                             QGraphicsView,
                             QMainWindow,
                             QSizePolicy)


class GraphicsView(QGraphicsView):
    def __init__(self, parent):
        super(GraphicsView, self).__init__(parent)
        self.pixmap = QPixmap()
        self._zoom_level = 0
        self._scene = Scene(self)
        self.setScene(self._scene)
        self.gpm = QGraphicsPixmapItem()
        self._scene.addItem(self.gpm)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setFrameShape(QFrame.NoFrame)
        self.has_image = False

    def maybe_resize(self, factor):
        self.resize_requested(factor)

    def read_image(self, path):
        self.base_image = cv2.imread(path, -1)
        self._original_res = self.base_image.shape
        h, w = self.base_image.shape[0], self.base_image.shape[1]
        self.resized_image = cv2.resize(self.base_image, (w // 4, h // 4))
        self.has_image = True
        self.set_image(self.resized_image)
        return self.resized_image

    def resize_requested(self, factor):
        factor = max(1. * (self._zoom_level * factor), 1)
        h = int(self.resized_image.shape[0] * factor)
        w = int(self.resized_image.shape[1] * factor)
        src = cv2.resize(self.base_image, (w, h))
        dst = np.ndarray(src.shape, src.dtype)
        dst[:, :, :] = src
        self.set_image(dst)

    def wheelEvent(self, event):
        factor = 1.1
        if event.angleDelta().y() < 0:
            factor = 0.9
            self._zoom_level-=1
        else:
            self._zoom_level+=1
        view_pos = event.pos()
        scene_pos = self.mapToScene(view_pos)
        self.centerOn(scene_pos)
        self.scale(factor, factor)
        delta = self.mapToScene(view_pos) - self.mapToScene(self.viewport().rect().center())
        self.centerOn(scene_pos - delta)
        # self.maybe_resize(factor)

    def set_image(self, img):
        if not self.has_image:
            return
        shape = img.shape
        w = shape[1]
        h = shape[0]
        self._image = img
        q_img_format = QImage.Format_RGB888
        try:
            bands = shape[2]
        except IndexError:
            bands = 1
        q_img = QImage(img, w, h, w * bands, q_img_format)
        self.pixmap = self.pixmap.fromImage(q_img)
        self.setSceneRect(QRectF(self.pixmap.rect()))
        self.gpm.setPixmap(self.pixmap)


class Scene(QGraphicsScene):
    zoom_changed = pyqtSignal(float)

    def __init__(self, parent=None):
        super(Scene, self).__init__(parent)


class Window(QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        self.gv = GraphicsView(self)
        self.setCentralWidget(self.gv)

    def load_image(self, path):
        self.gv.read_image(path)

    def sizeHint(self):
        return QSize(800, 800)


if __name__ == "__main__":
    app = QApplication([])
    w = Window()
    w.load_image('test.jpg')
    w.show()
    app.exit(app.exec_())

标签: pythonpyqt5pyside2qgraphicsviewqgraphicsscene

解决方案


推荐阅读