python gui界面编写_OpenCV-Python入门教程7-PyQt编写GUI界面

前面一直都是使用命令行运行代码,不够人性化。这篇用Python编写一个GUI界面,使用PyQt5编写图像处理程序。包括:打开、关闭摄像头,捕获图片,读取本地图片,灰度化和Otsu自动阈值分割的功能。

1490325-20190119103717395-656645944.png

使用Qt Designer来设计界面。而anaconda里自带了designer.exe,我使用的就是这个。designer.exe的路径:D:\ProgramData\Anaconda3\Library\bin\,如果是普通的Python环境,则需要自行安装

pip install pyqt5-tools

安装完成后,designer.exe应该在Python的安装目录下:xxx\Lib\site-packages\pyqt5_tools\

生成一个简单的界面,后面还会用到

importsysfrom PyQt5.QtWidgets importQApplication, QWidgetif __name__ == '__main__':

app=QApplication(sys.argv)

window=QWidget()

window.setWindowTitle('Hello World!')

window.show()

sys.exit(app.exec_())

1490325-20190118210806194-1697169518.png

一、界面设计

在D:\ProgramData\Anaconda3\Library\bin\下打开designer.exe,会弹出创建新窗体的窗口,我们直接点击"创建"(英文版是create)

1490325-20190118213447472-1011239628.png

界面左侧是Qt的常用控件"Widget Box",右侧有一个控件属性窗口"Property Editor"。本例中我们只用到了"Push Button"控件和"Label"控件,可以在属性窗口调整它的大小150x150(可以根据自己的需求适当调大或者缩小):

1490325-20190118214300593-1017660008.jpg

1490325-20190118214402317-1677869772.jpg

控件上显示的文字"text"属性和控件的名字"objectName"属性需要修改,便于显示和代码调用,可以按照下面的表格命名:

控件

显示内容text

控件名objectName

PushButton

打开摄像头

btnOpenCamera

PushButton

捕获图片

btnCapture

PushButton

打开图片

btnReadImage

PushButton

灰度化

btnGray

PushButton

阈值分割

btnThreshold

Label

摄像头

labelCamera

Label

捕获图

labelCapture

Label

结果图

labelResult

前面设计好了界面,接下来就是实现"打开摄像头"到"阈值分割"这五个按钮的功能,也就是给每个按钮指定一个函数,逻辑代码写在这个函数里面。这个函数就称事件,Qt中称为槽连接

点击Designer工具栏的Edit Signals/Slots按钮,进入槽函数编辑界面,点击旁边的"Edit Widgets"可以恢复正常视图:

1490325-20190118215810729-1932765656.gif

在弹出的配置窗口中,可以看到左侧是按钮的常用事件,我们选择点击事件”clicked()”,然后添加一个名为”btnOpenCamera_Clicked()”的槽函数:

1490325-20190118215859058-687888393.gif

重复上面的步骤,给五个按钮添加五个槽函数,最终结果如下:

1490325-20190118215958836-1299284228.jpg

Ctrl + S保存.ui文件。我们需要将ui转py代码。

打开cmd命令行,切换到ui文件的保存目录。Windows下有个小技巧,可以在目录的地址栏输入cmd,一步切换到当前目录:

1490325-20190118220254512-601039435.gif

执行这条指令

pyuic5 -o mainForm.py using_pyqt_create_ui.ui

生成mainForm.py文件,里面包含一个名为”Ui_MainWindow”的类。

二、编写逻辑代码

mainForm.py是根据ui文件生成的,也就是说,一旦ui文件有所改变,需要重新生成覆盖原来的文件。

新建一个mainEntry.py存放逻辑代码,代码虽然很长,但是很简单并不难懂。有些部分有所重复,并没有将其封装成一个函数(博主能力有限),感兴趣的可以试一下

importsysimportcv2from PyQt5 importQtCore, QtGui, QtWidgetsfrom PyQt5.QtCore import *

from PyQt5.QtGui import *

