使用 PyQt 根据其角度裁剪图像 [英] Cropping an image based on its angles with PyQt

查看:122
本文介绍了使用 PyQt 根据其角度裁剪图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想制作一个 python 脚本,其中程序显示一个包含矩形或正方形的图像,然后最终用户应通过在其角度上拖动一些指针来指定该形状的四个角度.这些指针将由程序呈现.

基于这些角度,程序应该从图像的其余部分裁剪形状.

  • 程序将显示的图像示例:

  • 指针图像:

  • 用户应该做什么:

  • 程序的输出:

我该怎么做?我正在使用 Python3PyQt5.

这就是我目前所做的,就是让用户浏览从他的电脑中选择一张图片并上传到程序的过程

from PyQt5 import QtCore, QtGui, QtWidgets从 PyQt5.QtGui 导入 QCursor类 Ui_Dialog(对象):def setupUi(self, Dialog):Dialog.setObjectName("对话框")Dialog.setEnabled(True)Dialog.resize(1050, 800)Dialog.setMinimumSize(QtCore.QSize(1050, 800))Dialog.setMaximumSize(QtCore.QSize(1050, 800))图标 = QtGui.QIcon()icon.addPixmap(QtGui.QPixmap("project pic/images LPR icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)Dialog.setWindowIcon(icon)Dialog.setStyleSheet("背景色:rgb(217, 217, 217);\n""背景颜色:RGB(243, 243, 243);")self.UserImageLbl = QtWidgets.QLabel(Dialog)self.UserImageLbl.setGeometry(QtCore.QRect(130, 60, 800, 600))self.UserImageLbl.setMinimumSize(QtCore.QSize(800, 600))self.UserImageLbl.setMaximumSize(QtCore.QSize(800, 600))self.UserImageLbl.setFrameShape(QtWidgets.QFrame.StyledPanel)self.UserImageLbl.setFrameShadow(QtWidgets.QFrame.Plain)self.UserImageLbl.setLineWidth(1)self.UserImageLbl.setMidLineWidth(0)self.UserImageLbl.setText("")self.UserImageLbl.setPixmap(QtGui.QPixmap("project pic/upn.png"))self.UserImageLbl.setScaledContents(False)self.UserImageLbl.setAlignment(QtCore.Qt.AlignCenter)self.UserImageLbl.setObjectName("UserImageLbl")self.BrowesImageButton = QtWidgets.QPushButton(Dialog)self.BrowesImageButton.setGeometry(QtCore.QRect(430, 690, 230, 60))self.BrowesImageButton.setMinimumSize(QtCore.QSize(230, 60))self.BrowesImageButton.setMaximumSize(QtCore.QSize(230, 60))字体 = QtGui.QFont()font.setFamily("微软雅黑UI")font.setPointSize(11)font.setBold(True)font.setWeight(75)self.BrowesImageButton.setFont(font)self.BrowesImageButton.setStyleSheet("background-color: rgb(0, 214, 157);\n""背景颜色:RGB(0, 170, 127);")self.BrowesImageButton.setCursor(QCursor(QtCore.Qt.PointingHandCursor))# self.BrowesImageButton.setStyleSheet("BrowesImageButton:hover { background-color: rgb(0, 214, 157) }" )self.BrowesImageButton.setCheckable(True)self.BrowesImageButton.setObjectName("BrowesImageButton")self.retranslateUi(Dialog)QtCore.QMetaObject.connectSlotsByName(Dialog)self.BrowesImageButton.clicked.connect(self.setImage)def retranslateUi(self, Dialog):_translate = QtCore.QCoreApplication.translateDialog.setWindowTitle(_translate("Dialog", "Cropping Shapes"))self.BrowesImageButton.setText(_translate("Dialog", "Browse Image"))def setImage(self):#fileName, _ = QtWidgets.QFileDialog.getOpenFileName(None, "Select Image", "", "Image Files (*.png *.jpg *jpeg *.bmp);;All Files (*)") # 请求文件fileName, _ = QtWidgets.QFileDialog.getOpenFileName(None, "Select Image", "", "Image Files (*.png)") # 请求文件if fileName: # 如果用户给了一个文件pixmap = QtGui.QPixmap(fileName) # 使用提供的图像设置像素图pixmap = pixmap.scaled(self.UserImageLbl.width(), self.UserImageLbl.height(), QtCore.Qt.KeepAspectRatio) # 缩放像素图self.UserImageLbl.setPixmap(pixmap) # 将像素图设置到标签上self.UserImageLbl.setAlignment(QtCore.Qt.AlignCenter) # 将标签居中对齐如果 __name__ == "__main__":导入系统app = QtWidgets.QApplication(sys.argv)对话框 = QtWidgets.QDialog()ui = Ui_Dialog()ui.setupUi(对话)Dialog.show()sys.exit(app.exec_())

提前致谢.

解决方案

在这种情况下,最好使用 QGraphicsView,因为它允许我们添加其他图像而无需缩放图像.在 QGraphicsView 中,您将获得点击具有图像的项目的点,然后使用

I want to make a python script where the program shows an image that contains a rectangle or a square and then the End-user should specify four angles of this shape by drag some pointers on its angles. These pointers will be presented by the program.

Based on these angles the program should crop the shape from the rest of the image.

  • Example of images that the program will show:

  • Pointers Images:

  • What the user should do :

  • The Output of the program:

How I can do this? I'm Working with Python3, PyQt5.

This is what I have done so far, which is the process of allowing the user to browse to select an image from his computer and upload it to the program

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QCursor

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.setEnabled(True)
        Dialog.resize(1050, 800)
        Dialog.setMinimumSize(QtCore.QSize(1050, 800))
        Dialog.setMaximumSize(QtCore.QSize(1050, 800))
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("project pic/images LPR icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        Dialog.setWindowIcon(icon)
        Dialog.setStyleSheet("background-color: rgb(217, 217, 217);\n"
"background-color: rgb(243, 243, 243);")
        self.UserImageLbl = QtWidgets.QLabel(Dialog)
        self.UserImageLbl.setGeometry(QtCore.QRect(130, 60, 800, 600))
        self.UserImageLbl.setMinimumSize(QtCore.QSize(800, 600))
        self.UserImageLbl.setMaximumSize(QtCore.QSize(800, 600))
        self.UserImageLbl.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.UserImageLbl.setFrameShadow(QtWidgets.QFrame.Plain)
        self.UserImageLbl.setLineWidth(1)
        self.UserImageLbl.setMidLineWidth(0)
        self.UserImageLbl.setText("")
        self.UserImageLbl.setPixmap(QtGui.QPixmap("project pic/upn.png"))
        self.UserImageLbl.setScaledContents(False)
        self.UserImageLbl.setAlignment(QtCore.Qt.AlignCenter)
        self.UserImageLbl.setObjectName("UserImageLbl")
        self.BrowesImageButton = QtWidgets.QPushButton(Dialog)
        self.BrowesImageButton.setGeometry(QtCore.QRect(430, 690, 230, 60))
        self.BrowesImageButton.setMinimumSize(QtCore.QSize(230, 60))
        self.BrowesImageButton.setMaximumSize(QtCore.QSize(230, 60))
        font = QtGui.QFont()
        font.setFamily("Microsoft YaHei UI")
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        self.BrowesImageButton.setFont(font)
        self.BrowesImageButton.setStyleSheet("background-color: rgb(0, 214, 157);\n"
"background-color: rgb(0, 170, 127);")
        self.BrowesImageButton.setCursor(QCursor(QtCore.Qt.PointingHandCursor))
       # self.BrowesImageButton.setStyleSheet("BrowesImageButton:hover { background-color:  rgb(0, 214, 157) }" )

        self.BrowesImageButton.setCheckable(True)
        self.BrowesImageButton.setObjectName("BrowesImageButton")

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

        self.BrowesImageButton.clicked.connect(self.setImage)


    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", " Cropping Shapes"))
        self.BrowesImageButton.setText(_translate("Dialog", "Browse Image"))


    def setImage(self):
        #fileName, _ = QtWidgets.QFileDialog.getOpenFileName(None, "Select Image", "", "Image Files (*.png *.jpg *jpeg *.bmp);;All Files (*)") # Ask for file
        fileName, _ = QtWidgets.QFileDialog.getOpenFileName(None, "Select Image", "", "Image Files (*.png)") # Ask for file

        if fileName: # If the user gives a file
            pixmap = QtGui.QPixmap(fileName) # Setup pixmap with the provided image
            pixmap = pixmap.scaled(self.UserImageLbl.width(), self.UserImageLbl.height(), QtCore.Qt.KeepAspectRatio) # Scale pixmap
            self.UserImageLbl.setPixmap(pixmap) # Set the pixmap onto the label
            self.UserImageLbl.setAlignment(QtCore.Qt.AlignCenter) # Align the label to center


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

Thanks in advance.

解决方案

In this case it is better to use QGraphicsView as it allows us to add other images without the need to scale the image. In the QGraphicsView you get the points where you click on the item that has the image, and then with that information using my previous answer you get the following:

import os
import sys

from PyQt5 import QtCore, QtGui, QtWidgets


current_dir = os.path.dirname(os.path.realpath(__file__))
point_filename = os.path.join(current_dir, "41uu2.png")


class GraphicsView(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super().__init__(QtWidgets.QGraphicsScene(), parent)
        self.pixmap_item = self.scene().addPixmap(QtGui.QPixmap())
        self.pixmap_item.setShapeMode(QtWidgets.QGraphicsPixmapItem.BoundingRectShape)

        self.setAlignment(QtCore.Qt.AlignCenter)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

    def set_image(self, pixmap):
        self.pixmap_item.setPixmap(pixmap)
        self.fitInView(self.pixmap_item, QtCore.Qt.KeepAspectRatio)


class CropView(GraphicsView):
    resultChanged = QtCore.pyqtSignal(QtGui.QPixmap)

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

        self.point_items = []

    def mousePressEvent(self, event):
        if not self.pixmap_item.pixmap().isNull():
            sp = self.mapToScene(event.pos())
            lp = self.pixmap_item.mapFromScene(sp)
            if self.pixmap_item.contains(lp):
                size = QtCore.QSize(30, 30)
                height = (
                    self.mapToScene(QtCore.QRect(QtCore.QPoint(), size))
                    .boundingRect()
                    .size()
                    .height()
                )
                pixmap = QtGui.QPixmap(point_filename)
                point_item = QtWidgets.QGraphicsPixmapItem(pixmap, self.pixmap_item)
                point_item.setOffset(
                    -QtCore.QRect(QtCore.QPoint(), pixmap.size()).center()
                )
                point_item.setPos(lp)
                scale = height / point_item.boundingRect().size().height()
                point_item.setScale(scale)
                self.point_items.append(point_item)
                if len(self.point_items) == 4:
                    points = []
                    for it in self.point_items:
                        points.append(it.pos().toPoint())
                    self.crop(points)
                elif len(self.point_items) == 5:
                    for it in self.point_items[:-1]:
                        self.scene().removeItem(it)
                    self.point_items = [self.point_items[-1]]
            else:
                print("outside")
        super().mousePressEvent(event)

    def crop(self, points):
        # https://stackoverflow.com/a/55714969/6622587
        polygon = QtGui.QPolygonF(points)
        path = QtGui.QPainterPath()
        path.addPolygon(polygon)

        source = self.pixmap_item.pixmap()

        r = path.boundingRect().toRect().intersected(source.rect())

        pixmap = QtGui.QPixmap(source.size())
        pixmap.fill(QtCore.Qt.transparent)
        painter = QtGui.QPainter(pixmap)
        painter.setClipPath(path)
        painter.drawPixmap(QtCore.QPoint(), source, source.rect())
        painter.end()
        result = pixmap.copy(r)
        self.resultChanged.emit(result)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFixedSize(1050, 600)

        self.left_view = CropView()
        self.rigth_view = GraphicsView()

        self.left_view.resultChanged.connect(self.rigth_view.set_image)

        button = QtWidgets.QPushButton(self.tr("Browse Image"))
        button.setStyleSheet("background-color: rgb(0, 214, 157);")
        button.setFixedSize(230, 60)
        font = QtGui.QFont()
        font.setFamily("Microsoft YaHei UI")
        font.setPointSize(11)
        font.setBold(True)
        font.setWeight(75)
        button.setFont(font)
        button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        button.clicked.connect(self.load_image)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        lay = QtWidgets.QGridLayout(central_widget)
        lay.addWidget(self.left_view, 0, 0)
        lay.addWidget(self.rigth_view, 0, 1)
        lay.addWidget(button, 1, 0, 1, 2, alignment=QtCore.Qt.AlignHCenter)

    @QtCore.pyqtSlot()
    def load_image(self):
        fileName, _ = QtWidgets.QFileDialog.getOpenFileName(
            None, "Select Image", "", "Image Files (*.png)"
        )
        if fileName:
            pixmap = QtGui.QPixmap(fileName)
            self.left_view.set_image(pixmap)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

这篇关于使用 PyQt 根据其角度裁剪图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