如何在 Python 中将函数连接到 PyQT5 GUI

Posted

技术标签:

【中文标题】如何在 Python 中将函数连接到 PyQT5 GUI【英文标题】:How to Connect Function to PyQT5 GUI in Python 【发布时间】:2020-08-10 10:58:13 【问题描述】:
import sys
from os import path

import cv2
import numpy as np

from PyQt5 import QtCore
from PyQt5 import QtWidgets
from PyQt5 import QtGui

import pytesseract
from PIL import Image
from pytesseract import image_to_string
from gtts import gTTS
import os


pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"


tessdata_dir_config = r'--tessdata-dir "C:\Program Files\Tesseract-OCR\tessdata"'



class RecordVideo(QtCore.QObject):
    image_data = QtCore.pyqtSignal(np.ndarray)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.camera = cv2.VideoCapture(0)

        self.timer = QtCore.QBasicTimer()

    def start_recording(self):
        self.timer.start(0, self)

    
    def timerEvent(self, event):
        if (event.timerId() != self.timer.timerId()):
            return

        read, data = self.camera.read()
        if read:
            self.image_data.emit(data)
    def framesave(self):
        
        read, data = self.camera.read()
        if read:
            cv2.imwrite('a.png',data)
            img=Image.fromarray(data)
            img.load()
            
            text=pytesseract.image_to_string(img, lang='spa', config=tessdata_dir_config)
        


class FaceDetectionWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.image = QtGui.QImage()
        self._red = (0, 0, 255)
        self._width = 2
        self._min_size = (30, 30)


    def image_data_slot(self, image_data):


        
        self.image = self.get_qimage(image_data)
        if self.image.size() != self.size():
            self.setFixedSize(self.image.size())

        self.update()
    
        
        
    def get_qimage(self, image: np.ndarray):
        height, width, colors = image.shape
        bytesPerLine = 3 * width
        QImage = QtGui.QImage

        image = QImage(image.data,
                       width,
                       height,
                       bytesPerLine,
                       QImage.Format_RGB888)

        image = image.rgbSwapped()
        return image

def static_ROI(self, cropped:np.ndarray):
    # height, width = image.shape[:2]
    #
    # top_left_x = int(width / 3)
    # top_left_y = int((height / 2) + (height / 4))
    # bottom_right_x = int((width / 3) * 2)
    # bottom_right_y = int((height / 2) - (height / 4))
    #
    # cv2.rectangle(image, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), 255, 3)
    #
    # image = image[bottom_right_y:top_left_y, top_left_x:bottom_right_x]

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        painter.drawImage(0, 0, self.image)
        self.image = QtGui.QImage()


class MainWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        
        self.face_detection_widget = FaceDetectionWidget()

        # TODO: set video port
        self.record_video = RecordVideo()

        image_data_slot = self.face_detection_widget.image_data_slot
        self.record_video.image_data.connect(image_data_slot)

        layout = QtWidgets.QVBoxLayout()

        layout.addWidget(self.face_detection_widget)
        self.run_button = QtWidgets.QPushButton('Start')
        layout.addWidget(self.run_button)

        self.run_button.clicked.connect(self.record_video.start_recording)

        self.screenshot = QtWidgets.QPushButton('Snap Shot')
        layout.addWidget(self.screenshot)

        self.screenshot.clicked.connect(self.record_video.framesave)
        self.setLayout(layout)


    
def main():
    app = QtWidgets.QApplication(sys.argv)

    main_window = QtWidgets.QMainWindow()
    main_widget = MainWidget()
    main_window.setCentralWidget(main_widget)
    main_window.show()

    sys.exit(app.exec_())


if __name__ == '__main__':

    main()

以上是在实时相机视图上进行字符识别的代码。我想添加静态 ROI 来限制感兴趣的区域,下面的代码就是这样做的:

height, width = frame.shape[:2]

            # Define ROI Box Dimensions
            top_left_x = int(width / 3)
            top_left_y = int((height / 2) + (height / 4))
            bottom_right_x = int((width / 3) * 2)
            bottom_right_y = int((height / 2) - (height / 4))

            # Draw rectangular window for our region of interest
            cv2.rectangle(frame, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), 255, 3)

            # Crop window of observation we defined above
            cropped = frame[bottom_right_y:top_left_y, top_left_x:bottom_right_x]

如何为下面的这个功能建立 GUI 连接?

我尝试的是在 FaceDetectionWidget 类下调用此函数,但它不起作用。我想要的是:

我想知道我应该在哪个类中创建这个函数以及如何调用它。

【问题讨论】:

请提供minimal, reproducible example,即使它没有按预期工作。向我们展示您迄今为止的尝试。 我试图从下面的代码中创建函数作为 Record_video 类下的 Static_ROI 并使用 self.record_video.Static_ROI() 调用它但没有工作。然后我尝试了另一种变体,例如在 face_detection 下添加函数并从 init 调用它。因为需要同时处理实时视频和 ROI 平方,所以在我看来它很复杂。我正在努力学习它,这对我来说将是很好的培训。 我不明白。你说你创建了一个Static_ROI 函数(顺便说一句,它在哪里?),但没有工作:what 没有工作?无论如何,如果你想在图像上绘制,你应该在timerEvent 发出信号之前进行。除此之外,是否应该直接在图像上绘制 ROI?不能在paintEvent中画出来吗? 抱歉,我在询问时没有添加我的更新。现在我更新了问题。但我认为 MainWidget 上需要添加一些东西。我需要帮助,因为我不知道应该在那里添加什么。 请回答所有问题:是否要直接在图像上绘制 ROI?在那种情况下,您是否尝试在发出信号之前直接在图像上绘制?如果没有,你不能在paintEvent中画一个矩形吗? 【参考方案1】:

我会让它变得更简单,并在小部件的paintEvent 中绘制 ROI。

class FaceDetectionWidget(QtWidgets.QWidget):
    drawROI = True
    # ...
    def setDrawROI(self, draw):
        self.drawROI = draw
        self.update()

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        painter.drawImage(0, 0, self.image)
        if not self.drawROI:
            return
        width = self.image.width()
        height = self.image.height()
        painter.setPen(QtGui.QPen(QtCore.Qt.red, 2))
        painter.drawRect(width / 3, height / 4, width / 3, height / 2)

然后您可以使用 setDrawROI(True/False) 启用/禁用 ROI。

【讨论】:

不客气!请记住,如果某个答案解决了您的问题,您可能希望通过单击其左侧的复选标记将其设置为已接受。

以上是关于如何在 Python 中将函数连接到 PyQT5 GUI的主要内容,如果未能解决你的问题,请参考以下文章

PyQt 5.6:连接到 DBus 信号挂起

如何在 qt 设计器中将功能连接到 qt 小部件? - Python

pyQt5从dict创建按钮连接到具有附加值的函数

如何在python中将第二行连接到第一行的末尾?

在 Datagrip 中将 Snowflake 数据库连接到 R 和 Python

如何在 Windows GUI 应用程序中将嵌入式 Python 连接到控制台的 I/O?