from PyQt5.QtWidgets importQFileDialog, QMainWindowfrom mainForm importUi_MainWindowclassPyQtMainEntry(QMainWindow, Ui_MainWindow):def __init__(self):

super().__init__()

self.setupUi(self)

self.camera=cv2.VideoCapture(0)

self.is_camera_opened= False #摄像头有没有打开标记

#定时器:30ms捕获一帧

self._timer =QtCore.QTimer(self)

self._timer.timeout.connect(self._queryFrame)

self._timer.setInterval(30)defbtnOpenCamera_Clicked(self):'''打开和关闭摄像头'''self.is_camera_opened= ~self.is_camera_openedifself.is_camera_opened:

self.btnOpenCamera.setText("关闭摄像头")

self._timer.start()else:

self.btnOpenCamera.setText("打开摄像头")

self._timer.stop()defbtnCapture_Clicked(self):'''捕获图片'''

#摄像头未打开,不执行任何操作

if notself.is_camera_opened:returnself.captured=self.frame#后面这几行代码几乎都一样,可以尝试封装成一个函数

rows, cols, channels =self.captured.shape

bytesPerLine= channels *cols#Qt显示图片时,需要先转换成QImgage类型

QImg =QImage(self.captured.data, cols, rows, bytesPerLine, QImage.Format_RGB888)

self.labelCapture.setPixmap(QPixmap.fromImage(QImg).scaled(

self.labelCapture.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))defbtnReadImage_Clicked(self):'''从本地读取图片 文件路径不能有中文'''

#打开文件选取对话框

filename, _ = QFileDialog.getOpenFileName(self, '打开图片')iffilename:

self.captured=cv2.imread(str(filename))#OpenCV图像以BGR通道存储,显示时需要从BGR转到RGB

self.captured =cv2.cvtColor(self.captured, cv2.COLOR_BGR2RGB)

rows, cols, channels=self.captured.shape

bytesPerLine= channels *cols

QImg=QImage(self.captured.data, cols, rows, bytesPerLine, QImage.Format_RGB888)

self.labelCapture.setPixmap(QPixmap.fromImage(QImg).scaled(

self.labelCapture.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))defbtnGray_Clicked(self):'''灰度化'''

#如果没有捕获图片,则不执行操作

if not hasattr(self, "captured"):returnself.cpatured=cv2.cvtColor(self.captured, cv2.COLOR_RGB2GRAY)

rows, columns=self.cpatured.shape

bytesPerLine=columns#灰度图是单通道,所以需要用Format_Indexed8

QImg =QImage(self.cpatured.data, columns, rows, bytesPerLine, QImage.Format_Indexed8)

self.labelResult.setPixmap(QPixmap.fromImage(QImg).scaled(

self.labelResult.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))defbtnThreshold_Clicked(self):'''Otsu自动阈值分割'''

if not hasattr(self, "captured"):return_, self.cpatured=cv2.threshold(

self.cpatured, 0,255, cv2.THRESH_BINARY +cv2.THRESH_OTSU)

rows, columns=self.cpatured.shape

bytesPerLine=columns#阈值分割图也是单通道,也需要用Format_Indexed8

QImg =QImage(self.cpatured.data, columns, rows, bytesPerLine, QImage.Format_Indexed8)

self.labelResult.setPixmap(QPixmap.fromImage(QImg).scaled(

self.labelResult.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))

@QtCore.pyqtSlot()def_queryFrame(self):'''循环捕获图片'''ret, self.frame=self.camera.read()

img_rows, img_cols, channels=self.frame.shape

bytesPerLine= channels *img_cols

cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB, self.frame)

QImg=QImage(self.frame.data, img_cols, img_rows, bytesPerLine, QImage.Format_RGB888)

self.labelCamera.setPixmap(QPixmap.fromImage(QImg).scaled(

self.labelCamera.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))if __name__ == "__main__":

app=QtWidgets.QApplication(sys.argv)

window=PyQtMainEntry()

window.show()

sys.exit(app.exec_())

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值