1、首先进行ui布局,初始化界面设置四个按键和一块黑色的背景布,四个按键功能设置为打开摄像头、关闭摄像头、拍照、录像,如图:
open和close是二选一的,点击open以后除了打开和显示摄像头画面,还得把close按键使能,把open停止
再点击close就会回到黑色背景的时候,并且把打开的摄像头关闭,释放摄像头占用的内存,以便下次打开
两个按键可以交替的控制摄像头读取,内存的占用和释放。
实现的过程为:
self.openCameraBtn = QPushButton(‘open’) 这是设置名为open的按键
self.openCameraBtn.clicked.connect(self.openCamera) 这是设置按键按下后促发的函数连接,即设置按键open按下促发openCamera函数的执行。
self.openCameraBtn.setEnabled(True) 这是使能该按键
self.openCameraBtn.setEnabled(False) 这是关闭该按键
这里的摄像头图像显示还涉及定时刷新的问题。所以在程序启动的时候除了初始化UI还会初始化一个定时器:
def initTimer(self):
self.timer = QTimer(self)#导入定时器
self.timer.timeout.connect(self.show_pic)#超时刷新函数self.show_pic
def show_pic(self):
ret, img = self.camera.read()
if not ret:
print('read error!\n')
self.closeCamera()
csbox = QMessageBox(QMessageBox.Warning, self.tr("读取失败"), self.tr("摄像头打开失败,请检查连接!"), QMessageBox.NoButton, self)
csbox.exec_()
return
# cv2.flip(img, 1, img)#参数:原始图像,翻转类型,新图像 翻转类型:水平(左右)翻转>0,垂直(上下)翻转=0,水平和垂直翻转<0
frame = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print(frame.shape)#(480, 640, 3) 行数,列数,色彩通道数(即RGB) img.shape[0]得到的是图片的高,img.shape[1]得到是图片的宽
heigt, width = frame.shape[:2]#[0]和[1]
pixmap = QImage(frame, width, heigt, QImage.Format_RGB888)#读取图像
# print(pixmap)
pixmap = QPixmap.fromImage(pixmap)
self.showcamera.setPixmap(pixmap)#设置像素
self.imgsave=img
if self.opencameras==True and self.openvideo==True:
self.out.write(frame)
self.videoCameraBtn.setEnabled(False)
else:
print(self.openvideo)
self.openvideo=False
self.videoCameraBtn.setEnabled(True)
2、接下来是设置拍照功能,按下拍照按键后会进入pictureCamera函数,函数内容如下,可以看到这里是有检测确保摄像头打开才进行读写图像数据,如果不确保摄像头打开,数据为空,在写入图的时候就会报错,拍照和录像之前都是得确保摄像头已经打开。
if self.opencameras==True:#摄像头已经打开
img_name = 'pictures/%d.jpg'%self.count
cv2.imwrite(img_name, self.imgsave) #训练集写入路径
self.count += 1
cv2.imshow("camera", self.imgsave)
可以看到,在按下拍照后是会把当前的一直摄像头的状态保存写入一个按顺序命名的图片,并且还会弹出一个拍到的图像画面。
3、下面是设置录像功能,按下录像按键后会进入videoCamera函数,函数内容如下,可以看到这里也是有检测确保摄像头打开才进行读写图像数据。
if self.opencameras==True:#摄像头已经打开
self.nowtimes = time.strftime("%Y-%m-%d_%H_%M_%S_%p",time.localtime())+"_"+time.strftime("%u",time.localtime())
videos='./videos/'+self.nowtimes+'.avi'
print(videos)
self.out = cv2.VideoWriter(videos,self.fourcc, 20.0, (640,480))#创建一个录像文件
self.openvideo=True #打开录像文件的标记
self.videoCameraBtn.setEnabled(False)
这里除了正常的一个创建录像文件的过程,还多了一个关闭录像按键,这也表明录像按下一次只能生成一个avi文件,每次定时刷新图像的时候都会判断一下是否处于录像过程,如果处于录像就把从摄像头读取的frame写入到录像文件
if self.opencameras==True and self.openvideo==True:
self.out.write(frame)
self.videoCameraBtn.setEnabled(False)
else:
print(self.openvideo)
self.openvideo=False
self.videoCameraBtn.setEnabled(True)
如下图就是在录像的过程:
停止录像就按closs关闭摄像头就可以。关闭按键连接的函数内容如下:
self.camera.release()#释放占用的摄像头
if self.openvideo==True:
self.out.release()
self.openCameraBtn.setEnabled(True)
self.closeCameraBtn.setEnabled(False)#关闭按键使能
self.videoCameraBtn.setEnabled(True)#使能按键
self.showcamera.setStyleSheet("background:black;")#设置样式:背景为黑色
self.showcamera.setPixmap(QPixmap())#设置像素
self.timer.stop()#定时器停止
self.opencameras=False
self.openvideo=False
可以看到函数包含了几个部分,一个是处理摄像头,释放摄像头占用的内存;二个是按键的ui处理,即使能打开按键和录像按键,关闭摄像头按键的去使能;三个是时钟的处理,停止定时器,目的是停止显示摄像头采集图像,不停止就会报错,因为已经释放了摄像头的内存,所以,时钟定时刷新的图像已经采集不到内容,所有就会报错。
以下是项目源码:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import cv2
import sys
import os
import time
def chdir(path):
# 引入模块
import os
# 去除首位空格
path = path.strip()
# 去除尾部 \ 符号
path = path.rstrip("\\")
# 判断路径是否存在
# 存在 True
# 不存在 False
isExists = os.path.exists(path)
# 判断结果
if not isExists:
# 如果不存在则创建目录
# 创建目录操作函数
print(path + ' 目录不存在')
return False
else:
# 如果目录存在则不创建,并提示目录已存在
print(path + ' 目录已存在')
return True
#读取备份文件列表
def read_filename(filePath):
import os
name = os.listdir(filePath)#获取filepath的文件列表
print(name)
return name
class Example(QWidget):
def __init__(self):
super().__init__()
#检查和创建文件夹
if chdir('pictures')==False:
os.mkdir('pictures')
if chdir('videos')==False:
os.mkdir('videos')
print(len(read_filename('pictures')))
# self.fourcc = cv2.VideoWriter_fourcc(*'XVID')#FourCC 就是一个 4 字节码,用来确定视频的编码格式
self.fourcc = cv2.VideoWriter_fourcc(*'MJPG')
self.nowtimes=' '
self.opencameras=False
self.openvideo=False
self.count = int(len(read_filename('pictures')))
self.initUI()
self.initTimer()
def initTimer(self):
self.timer = QTimer(self)#导入定时器
self.timer.timeout.connect(self.show_pic)#超时刷新函数self.show_pic
def show_pic(self):
ret, img = self.camera.read()
if not ret:
print('read error!\n')
self.closeCamera()
csbox = QMessageBox(QMessageBox.Warning, self.tr("读取失败"), self.tr("摄像头打开失败,请检查连接!"), QMessageBox.NoButton, self)
csbox.exec_()
return
# cv2.flip(img, 1, img)#参数:原始图像,翻转类型,新图像 翻转类型:水平(左右)翻转>0,垂直(上下)翻转=0,水平和垂直翻转<0
frame = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print(frame.shape)#(480, 640, 3) 行数,列数,色彩通道数(即RGB) img.shape[0]得到的是图片的高,img.shape[1]得到是图片的宽
heigt, width = frame.shape[:2]#[0]和[1]
pixmap = QImage(frame, width, heigt, QImage.Format_RGB888)#读取图像
# print(pixmap)
pixmap = QPixmap.fromImage(pixmap)
self.showcamera.setPixmap(pixmap)#设置像素
self.imgsave=img
if self.opencameras==True and self.openvideo==True:
self.out.write(frame)
self.videoCameraBtn.setEnabled(False)
else:
print(self.openvideo)
self.openvideo=False
self.videoCameraBtn.setEnabled(True)
def openCamera(self):
self.showcamera.setEnabled(True)
self.camera = cv2.VideoCapture(0) #'http://admin:admin@192.168.100.245:8081'
# self.camera = cv2.VideoCapture('http://admin:admin@192.168.100.245:8081')
self.openCameraBtn.setEnabled(False)#关闭按键
self.closeCameraBtn.setEnabled(True)#使能按键
self.timer.start(3)#定时3 开始计时
self.opencameras=True
def closeCamera(self):
self.camera.release()#释放占用的摄像头
if self.openvideo==True:
self.out.release()
self.openCameraBtn.setEnabled(True)
self.closeCameraBtn.setEnabled(False)#关闭按键使能
self.videoCameraBtn.setEnabled(True)#使能按键
self.showcamera.setStyleSheet("background:black;")#设置样式:背景为黑色
self.showcamera.setPixmap(QPixmap())#设置像素
self.timer.stop()#定时器停止
self.opencameras=False
self.openvideo=False
def pictureCamera(self):
print('picture')
if self.opencameras==True:#摄像头已经打开
img_name = 'pictures/%d.jpg'%self.count
cv2.imwrite(img_name, self.imgsave) #训练集写入路径
self.count += 1
cv2.imshow("camera", self.imgsave)
def videoCamera(self):
print('video')
if self.opencameras==True:#摄像头已经打开
self.nowtimes = time.strftime("%Y-%m-%d_%H_%M_%S_%p",time.localtime())+"_"+time.strftime("%u",time.localtime())
videos='./videos/'+self.nowtimes+'.avi'
print(videos)
self.out = cv2.VideoWriter(videos,self.fourcc, 20.0, (640,480))#创建一个录像文件
self.openvideo=True #打开录像文件的标记
self.videoCameraBtn.setEnabled(False)
def initUI(self):
self.openCameraBtn = QPushButton('open')
self.openCameraBtn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) #设置控件在布局(layout)里面的大小变化的属性 QSizePolicy.Fixed:固定大小,不可拉伸或者压缩
self.openCameraBtn.clicked.connect(self.openCamera)
self.closeCameraBtn = QPushButton('close')
self.closeCameraBtn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.closeCameraBtn.clicked.connect(self.closeCamera)
self.pictureCameraBtn = QPushButton('拍照')
self.pictureCameraBtn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) #设置控件在布局(layout)里面的大小变化的属性 QSizePolicy.Fixed:固定大小,不可拉伸或者压缩
self.pictureCameraBtn.clicked.connect(self.pictureCamera)
self.videoCameraBtn = QPushButton('录像')
self.videoCameraBtn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self.videoCameraBtn.clicked.connect(self.videoCamera)
self.openCameraBtn.setEnabled(True)
self.closeCameraBtn.setEnabled(False)
self.showcamera = QLabel(self)
self.showcamera.resize(640, 480)
self.hbox = QHBoxLayout(self)#水平布局
self.hbox.addWidget(self.showcamera)#在水平布局的基础上添加控件 addwidget()方法用于向布局中添加控件
self.vbox = QVBoxLayout(self)#垂直布局
self.vbox.addWidget(self.openCameraBtn)
self.vbox.addWidget(self.closeCameraBtn)
self.vbox.addWidget(self.pictureCameraBtn)
self.vbox.addWidget(self.videoCameraBtn)
self.hbox.addLayout(self.vbox)
self.setLayout(self.hbox)#setLayout是将已设置好的布局应用到控件中去
self.showcamera.setStyleSheet("background:black;")#设置样式:背景为黑色
self.showcamera.setPixmap(QPixmap())#设置像素
# self.move(300, 300)
self.setWindowTitle('camera')
self.setGeometry(600, 200, 760, 510)
self.show()
def closeEvent(self, event):
reply = QMessageBox.question(self, '提示', "确定退出吗?", QMessageBox.Yes |QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
if __name__=='__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
下面是运行视频:
【cameras-哔哩哔哩】 https://b23.tv/DY6bOAM
cameras