利用Python开发多路显示USB摄像头
1、项目介绍
- 这是一个用来测试多个USB摄像头同时打开、拍照保存图像的小工具
1.1 开发环境:
python3.6.5
pycharm2018专业版
PyQt5 5.6
opencv-python
QT Designer
1.2 硬件准备:
- 3~4个USB摄像头
1.3 新建项目文件夹:
确认pycharm已经配置好tools环境,方便打开QT设计师工具
目录结构:
2、设计界面布局和按钮功能
- 利用pycharm打开QT Designer设计工具的界面布局,设计结果如下图。
回到pycharm中,利用pyuic将刚刚设计好的界面UI文件,生成对应的UI文件代码。
- 下面是生成好的UI文件代码,保存的时候修改模块名称:如multiplexer_camera.py,运行如上图所示。
# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(700, 500)
Form.setMinimumSize(QtCore.QSize(700, 500))
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
self.verticalLayout.setContentsMargins(5, 5, 5, 5)
self.verticalLayout.setObjectName("verticalLayout")
self.widget_3 = QtWidgets.QWidget(Form)
self.widget_3.setMaximumSize(QtCore.QSize(16777215, 46))
self.widget_3.setObjectName("widget_3")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget_3)
self.horizontalLayout.setObjectName("horizontalLayout")
self.pushButton = QtWidgets.QPushButton(self.widget_3)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth())
self.pushButton.setSizePolicy(sizePolicy)
self.pushButton.setMinimumSize(QtCore.QSize(130, 0))
self.pushButton.setMaximumSize(QtCore.QSize(150, 16777215))
self.pushButton.setObjectName("pushButton")
self.horizontalLayout.addWidget(self.pushButton)
self.pushButton_2 = QtWidgets.QPushButton(self.widget_3)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_2.sizePolicy().hasHeightForWidth())
self.pushButton_2.setSizePolicy(sizePolicy)
self.pushButton_2.setMinimumSize(QtCore.QSize(130, 0))
self.pushButton_2.setMaximumSize(QtCore.QSize(150, 16777215))
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout.addWidget(self.pushButton_2)
self.pushButton_4 = QtWidgets.QPushButton(self.widget_3)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_4.sizePolicy().hasHeightForWidth())
self.pushButton_4.setSizePolicy(sizePolicy)
self.pushButton_4.setMinimumSize(QtCore.QSize(130, 0))
self.pushButton_4.setObjectName("pushButton_4")
self.horizontalLayout.addWidget(self.pushButton_4)
self.pushButton_3 = QtWidgets.QPushButton(self.widget_3)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton_3.sizePolicy().hasHeightForWidth())
self.pushButton_3.setSizePolicy(sizePolicy)
self.pushButton_3.setMinimumSize(QtCore.QSize(130, 0))
self.pushButton_3.setMaximumSize(QtCore.QSize(150, 16777215))
self.pushButton_3.setObjectName("pushButton_3")
self.horizontalLayout.addWidget(self.pushButton_3)
self.verticalLayout.addWidget(self.widget_3)
self.widget = QtWidgets.QWidget(Form)
self.widget.setStyleSheet("background-color: rgb(194, 255, 250);")
self.widget.setObjectName("widget")
self.gridLayout = QtWidgets.QGridLayout(self.widget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setSpacing(5)
self.gridLayout.setObjectName("gridLayout")
self.gridLayout_3 = QtWidgets.QGridLayout()
self.gridLayout_3.setObjectName("gridLayout_3")
self.label_2 = QtWidgets.QLabel(self.widget)
self.label_2.setMaximumSize(QtCore.QSize(16777215, 20))
self.label_2.setStyleSheet("background-color: rgb(255, 255, 127);")
self.label_2.setAlignment(QtCore.Qt.AlignCenter)
self.label_2.setObjectName("label_2")
self.gridLayout_3.addWidget(self.label_2, 0, 0, 1, 1)
self.show_video2 = QtWidgets.QLabel(self.widget)
self.show_video2.setStyleSheet("background-color: rgb(170, 170, 255);")
self.show_video2.setAlignment(QtCore.Qt.AlignCenter)
self.show_video2.setObjectName("show_video2")
self.gridLayout_3.addWidget(self.show_video2, 1, 0, 1, 1)
self.gridLayout.addLayout(self.gridLayout_3, 0, 1, 1, 1)
self.gridLayout_2 = QtWidgets.QGridLayout()
self.gridLayout_2.setObjectName("gridLayout_2")
self.show_video1 = QtWidgets.QLabel(self.widget)
self.show_video1.setStyleSheet("background-color: rgb(170, 170, 255);")
self.show_video1.setAlignment(QtCore.Qt.AlignCenter)
self.show_video1.setObjectName("show_video1")
self.gridLayout_2.addWidget(self.show_video1, 2, 0, 1, 1)
self.label = QtWidgets.QLabel(self.widget)
self.label.setMaximumSize(QtCore.QSize(16777215, 20))
self.label.setStyleSheet("background-color: rgb(255, 255, 127);")
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
self.gridLayout.addLayout(self.gridLayout_2, 0, 0, 1, 1)
self.gridLayout_6 = QtWidgets.QGridLayout()
self.gridLayout_6.setObjectName("gridLayout_6")
self.label_8 = QtWidgets.QLabel(self.widget)
self.label_8.setMaximumSize(QtCore.QSize(16777215, 20))
self.label_8.setStyleSheet("background-color: rgb(255, 255, 127);")
self.label_8.setAlignment(QtCore.Qt.AlignCenter)
self.label_8.setObjectName("label_8")
self.gridLayout_6.addWidget(self.label_8, 0, 0, 1, 1)
self.show_video3 = QtWidgets.QLabel(self.widget)
self.show_video3.setStyleSheet("background-color: rgb(170, 170, 255);")
self.show_video3.setAlignment(QtCore.Qt.AlignCenter)
self.show_video3.setObjectName("show_video3")
self.gridLayout_6.addWidget(self.show_video3, 1, 0, 1, 1)
self.gridLayout.addLayout(self.gridLayout_6, 1, 0, 1, 1)
self.gridLayout_7 = QtWidgets.QGridLayout()
self.gridLayout_7.setObjectName("gridLayout_7")
self.label_9 = QtWidgets.QLabel(self.widget)
self.label_9.setMaximumSize(QtCore.QSize(16777215, 20))
self.label_9.setStyleSheet("background-color: rgb(255, 255, 127);")
self.label_9.setAlignment(QtCore.Qt.AlignCenter)
self.label_9.setObjectName("label_9")
self.gridLayout_7.addWidget(self.label_9, 0, 0, 1, 1)
self.show_video4 = QtWidgets.QLabel(self.widget)
self.show_video4.setStyleSheet("background-color: rgb(170, 170, 255);")
self.show_video4.setAlignment(QtCore.Qt.AlignCenter)
self.show_video4.setObjectName("show_video4")
self.gridLayout_7.addWidget(self.show_video4, 1, 0, 1, 1)
self.gridLayout.addLayout(self.gridLayout_7, 1, 1, 1, 1)
self.verticalLayout.addWidget(self.widget)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "显示多路USB摄像头"))
self.pushButton.setText(_translate("Form", "显示摄像头图像"))
self.pushButton_2.setText(_translate("Form", "保存图片"))
self.pushButton_4.setText(_translate("Form", "暂停播放"))
self.pushButton_3.setText(_translate("Form", "退出程序"))
self.label_2.setText(_translate("Form", "摄像头②"))
self.show_video2.setText(_translate("Form", "显示图像②"))
self.show_video1.setText(_translate("Form", "显示图像①"))
self.label.setText(_translate("Form", "摄像头①"))
self.label_8.setText(_translate("Form", "摄像头③"))
self.show_video3.setText(_translate("Form", "显示图像③"))
self.label_9.setText(_translate("Form", "摄像头④"))
self.show_video4.setText(_translate("Form", "显示图像④"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
- 界面设计完毕后,新建一个py文件multiplexer_main.py,导入UI模块的界面类并继承,开始编写按钮触发
事件函数代码,完整代码如下。
#!/usr/bin/python
# -*- coding:utf-8 -*-
# Author:凌云剑圣
# datetime:20210919
from PyQt5.Qt import *
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QApplication
import sys
from multiplexer_camera import Ui_Form
import cv2 as cv
class ShowImage:
def __init__(self, camera_object, show_label_object):
self.camera_object = camera_object
self.show_label_object = show_label_object
self.frame = [] # 存图片
self.detectFlag = False # 检测flag
self.cap = []
self.timer_camera = QTimer() # 定义定时器
def open_file(self):
"""代开文件"""
# print('打开文件')
self.cap = cv.VideoCapture(self.camera_object, cv.CAP_DSHOW)
self.timer_camera.start(100)
self.timer_camera.timeout.connect(self.open_frame)
def open_frame(self):
if (self.cap.isOpened()):
self.detectFlag = True
ret, self.frame = self.cap.read()
self.read_video(ret, self.frame)
def read_video(self, ret, frame):
if ret:
src = cv.flip(frame, 1) # 摄像头镜像翻转
frame = cv.cvtColor(src, cv.COLOR_BGR2RGB)
height, width, bytesPerComponent = frame.shape
bytesPerLine = bytesPerComponent * width
q_image = QImage(frame.data, width, height, bytesPerLine,
QImage.Format_RGB888).scaled(self.show_label_object.width(),
self.show_label_object.height())
self.show_label_object.setPixmap(QPixmap.fromImage(q_image))
else:
self.cap.release()
self.timer_camera.stop() # 停止计时器
def stop_video(self):
"""停止视频"""
# print('play_video')
if self.cap != []:
self.cap.release()
self.timer_camera.stop() # 停止计时器
self.detectFlag = False
self.show_label_object.setText("该通道已停播~\\(^o^)/~")
self.show_label_object.setStyleSheet("QLabel{background:pink;}"
"QLabel{color:rgb(100,100,100);"
"font-size:15px;font-weight:bold;"
"font-family:宋体;}")
else:
# QMessageBox.warning(self, "Warming", "Push the left upper corner button to Quit.",
# QMessageBox.Yes)
pass
def save_image(self):
# src = cv.flip(self.frame, 1) # 摄像头镜像翻转
cv.imwrite("./camera_%s.png" % str(int(self.camera_object) + 1), self.frame) # 保存图像
class Window(QWidget, Ui_Form):
def __init__(self):
super().__init__()
icon = './15.png'
self.setWindowIcon(QIcon(icon))
self.setupUi(self)
self.save_path = None
self.video_obj = []
def open_camera(self):
for i in range(self.video_spinBox.value()):
self.video_obj.append(ShowImage(i, getattr(self, "show_video%s" % int(i+1))))
return self.video_obj
def on_click(self):
self.pushButton.clicked.connect(self.show_multiplexer_video)
self.pushButton_2.clicked.connect(self.save_multiplexer_image)
self.pushButton_3.clicked.connect(self.quit_obj)
self.pushButton_4.clicked.connect(self.stop_video)
def show_multiplexer_video(self):
"""
显示多路USB摄像头图像
:return:
"""
try:
for i in self.open_camera():
i.open_file()
except Exception as e:
print(e)
def save_multiplexer_image(self):
"""
保存多路摄像头图像
:return:
"""
try:
for i in self.video_obj:
if i.detectFlag:
i.save_image()
except Exception as e:
print(e)
def stop_video(self):
""" stop"""
try:
for i in self.video_obj:
if i.detectFlag:
i.stop_video()
except Exception as e:
print(e)
def quit_obj(self):
# print('88')
quit()
# 在被其他文档调用时,下面的代码不会被执行
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
window.on_click()
sys.exit(app.exec_())
完成以上步骤,运行multiplexer_main.py文件,运行后,结果如UI设计界面所示,可见即可得。
3、测试工具
- 插上开始时准备好的USB摄像头,运行multiplexer_main.py文件,测试各功能。不出意外,完美运行。如图:
项目到处结束,要打包成exe文件的小伙伴自己动手哟。如果懒得动手,请点击以下链接:
项目总结:
这个小工具做出来还是比较实用的,考验pyqt5和OpenCV的应用以及QT Designer布局管理的应用,希望能帮助到小伙伴们,感谢你的预览,祝你生活愉快,天天开心。