Issue
I cannot figure out how to crop a QPixmap that is set on a scene with a rotated QGraphicsRectItem also placed in the same scene.
Here is the code for my QGraphicsScene and QPixmap.
class crop_pattern(QGraphicsView):
img_is_cropped = QtCore.Signal(object)
def __init__(self, path, scale):
super().__init__()
# Connect graphics scene with graphics view
self.setFixedSize(500, 500)
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.roi_scale = scale
# Display image
self.set_image(path)
def set_image(self, path):
pixmap = QtGui.QPixmap(path)
if pixmap:
pixmap = pixmap.scaledToHeight(self.roi_scale * pixmap.height())
self.scene.clear()
self.scene.addPixmap(pixmap)
self.setAlignment(QtCore.Qt.AlignCenter)
def wheelEvent(self, event):
zoomInFactor = 1.05
zoomOutFactor = 1 / zoomInFactor
oldPos = self.mapToScene(event.pos())
if event.angleDelta().y() > 0:
zoomFactor = zoomInFactor
else:
zoomFactor = zoomOutFactor
self.scale(zoomFactor, zoomFactor)
newPos = self.mapToScene(event.pos())
delta = newPos - oldPos
self.translate(delta.x(), delta.y())
(Credits to QGraphicsView Zooming in and out under mouse position using mouse wheel for the wheelEvent function)
Here is the QGraphicsItem that is generated when the user clicks a certain button.
QtCore.Slot(bool)
def create_shape(self):
sender = self.sender()
if sender.text().lower() == "circle":
self.shape = ellipse_shape(0, 0, 100, 100)
elif sender.text().lower() == "rectangle":
self.shape = rect_shape(0, 0, 100, 100)
self.shape.setZValue(1)
self.shape.setTransformOriginPoint(50, 50)
self.crop_pattern.scene.addItem(self.shape) # added item to the same scene, which is crop_pattern.
Here is the GUI as the question suggested. (QGraphicsRectItem has been resized)
How can I crop the pixels inside the rectangle? Thanks!
Solution
One possible solution is to create a hidden QGraphicsView and use the render()
method to save the image section. The objective of the hidden QGraphicsView is not to modify the existing view since the image must be rotated in addition to not being affected by the scaling.
from PyQt5 import QtCore, QtGui, QtWidgets
def crop_rect(rect_item, scene):
is_visible = rect_item.isVisible()
rect_item.hide()
hide_view = QtWidgets.QGraphicsView(scene)
hide_view.rotate(-rect_item.rotation())
polygon = rect_item.mapToScene(rect_item.rect())
pixmap = QtGui.QPixmap(rect_item.rect().size().toSize())
pixmap.fill(QtCore.Qt.transparent)
source_rect = hide_view.mapFromScene(polygon).boundingRect()
painter = QtGui.QPainter(pixmap)
hide_view.render(
painter,
target=QtCore.QRectF(pixmap.rect()),
source=source_rect,
)
painter.end()
rect_item.setVisible(is_visible)
return pixmap
def main():
app = QtWidgets.QApplication([])
scene = QtWidgets.QGraphicsScene()
view = QtWidgets.QGraphicsView(alignment=QtCore.Qt.AlignCenter)
view.setScene(scene)
# emulate wheel
view.scale(0.8, 0.8)
# create pixmap
pixmap = QtGui.QPixmap(500, 500)
pixmap.fill(QtGui.QColor("green"))
painter = QtGui.QPainter(pixmap)
painter.setBrush(QtGui.QColor("salmon"))
painter.drawEllipse(pixmap.rect().adjusted(100, 90, -80, -100))
painter.end()
pixmap_item = scene.addPixmap(pixmap)
rect = QtCore.QRectF(0, 0, 200, 300)
rect_item = scene.addRect(rect)
rect_item.setPen(QtGui.QPen(QtGui.QColor("red"), 4))
rect_item.setPos(100, 100)
rect_item.setTransformOriginPoint(50, 50)
rect_item.setRotation(10)
view.resize(640, 480)
view.show()
qpixmap = crop_rect(rect_item, scene)
label = QtWidgets.QLabel()
label.setPixmap(qpixmap)
label.show()
app.exec_()
if __name__ == "__main__":
main()
Input:
Output:
Answered By - eyllanesc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.