Perspective Transform by Mouse Drag - PyQT(Pyside)

Viewed 21

I am making perspective transform by Mouse Drag.

I maked almost, but When transform by Qtransform.quadToQuad, Position(Coordinate) is not fit. (See uploaded Image)

Good Example - When Size not Changed

Good Example - When Size not Changed

Bad Example - When Size Changed?

Bad Example - When Size Changed?

How To Fit 4 Point(by Square Point) and Transformed image? Maybe Need to change Postion(size) Image?

import sys

from PySide2.QtCore import QRectF, QPointF
from PySide2.QtGui import *
from PySide2.QtWidgets import *

from mylogger import logger


class Map(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # set windowflag
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)

        # monitor 0 execute
        monitor = QDesktopWidget().screenGeometry(0)
        self.move(monitor.left(), monitor.top())



        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)

        # QGraphicsView
        self.view = QGraphicsView()
        self.view.setViewportMargins(0, 0, 0, 0)
        self.view.setFrameStyle(QFrame.NoFrame)
        self.view.setRenderHints(QPainter.Antialiasing)
        self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.layout.addWidget(self.view)

        # QGraphicsScene
        self.scene = QGraphicsScene()
        self.view.setScene(self.scene)

        # Set Image
        self.pixmap = QPixmap("../sample.png")
        self.pixmap = self.pixmap.scaled(monitor.width(), monitor.height())
        self.image = self.scene.addPixmap(self.pixmap)
        self.image.setFlag(QGraphicsItem.ItemIsMovable)

        # Set 4 Point (square point)
        self.point_size = 8

        self.point_left_top = ROIPoint(QRectF(0, 0, self.point_size, self.point_size), "left_top", self)
        self.point_left_top.setFlag(QGraphicsItem.ItemIsMovable)
        self.scene.addItem(self.point_left_top)

        self.point_right_top = ROIPoint(QRectF(monitor.width() - self.point_size, 0, self.point_size, self.point_size),
                                        "right_top", self)
        self.point_right_top.setFlag(QGraphicsItem.ItemIsMovable)
        self.scene.addItem(self.point_right_top)

        self.point_right_bottom = ROIPoint(
            QRectF(monitor.width() - self.point_size, monitor.height() - self.point_size, self.point_size,
                   self.point_size), "right_bottom", self)
        self.point_right_bottom.setFlag(QGraphicsItem.ItemIsMovable)
        self.scene.addItem(self.point_right_bottom)

        self.point_left_bottom = ROIPoint(
            QRectF(0, monitor.height() - self.point_size, self.point_size, self.point_size), "left_bottom", self)
        self.point_left_bottom.setFlag(QGraphicsItem.ItemIsMovable)
        self.scene.addItem(self.point_left_bottom)

        self.scene.update()


class ROIPoint(QGraphicsRectItem):
    parent = None
    position_str = None

    def __init__(self, rect, position_str, parent):
        super(ROIPoint, self).__init__()
        self.parent = parent
        self.position_str = position_str

        self.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
        self.setFlag(QGraphicsItem.ItemIsFocusable, True)
        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, True)

        self.setAcceptHoverEvents(True)

        self.setCursor(Qt.PointingHandCursor)
        self.rectangle = rect
        self.setBrush(Qt.red)
        self.setRect(rect)

    def boundingRect(self):
        return QRectF(self.rectangle)

    def dragMoveEvent(self, event):
        logger.info(f"dragMoveEvent() : {event} ")

    def calcurated_position(self):
        value = self.pos()
        if self.position_str == "left_top":
            logger.debug(f" left_top : {self.parent.image.mapFromScene(value)}")
            pos = self.parent.image.mapFromScene(value)
        if self.position_str == "right_top":
            logger.debug(f" right_top : {self.parent.image.mapFromScene(value)}")
            pos = QPointF(self.scene().width() + self.parent.image.mapFromScene(value).x(),
                          self.parent.image.mapFromScene(value).y())
        if self.position_str == "right_bottom":
            logger.debug(f" right_bottom : {self.parent.image.mapFromScene(value)}")
            pos = QPointF(self.scene().width() + self.parent.image.mapFromScene(value).x(),
                          self.scene().height() + self.parent.image.mapFromScene(value).y())
        if self.position_str == "left_bottom":
            logger.debug(f" left_bottom : {self.parent.image.mapFromScene(value)}")
            pos = QPointF(self.parent.image.mapFromScene(value).x(),
                          self.scene().height() + self.parent.image.mapFromScene(value).y())

        return pos

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemPositionChange:
            logger.info(f"calcurated_position : {self.calcurated_position()}")

            # transform
            square = QPolygonF(self.scene().sceneRect())
            square.remove(4)
            logger.info(f"square:{square}")

            cone = QPolygonF([
                self.parent.point_left_top.calcurated_position(),
                self.parent.point_right_top.calcurated_position(),
                self.parent.point_right_bottom.calcurated_position(),
                self.parent.point_left_bottom.calcurated_position()
            ])
            transform = QTransform()
            if QTransform.quadToQuad(square, cone, transform):
                new = self.parent.pixmap.transformed(transform, Qt.SmoothTransformation)
                self.parent.image.setPixmap(new)


        return super().itemChange(change, value)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    view = Map()
    view.showFullScreen()
    sys.exit(app.exec_())


0 Answers
Related