因为横向课题需要,这是其中的一个小小的功能,单独拎出来作为一个小demo,方便后续学习使用
项目实现功能:
点击open按钮,摄像头开启,实时捕获周围图像并显示
点击capture按钮,保存摄像头照片,类似截图功能
点击close按钮,关闭摄像头
一、Qt页面设计
创建一个Main Window
所用到的控件主要有:一个Label、三个Push Button
我这里保存的名称为:capture.ui
二、创建项目
其实就用到一个文件就行
项目结构如下:
一个主函数文件main.py
,一个ui界面capture.ui
三、导包
from PySide2.QtWidgets import QApplication
from PySide2.QtUiTools import QUiLoader
import cv2
from PySide2.QtWidgets import *
from PySide2.QtGui import QImage, QPixmap
from PySide2.QtCore import Qt, QTimer
import time
四、系统初始化
self.ui = QUiLoader().load('./capture.ui')
把设计好的UI界面加载进来
self.camera_timer = QTimer()
设置一个定时器
def __init__(self):# 加载ui文件self.ui = QUiLoader().load('./capture.ui')self.output_size = 150self.camera_timer = QTimer()# 获取显示器分辨率信息self.desktop = QApplication.desktop()self.screenRect = self.desktop.screenGeometry()self.screenheight = self.screenRect.height()self.screenwidth = self.screenRect.width()print("Screen height {}".format(self.screenheight))print("Screen width {}".format(self.screenwidth))self.ui.setFixedSize(self.ui.width(), self.ui.height())
五、窗口初始化
对每个按钮绑定不同的事件
self.ui.pushButton.clicked.connect(self.open_camera)
pushButton对应的是open,与打开摄像头功能open_camera这个函数进行事件绑定
同理
self.ui.pushButton_2.clicked.connect(self.getcapture)
pushButton_2对应的是capture,与拍摄保存照片功能getcapture这个函数进行事件绑定
self.ui.pushButton_3.clicked.connect(self.close_camera)
pushButton_3对应的是close,与关闭摄像头功能close_camera这个函数进行事件绑定
self.camera_timer.timeout.connect(self.show_image)
定时器超时与show_image函数进行事件绑定
self.i = i = 0;
这里的i用于捕获多张照片的时候命名不重复
def window_init(self):self.ui.pushButton.clicked.connect(self.open_camera)self.ui.pushButton_2.clicked.connect(self.getcapture)self.ui.pushButton_3.clicked.connect(self.close_camera)self.camera_timer.timeout.connect(self.show_image)self.i = i = 0;
六、打开摄像头函数——open_camera实现
cv2.VideoCapture(0)
,调用本地摄像头
若是外设就把参数0改为1
若要播放某段视频就把参数0改为视频的路径即可,记得是字符串形式哈
self.camera_timer.start(40)
,每40ms读取一次,只要读取速度够快,人眼感觉不出来,看到的就是流畅的实时视频
def open_camera(self):self.capture = cv2.VideoCapture(0) # 摄像头self.camera_timer.start(40) # 每40毫秒读取一次,即刷新率为25帧print("open_camera is successful")
七、关闭摄像头函数——close_camera实现
camera_timer.stop()
,摄像头定时器关闭,停止读取
capture.release()
,用于捕获摄像头的每帧图片,释放摄像头资源
ui.label.clear()
,将显示图片的lable控件内容给清除
ui.label.setText("TextLabel")
,在控件上显示点字符串
def close_camera(self): # 关闭摄像头self.camera_timer.stop() # 停止读取self.capture.release() # 释放摄像头self.ui.label.clear() # 清除DisplayInterface组件上的图片self.ui.label.setText("TextLabel") # 设置文字在界面上
八、定时器超时绑定事件函数——show_image实现
打开摄像头之后每隔40ms捕获读取一张,那么这之间的空窗期都干些啥由show_image函数进行控制
flag, self.image = self.capture.read() # 从视频流中读取图片
学过OpenCV的同学就应该知道,flag是个bool类型表示是否读取成功,image就是每一帧的图像
width, height, _ = self.image.shape
得到摄像头照片的宽高信息
self.image_show = cv2.flip(self.image, 1)
因为摄像头拍摄都是镜像,需要中心反转一下
self.image_show = cv2.cvtColor(self.image_show, cv2.COLOR_BGR2RGB)
OpenCV中图像时BGR,但是PySide2里面的图像是RGB,故需要转换一下
self.image_file = QImage(self.image_show.data, height, width, QImage.Format_RGB888)
固定格式,用于PySide里面的图像显示
self.ui.label.setPixmap(QPixmap.fromImage(self.image_file))
将图片image_file显示到label控件上
def show_image(self): # 显示图片flag, self.image = self.capture.read() # 从视频流中读取图片width, height, _ = self.image.shape # 行:宽,列:高self.image_show = cv2.flip(self.image, 1) # 水平翻转,因为摄像头拍的是镜像的。self.image_show = cv2.cvtColor(self.image_show, cv2.COLOR_BGR2RGB) # opencv读的通道是BGR,要转成RGBself.image_file = QImage(self.image_show.data, height, width, QImage.Format_RGB888)self.ui.label.setPixmap(QPixmap.fromImage(self.image_file))self.ui.label.setScaledContents(True) # 让图片自适应 label 大小
九、捕获摄像头函数——getcapture实现
self.i = self.i + 1
每次捕获照片都要自加一下,为了防止名称重复
date_name = time.strftime("%Y%m%d")
获取当前的年月日
image = cv2.flip(self.image, 1)
因为image是摄像头捕获得到的图片,是镜像过的,故需要通过flip函数镜像转换一下
cv2.imwrite("./{}_capture_{}.jpg".format(str(date_name), self.i), image)
将图片保存到当前路径下,命名格式为当前年月日_capture_第几次
self.camera_timer.stop()
,停止读取
self.capture.release()
,释放摄像头资源
def getcapture(self):self.i = self.i + 1;date_name = time.strftime("%Y%m%d")print("getcapture")print(date_name)image = cv2.flip(self.image, 1)cv2.imwrite("./{}_capture_{}.jpg".format(str(date_name), self.i), image)self.camera_timer.stop() # 停止读取self.capture.release() # 释放摄像头
十、主函数入口
gui = Mainwindow()
我的这个类为Mainwindow,当然要根据实际情况定义声明即可
if __name__ == '__main__':app = QApplication([])gui = Mainwindow() #初始化gui.window_init()gui.ui.show() #将窗口控件显示在屏幕上app.exit(app.exec_())
十一、完整代码
main.py
from PySide2.QtWidgets import QApplication
from PySide2.QtUiTools import QUiLoader
import cv2
from PySide2.QtWidgets import *
from PySide2.QtGui import QImage, QPixmap
from PySide2.QtCore import Qt, QTimer
import timeclass Mainwindow(object):def __init__(self):# 加载ui文件self.ui = QUiLoader().load('./capture.ui')self.output_size = 150self.camera_timer = QTimer()# 获取显示器分辨率self.desktop = QApplication.desktop()self.screenRect = self.desktop.screenGeometry()self.screenheight = self.screenRect.height()self.screenwidth = self.screenRect.width()print("Screen height {}".format(self.screenheight))print("Screen width {}".format(self.screenwidth))self.ui.setFixedSize(self.ui.width(), self.ui.height())def window_init(self):self.ui.pushButton.clicked.connect(self.open_camera)self.ui.pushButton_2.clicked.connect(self.getcapture)self.ui.pushButton_3.clicked.connect(self.close_camera)self.camera_timer.timeout.connect(self.show_image)self.i = i = 0def getcapture(self):self.i = self.i + 1date_name = time.strftime("%Y%m%d")print("getcapture")print(date_name)image = cv2.flip(self.image, 1)cv2.imwrite("./{}_capture_{}.jpg".format(str(date_name), self.i), image)self.camera_timer.stop() # 停止读取self.capture.release() # 释放摄像头def open_camera(self):self.capture = cv2.VideoCapture(0) # 摄像头self.camera_timer.start(40) # 每40毫秒读取一次,即刷新率为25帧print("open_camera is successful")def close_camera(self): # 关闭摄像头self.camera_timer.stop() # 停止读取self.capture.release() # 释放摄像头self.ui.label.clear() # 清除DisplayInterface组件上的图片self.ui.label.setText("TextLabel") # 设置文字在界面上def show_image(self): # 显示图片flag, self.image = self.capture.read() # 从视频流中读取图片width, height, _ = self.image.shape # 行:宽,列:高self.image_show = cv2.flip(self.image, 1) # 水平翻转,因为摄像头拍的是镜像的。self.image_show = cv2.cvtColor(self.image_show, cv2.COLOR_BGR2RGB) # opencv读的通道是BGR,要转成RGBself.image_file = QImage(self.image_show.data, height, width, QImage.Format_RGB888)self.ui.label.setPixmap(QPixmap.fromImage(self.image_file))self.ui.label.setScaledContents(True) # 让图片自适应 label 大小if __name__ == '__main__':app = QApplication([])gui = Mainwindow() #初始化gui.window_init()gui.ui.show() #将窗口控件显示在屏幕上app.exit(app.exec_())
十二、运行结果
目前项目下一张图片都没
open
capture
捕捉之后项目下会保存刚才抓拍的图片
close