Get ROI from zoomed image in QGraphicsScene PyQt5

315 Views Asked by At

There is added QGraphicsPixmapItem in QGraphicsScene. The image is inserted via the setPhoto method. The wheelEvent method zooms in or out on the image.

If image is zoomed I would like to take the displayed part of the image as ROI (img[y:y+h, x:x+w]), is there some method in QGraphicsPixmapItem (or another) that gives me x,y,w,h of displayed image if image is zoomed or I have to calculate it in the method wheelEvent?

Thanks.

Sample code:

from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtGui import QImage
from PyQt5.QtWidgets import *
import sys
import cv2
import os

class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.setWindowTitle('ROI')
        self.setMinimumWidth(1400)
        self.setMinimumHeight(1000)
        self.main_widget = QtWidgets.QWidget(self)
        self.setCentralWidget(self.main_widget)

        self.view = GraphicsView(self)

        self.lay()
        self.akce()

    def lay(self):
        self.butt = QPushButton('Load image')
        self.hlay = QHBoxLayout(self.main_widget)
        self.grid = QGridLayout()
        self.hlay.addLayout(self.grid, 2)
        self.hlay.addWidget(self.view, 8)
        self.grid.addWidget(self.butt, 1, 1)

    def akce(self):
        self.butt.clicked.connect(self.loadImage)

    def loadImage(self):
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getOpenFileName(self, 'Load image', '',
                                                  'Images (*.bmp *.jpeg *.tif *.jpg *.png *.ppm *.xbm *.xpm)',
                                                  options=options)
        if fileName:
            flnm = r'{pth}'.format(pth=os.path.abspath(fileName))
            bgrImage = cv2.imread(fr'{flnm}')
            rgbImage = cv2.cvtColor(bgrImage, cv2.COLOR_BGR2RGB)
            rgbImage = QImage(rgbImage, rgbImage.shape[1], rgbImage.shape[0], rgbImage.strides[0], QImage.Format_RGB888)
            self.view.setPhoto(QtGui.QPixmap.fromImage(rgbImage))
            self.view.fitWindow()

class GraphicsView(QtWidgets.QGraphicsView):
    def __init__(self, parent):
        super(GraphicsView, self).__init__(parent)

        self.val_zoom = 0
        self.val_empty = True
        self._graphicsScene = QtWidgets.QGraphicsScene(self)
        self._mapaPixmap = QtWidgets.QGraphicsPixmapItem()
        self._graphicsScene.addItem(self._mapaPixmap)
        self.setScene(self._graphicsScene)
        self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
        # self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        # self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(30, 30, 30)))
        self.setFrameShape(QtWidgets.QFrame.NoFrame)

    def isLoaded(self):
        return not self.val_empty

    def fitWindow(self, scale=True):
        rect = QtCore.QRectF(self._mapaPixmap.pixmap().rect())
        if not rect.isNull():
            self.setSceneRect(rect)
            if self.isLoaded():
                unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))
                self.scale(1 / unity.width(), 1 / unity.height())
                viewrect = self.viewport().rect()
                scenerect = self.transform().mapRect(rect)
                factor = min(viewrect.width() / scenerect.width(),
                             viewrect.height() / scenerect.height())
                self.scale(factor, factor)
            self.val_zoom = 0

    def setPhoto(self, pixmap=None):
        if pixmap and not pixmap.isNull():
            self.val_empty = False
            self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
            self._mapaPixmap.setPixmap(pixmap)
        else:
            self.val_empty = True
            self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
            self._mapaPixmap.setPixmap(QtGui.QPixmap())

    def wheelEvent(self, event):
        if self.isLoaded():
            if event.angleDelta().y() > 0:
                factor = 1.25
                self.val_zoom += 1
            else:
                factor = 0.8
                self.val_zoom -= 1
            if self.val_zoom > 0:
                self.scale(factor, factor)
            elif self.val_zoom == 0:
                self.fitWindow()
            else:
                self.val_zoom = 0

    def toggleDragMode(self):
        if self.dragMode() == QtWidgets.QGraphicsView.ScrollHandDrag:
            self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
        elif not self._mapaPixmap.pixmap().isNull():
            self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    wd = MainWindow()
    wd.show()
    sys.exit(app.exec_())

0

There are 0 best solutions below