说明
功能需求说明:
1、选择模型按键,选择需要加载的模型
2、打开摄像头按键,打开摄像头并开始显示图像
3、算法检测按键,将摄像头图像进行算法检测后返回检测结果
实现说明:
1、选择模型
1.1、本地端,选择需要加载的模型后,返回模型所在地址,供调用;服务器端,发送指令给服务器进行模型配置
2、打开摄像头
2.1、读取图像可能会造成程序阻塞,故需要新建线程
2.2、关闭摄像头后,结束对应的线程
3、算法检测
3.1、flag变量,当摄像头打开,且按下‘开始算法检测’按钮后,摄像头获得的数据经过处理传入算法模型内部.
代码
代码分为两部分,一部分是主窗口,一部分是捕获线程。未集成算法部分代码,模拟了算法被调用过程。
Main_UI.py
import sys
from PyQt5.QtWidgets import QMainWindow, QWidget, QApplication, QGridLayout, QPushButton, QGraphicsView, QGraphicsScene, \
QFileDialog, QLineEdit, QLabel, QHBoxLayout
# 导入自定义库-摄像头捕获线程
from ThreadCapture import ThreadCapture
# 主窗口类
class MyWindow(QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
# 状态
self.openCameraText = '打开摄像头'
self.closeCameraText = '关闭摄像头'
self.startAlgDetectText = '开始算法检测'
self.stopAlgDetectText = '停止算法检测'
# 初始化UI
self.initUI()
self.filePath = None # 模型文件
def initUI(self):
self.resize(800, 600)
self.setWindowTitle('test')
# 创建UI上的控件
self.creatInterface()
# 显示UI
self.show()
def creatInterface(self):
# 创建状态栏
self.mainStatusBar = self.statusBar()
self.mainStatusBarLabel = QLabel(self.mainStatusBar)
self.mainStatusBar.addPermanentWidget(self.mainStatusBarLabel)
self.mainStatusBarLabel.setText('None')
# 创建所需的组件
self.selectModelBtn = QPushButton('选择模型')
self.cameraNumText = QLineEdit('0')
self.cameraBtn = QPushButton(self.openCameraText)
self.algDetectBtn = QPushButton(self.startAlgDetectText)
self.algDetectBtn.setEnabled(False) # 防止误操作
self.cameraNumText.setMaximumWidth(int(100)) # 如果不限制,则显示的过宽
self.imageScene = QGraphicsScene() # 场景用于添加图像
self.imageView = QGraphicsView() # 视图中添加场景
# 配置控件初始状态以及绑定动作
self.setWidget()
# 布局
gridLayout = QGridLayout()
gridLayout.addWidget(self.selectModelBtn, 0, 0)
gridLayout.addWidget(self.cameraNumText, 1, 0)
gridLayout.addWidget(self.cameraBtn, 2, 0)
gridLayout.addWidget(self.algDetectBtn, 3, 0)
gridLayout.addWidget(self.imageView, 0, 1, 8, 8)
widget = QWidget(self)
widget.setLayout(gridLayout)
self.setCentralWidget(widget)
# 配置控件初始状态以及绑定动作
def setWidget(self):
self.selectModelBtn.clicked.connect(self.actionSelectModelBtn)
self.cameraBtn.clicked.connect(self.actionCameraBtn)
self.algDetectBtn.clicked.connect(self.actionDetectBtn)
self.imageView.setScene(self.imageScene)
def actionSelectModelBtn(self):
# 选择文件
print('actionSelectModel')
# folderPath = QFileDialog.getExistingDirectory(self, '选取文件夹') # 文件夹路径
# print(folderPath)
# 选择文件,返回文件的路径
self.filePath, _ = QFileDialog.getOpenFileName(self, caption="选取文件", filter="Image Files (*.jpg);;Text Files (*.txt)")
print(self.filePath)
# 状态栏显示模型路径
self.mainStatusBarLabel.setText(self.filePath)
if self.cameraBtn.text() == self.closeCameraText:
# 如果摄像头已经打开,则允许‘开始算法检测’
self.algDetectBtn.setEnabled(True)
def actionCameraBtn(self):
"""
如果当前状态为“打开摄像头”,则创建线程进行图像捕获,更新显示为“关闭摄像头”。
如果当前状态为“关闭摄像头”,则结束打开的线程,更新显示为“打开摄像头”。
:return:
"""
print('actionOpenCamera')
if self.cameraBtn.text() == self.openCameraText:
# 创建线程
self.threadCapture = ThreadCapture(int(self.cameraNumText.text()))
self.threadCapture.signal_image.connect(self.showImage)
self.threadCapture.start()
else:
# 结束线程
self.threadCapture.terminate()
self.threadCapture.quit()
if self.cameraBtn.text() == self.openCameraText:
self.cameraBtn.setText(self.closeCameraText)
# 当选择了模型以及摄像头处于打开状态时才允许进行算法检测
if self.filePath is not None:
self.algDetectBtn.setEnabled(True)
else:
self.cameraBtn.setText(self.openCameraText)
self.algDetectBtn.setEnabled(False) # 算法检测失能,且更新显示
self.algDetectBtn.setText(self.startAlgDetectText)
self.selectModelBtn.setEnabled(True) # 允许选择模型
def actionDetectBtn(self):
if self.algDetectBtn.text() == self.startAlgDetectText:
self.threadCapture.algDetectFlag = True
else:
self.threadCapture.algDetectFlag = False
if self.algDetectBtn.text() == self.startAlgDetectText:
self.algDetectBtn.setText(self.stopAlgDetectText)
self.selectModelBtn.setEnabled(False) # 算法检测期间不允许更换模型
else:
self.algDetectBtn.setText(self.startAlgDetectText)
self.selectModelBtn.setEnabled(True) # 算法检测期间不允许更换模型
def showImage(self, image):
self.imageScene.addPixmap(image)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
sys.exit(app.exec_())
ThreadCapture.py
import cv2
from PyQt5.QtCore import QThread, pyqtSignal, QMutex
from PyQt5.QtGui import QImage, QPixmap
import random
class ThreadCapture(QThread):
# 定义信号,用于传输图像
signal_image = pyqtSignal(QPixmap)
def __init__(self, cameraNum):
super(ThreadCapture, self).__init__()
self.cameraNum = cameraNum
self.qmutex = QMutex() # 进行锁
self.algDetectFlag = False # 算检测标志位
def run(self):
self.cap = cv2.VideoCapture(self.cameraNum, cv2.CAP_DSHOW) # cv2.CAP_DSHOW 可以消除警告
while True:
print('thread id:', QThread.currentThreadId())
# 读取图像是,锁住线程
self.qmutex.lock()
ret, self.image = self.cap.read()
self.qmutex.unlock()
if ret:
# 处理图像
self.dealImage()
# 处理图像数据,符合算法要求后传入模型,等待返回结果
if self.algDetectFlag:
print('start alg detect')
cv2.rectangle(self.image, (100, 100), (300, 300),
(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),)
# 转换为qt的图像格式
pixmap = self.imageCv2Qt(self.image)
self.signal_image.emit(pixmap)
def dealImage(self):
self.image = cv2.resize(self.image, (400, 400))
height, width, depth = self.image.shape
# cv2.putText(self.image, 'height-{}:width-{}'.format(height, width), (10, 100), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255 ,0))
# 转换为qt的图像格式
def imageCv2Qt(self, image):
rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
height, width, depth = rgb.shape
bytesPerLine = width * depth
qrgb = QImage(rgb.data, width, height, bytesPerLine, QImage.Format_RGB888)
pixmap = QPixmap.fromImage(qrgb)
return pixmap