OpenCV-Python入门教程7-PyQt编写GUI界面
前面一直都是使用命令行运行代码,不够人性化。这篇用Python编写一个GUI界面,使用PyQt5编写图像处理程序。包括:打开、关闭摄像头,捕获图片,读取本地图片,灰度化和Otsu自动阈值分割的功能。
使用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\
生成一个简单的界面,后面还会用到
- import sys
- from PyQt5.QtWidgets import QApplication, QWidget
- if __name__ == '__main__':
- app = QApplication(sys.argv)
- window = QWidget()
- window.setWindowTitle('Hello World!')
- window.show()
- sys.exit(app.exec_())
一、界面设计
在D:\ProgramData\Anaconda3\Library\bin\下打开designer.exe,会弹出创建新窗体的窗口,我们直接点击"创建"(英文版是create)
界面左侧是Qt的常用控件"Widget Box",右侧有一个控件属性窗口"Property Editor"。本例中我们只用到了"Push Button"控件和"Label"控件,可以在属性窗口调整它的大小150x150(可以根据自己的需求适当调大或者缩小):
控件上显示的文字"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"可以恢复正常视图:
在弹出的配置窗口中,可以看到左侧是按钮的常用事件,我们选择点击事件”clicked()”,然后添加一个名为”btnOpenCamera_Clicked()”的槽函数:
重复上面的步骤,给五个按钮添加五个槽函数,最终结果如下:
Ctrl + S保存.ui文件。我们需要将ui转py代码。
打开cmd命令行,切换到ui文件的保存目录。Windows下有个小技巧,可以在目录的地址栏输入cmd,一步切换到当前目录:
执行这条指令
pyuic5 -o mainForm.py using_pyqt_create_ui.ui
生成mainForm.py文件,里面包含一个名为”Ui_MainWindow”的类。
二、编写逻辑代码
mainForm.py是根据ui文件生成的,也就是说,一旦ui文件有所改变,需要重新生成覆盖原来的文件。
新建一个mainEntry.py存放逻辑代码,代码虽然很长,但是很简单并不难懂。有些部分有所重复,并没有将其封装成一个函数(博主能力有限),感兴趣的可以试一下
- import sys
- import cv2
- from PyQt5 import QtCore, QtGui, QtWidgets
- from PyQt5.QtCore import *
- from PyQt5.QtGui import *
- from PyQt5.QtWidgets import QFileDialog, QMainWindow
- from mainForm import Ui_MainWindow
- class PyQtMainEntry(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)
- def btnOpenCamera_Clicked(self):
- '''
- 打开和关闭摄像头
- '''
- self.is_camera_opened = ~self.is_camera_opened
- if self.is_camera_opened:
- self.btnOpenCamera.setText("关闭摄像头")
- self._timer.start()
- else:
- self.btnOpenCamera.setText("打开摄像头")
- self._timer.stop()
- def btnCapture_Clicked(self):
- '''
- 捕获图片
- '''
- # 摄像头未打开,不执行任何操作
- if not self.is_camera_opened:
- return
- self.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))
- def btnReadImage_Clicked(self):
- '''
- 从本地读取图片 文件路径不能有中文
- '''
- # 打开文件选取对话框
- filename, _ = QFileDialog.getOpenFileName(self, '打开图片')
- if filename:
- 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))
- def btnGray_Clicked(self):
- '''
- 灰度化
- '''
- # 如果没有捕获图片,则不执行操作
- if not hasattr(self, "captured"):
- return
- self.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))
- def btnThreshold_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_())
参考网址:https://tianchi.aliyun.com/course/courseConsole?courseId=40992&chapterIndex=1§ionIndex=16
OpenCV-Python入门教程7-PyQt编写GUI界面的更多相关文章
- Python入门教程 超详细1小时学会Python
Python入门教程 超详细1小时学会Python 作者: 字体:[增加 减小] 类型:转载 时间:2006-09-08我要评论 本文适合有经验的程序员尽快进入Python世界.特别地,如果你掌握Ja ...
- Python入门教程 超详细1小时学会Python
Python入门教程 超详细1小时学会Python 本文适合有经验的程序员尽快进入Python世界.特别地,如果你掌握Java和Javascript,不用1小时你就可以用Python快速流畅地写有用的 ...
- 2018-06-20 中文代码示例视频演示Python入门教程第三章 简介Python
知乎原链 Python 3.6.5官方入门教程中示例代码汉化后演示 对应在线文档: 3. An Informal Introduction to Python 不知如何合集, 请指教. 中文代码示例P ...
- 毫无基础的人入门Python,Python入门教程
随着人工智能的发展,Python近两年也是大火,越来越多的人加入到Python学习大军,对于毫无基础的人该如何入门Python呢?这里整理了一些个人经验和Python入门教程供大家参考. 如果你是零基 ...
- 老鸟的Python入门教程
转自老鸟的Python入门教程 重要说明 这不是给编程新手准备的教程,如果您入行编程不久,或者还没有使用过1到2门编程语言,请移步!这是有一定编程经验的人准备的.最好是熟知Java或C,懂得命令行,S ...
- 2018-06-21 中文代码示例视频演示Python入门教程第五章 数据结构
知乎原链 续前作: 中文代码示例视频演示Python入门教程第四章 控制流 对应在线文档: 5. Data Structures 这一章起初还是采取了尽量与原例程相近的汉化方式, 但有些语义较偏(如T ...
- 2018-06-20 中文代码示例视频演示Python入门教程第四章 控制流
知乎原链 续前作: 中文代码示例视频演示Python入门教程第三章 简介Python 对应在线文档: 4. More Control Flow Tools 录制中出了不少岔子. 另外, 输入法确实是一 ...
- 极度舒适的 Python 入门教程,小猪佩奇也能学会~
编程几乎已经成为现代人的一门必修课,特别是 Python ,不仅长期霸占编程趋势榜.薪资榜第一,还屡屡进入小学教材,甚至成为浙江省信息技术高考项目-- 今天,小编带来了一门极度舒适的 Python 入 ...
- Python入门教程完整版(懂中文就能学会)
前几天给大家分享<从零学会Photoshop经典教程300集>的教程受到了广泛的关注,有人不知道怎么领取,居然称小编为"骗子". 不过小编的内心是强大的,网友虐我千百遍 ...
- python实现串口通讯小程序(GUI界面)
python实现串口通讯小程序(GUI界面) 使用python实现串口通讯需要使用python的pyserial库来实现,这个库在安装python的时候没有自动进行安装,需要自己进行安装. 1.安装p ...
随机推荐
- CentOS 7 安装配置 MySQL
https://blog.imzhengfei.com/centos-7-an-zhuang-pei-zhi-mysql/ MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前 ...
- [转] 隐马尔可夫(HMM)、前/后向算法、Viterbi算法 再次总结
最近工作需要优化LSTM-CRF经典模型中的维特比解码部分,发现对维特比一直是个模糊概念,没有get到本质,搜了一圈,发现一篇好文,mark 博主不让转载,mark个地址吧: https://blog ...
- Three.js基础探寻四——立方体、平面与球体
前面简单介绍了webGL和Three.js的背景以及照相机的设定,接下来介绍一些Three.js中的几何形状. 1.立方体 虽然这一形状的名字叫立方体(CubeGeometry),但它其实是长方体,也 ...
- MFC修改对话框标题
对话框标题栏内容为静态 直接在对话框属性"常规"的"Caption"中修改. 动态生成对话框标题栏内容 SetWindowText()函数就可以 CString ...
- android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论【转】
转自:https://www.cnblogs.com/deman/p/5584198.html 阅读目录 1.OpenGL & OpenGL ES 2.Android的硬件接口HAL 3.An ...
- Delphi 实现自动更新
Delphi 通用程序自动更新升级:http://www.delphitop.com/html/wangluo/2968.html https://www.cnblogs.com/hnxxcxg/p/ ...
- Memcached技术
Memcached技术 介绍: memcached是一种缓存技术, 他可以把你的数据放入内存,从而通过内存访问提速,因为内存最快的, memcached技术的主要目的提速, 在memachec 中维护 ...
- 《The Practice and Theory of Bolshevism》的笔记-第114页
章节名:International Policy 页码:第114页 2017-09-30 15:11:24 Among religions, Bolshevism is to be reckoned ...
- HTML5 播放器
之前一个前端群里 大牛 做了一个自适应的HMLT5播放器 最近根据其思路做了一个相对单一移动端的demo,demo用的图片和歌曲json的数据设计 都是群里大牛做的,在这谢谢~: 同时借鉴的几篇文章: ...
- tcpdump抓取mysql语句
抓包工具tcpdump的使用,抓取具体的sql语句 [root@test7_chat_api_im ~]# tcpdump -s -l - |strings tcpdump: listening on ...