睿智的目标检测——pyqt5搭建目标检测界面(代码片段)

_白鹭先生_ _白鹭先生_     2023-03-12     730

关键词:

睿智的目标检测——PyQt5搭建目标检测界面

学习前言

基于B导开源的YoloV4-Pytorch源码开发了戴口罩人脸检测系统(21年完成的本科毕设,较为老旧,可自行替换为最新的目标检测算法)。

源码下载

https://github.com/Egrt/YOLO_PyQt5
喜欢的可以点个star噢。

支持功能

  1. 支持读取本地图片
  2. 支持读取本地视频
  3. 支持打开摄像头实时检测
  4. 支持多线程,防止卡顿
  5. 支持检测到人脸未佩戴口罩时记录,并语音警告

界面展示

PyQt5

PyQt5是Python语言中一款流行的GUI(图形用户界面)开发框架,基于Qt GUI应用程序开发框架,提供了一个强大的工具集,用于创建各种桌面应用程序。PyQt5可以用于开发桌面应用程序、Web应用程序和移动应用程序,具有良好的跨平台性和丰富的功能。

信号与槽

信号和槽是PyQt5中一个重要的概念,是用于组织和管理GUI元素之间交互的机制。信号是GUI元素发出的事件或动作,槽是处理信号的函数。当信号发生时,与之相关联的槽将被自动调用。

下面是一个简单的示例代码,演示如何在PyQt5中使用信号和槽。这个示例创建了一个窗口,其中包含一个按钮和一个标签。当用户单击按钮时,标签的文本将会改变:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel

class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Signal and Slot')

        self.button = QPushButton('Click', self)
        self.button.move(100, 100)
        self.button.clicked.connect(self.changeText)

        self.label = QLabel('Hello World', self)
        self.label.move(110, 60)

    def changeText(self):
        self.label.setText('Button Clicked')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    sys.exit(app.exec_())

在这个示例代码中,我们创建了一个名为MyWindow的窗口类,该类继承自QWidget。在MyWindow的构造函数中,我们创建了一个按钮和一个标签,并使用clicked信号将按钮的单击事件连接到changeText槽函数。当按钮被单击时,changeText槽函数将会被调用,该函数会改变标签的文本。

运行代码后,可以看到窗口上有一个按钮和一个标签,单击按钮后标签的文本会改变为“Button Clicked”。这个示例演示了如何使用PyQt5中的信号和槽来实现交互式GUI应用程序。

功能实现

界面设计

根据任务需求,可以将界面分为四部分:

  1. 最上方放置按钮来实现选择读取图片、视频、开启摄像头实时检测。
  2. 左侧放置目录控件,浏览本地文件。
  3. 中间显示YOLO处理后的图片。
  4. 在处理视频或实时读取摄像头检测时,如果多帧连续识别到不戴口罩人脸将其记录并发出语音警告。

因此编写代码如下:

class MyApp(QMainWindow):
    def __init__(self):
        super(MyApp, self).__init__()

        self.cap                 = cv2.VideoCapture()
        self.CAM_NUM             = 0
        self.thread_status       = False  # 判断识别线程是否开启
        self.tool_bar            = self.addToolBar('工具栏')
        self.action_right_rotate = QAction(
            QIcon("icons/右旋转.png"), "向右旋转90", self)
        self.action_left_rotate = QAction(
            QIcon("icons/左旋转.png"), "向左旋转90°", self)
        self.action_opencam = QAction(QIcon("icons/摄像头.png"), "开启摄像头", self)
        self.action_video   = QAction(QIcon("icons/video.png"), "加载视频", self)
        self.action_image   = QAction(QIcon("icons/图片.png"), "加载图片", self)
        self.action_right_rotate.triggered.connect(self.right_rotate)
        self.action_left_rotate.triggered.connect(self.left_rotate)
        self.action_opencam.triggered.connect(self.opencam)
        self.action_video.triggered.connect(self.openvideo)
        self.action_image.triggered.connect(self.openimage)
        self.tool_bar.addActions((self.action_left_rotate, self.action_right_rotate,
                                  self.action_opencam, self.action_video, self.action_image))
        self.stackedWidget      = StackedWidget(self)
        self.fileSystemTreeView = FileSystemTreeView(self)
        self.graphicsView       = GraphicsView(self)
        self.dock_file          = QDockWidget(self)
        self.dock_file.setWidget(self.fileSystemTreeView)
        self.dock_file.setTitleBarWidget(QLabel('目录'))
        self.dock_file.setFeatures(QDockWidget.NoDockWidgetFeatures)

        self.dock_attr = QDockWidget(self)
        self.dock_attr.setWidget(self.stackedWidget)
        self.dock_attr.setTitleBarWidget(QLabel('上报数据'))
        self.dock_attr.setFeatures(QDockWidget.NoDockWidgetFeatures)

        self.setCentralWidget(self.graphicsView)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_file)
        self.addDockWidget(Qt.RightDockWidgetArea, self.dock_attr)

        self.setWindowTitle('口罩佩戴检测')
        self.setWindowIcon(QIcon('icons/mask.png'))
        self.src_img = None
        self.cur_img = None

槽函数

在初始化中配置窗口的界面并使用connect连接信号与槽函数,当信号发生时,与之相关联的槽将被自动调用。控制打开图片、视频与本地摄像头的槽函数分别为:

def openvideo(self):
   print(self.thread_status)
   if self.thread_status == False:

       fileName, filetype = QFileDialog.getOpenFileName(
           self, "选择视频", "D:/", "*.mp4;;*.flv;;All Files(*)")

       flag = self.cap.open(fileName)
       if flag == False:
           msg = QtWidgets.QMessageBox.warning(self, u"警告", u"请选择视频文件",
                                               buttons=QtWidgets.QMessageBox.Ok,
                                               defaultButton=QtWidgets.QMessageBox.Ok)
       else:
           self.detectThread = DetectThread(fileName)
           self.detectThread.Send_signal.connect(self.Display)
           self.detectThread.start()
           self.action_video.setText('关闭视频')
           self.thread_status = True
   elif self.thread_status == True:
       self.detectThread.terminate()
       if self.cap.isOpened():
           self.cap.release()
       self.action_video.setText('打开视频')
       self.thread_status = False

def openimage(self):
   if self.thread_status == False:
       fileName, filetype = QFileDialog.getOpenFileName(
           self, "选择图片", "D:/", "*.jpg;;*.png;;All Files(*)")
       if fileName != '':
           src_img = Image.open(fileName)
           r_image, predicted_class = yolo.detect_image(src_img)
           r_image = np.array(r_image)
           showImage = QtGui.QImage(
               r_image.data, r_image.shape[1], r_image.shape[0], QtGui.QImage.Format_RGB888)
           self.graphicsView.set_image(QtGui.QPixmap.fromImage(showImage))

def opencam(self):
   if self.thread_status == False:
       flag = self.cap.open(self.CAM_NUM)
       if flag == False:
           msg = QtWidgets.QMessageBox.warning(self, u"警告", u"请检测相机与电脑是否连接正确",
                                               buttons=QtWidgets.QMessageBox.Ok,
                                               defaultButton=QtWidgets.QMessageBox.Ok)
       else:
           self.detectThread = DetectThread(self.CAM_NUM)
           self.detectThread.Send_signal.connect(self.Display)
           self.detectThread.start()
           self.action_video.setText('关闭视频')
           self.thread_status = True
   else:
       self.detectThread.terminate()
       if self.cap.isOpened():
           self.cap.release()
       self.action_video.setText('打开视频')
       self.thread_status = False

多线程

在读取视频文件或摄像头时,为避免界面卡顿,使用了多线程进行处理,并在结束处理视频文件时需要关闭线程防止系统卡死,且在关闭摄像头时还需要使用self.cap.release()对摄像头进行释放。

在多线程处理连续帧时,采用了Qt自带的多线程库QThread:

class DetectThread(QThread):
    Send_signal = pyqtSignal(np.ndarray, int)

    def __init__(self, fileName):
        super(DetectThread, self).__init__()
        self.capture = cv2.VideoCapture(fileName)
        self.count = 0
        self.warn = False  # 是否发送警告信号

    def run(self):
        ret, self.frame = self.capture.read()
        while ret:
            ret, self.frame = self.capture.read()
            self.detectCall()

    def detectCall(self):
        fps = 0.0
        t1 = time.time()
        # 读取某一帧
        frame = self.frame
        # 格式转变,BGRtoRGB
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        # 转变成Image
        frame = Image.fromarray(np.uint8(frame))
        # 进行检测
        frame_new, predicted_class = yolo.detect_image(frame)
        frame = np.array(frame_new)
        if predicted_class == "face":
            self.count = self.count+1
        else:
            self.count = 0
        # RGBtoBGR满足opencv显示格式
        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
        fps = (fps + (1./(time.time()-t1))) / 2
        print("fps= %.2f" % (fps))
        frame = cv2.putText(frame, "fps= %.2f" % (
            fps), (0, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        if self.count > 30:
            self.count = 0
            self.warn = True
        else:
            self.warn = False
        # 发送pyqt信号
        self.Send_signal.emit(frame, self.warn)

信息记录

如果连续30帧识别到未佩戴口罩的人脸时,将发送信号在右侧列表中显示,并记录当前帧画面:

def add_item(self, image):
    # 总Widget
    wight = QWidget()
    # 总体横向布局
    layout_main = QHBoxLayout()
    map_l = QLabel()  # 图片显示
    map_l.setFixedSize(60, 40)
    map_l.setPixmap(image.scaled(60, 40))
    # 右边的纵向布局
    layout_right = QVBoxLayout()
    # 右下的的横向布局
    layout_right_down = QHBoxLayout()  # 右下的横向布局
    layout_right_down.addWidget(
        QLabel(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))

    # 按照从左到右, 从上到下布局添加
    layout_main.addWidget(map_l)  # 最左边的图片
    layout_right.addWidget(QLabel('警告!检测到未佩戴口罩'))  # 右边的纵向布局
    layout_right.addLayout(layout_right_down)  # 右下角横向布局
    layout_main.addLayout(layout_right)  # 右边的布局
    wight.setLayout(layout_main)  # 布局给wight
    item = QListWidgetItem()  # 创建QListWidgetItem对象
    item.setSizeHint(QSize(300, 80))  # 设置QListWidgetItem大小
    self.stackedWidget.addItem(item)  # 添加item
    self.stackedWidget.setItemWidget(item, wight)  # 为item设置widget

关闭系统

在关闭系统时,需要确保关闭了多线程,且关闭了已经打开的摄像头,否则在退出时也将造成卡顿:

def Display(self, frame, warn):
        im = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        showImage = QtGui.QImage(
            im.data, im.shape[1], im.shape[0], QtGui.QImage.Format_RGB888)
        self.graphicsView.set_image(QtGui.QPixmap.fromImage(showImage))

def closeEvent(self, event):
    ok = QtWidgets.QPushButton()
    cacel = QtWidgets.QPushButton()
    msg = QtWidgets.QMessageBox(
        QtWidgets.QMessageBox.Warning, u"关闭", u"确定退出?")
    msg.addButton(ok, QtWidgets.QMessageBox.ActionRole)
    msg.addButton(cacel, QtWidgets.QMessageBox.RejectRole)
    ok.setText(u'确定')
    cacel.setText(u'取消')
    if msg.exec_() == QtWidgets.QMessageBox.RejectRole:
        event.ignore()
    else:
        if self.thread_status == True:
            self.detectThread.terminate()
        if self.cap.isOpened():
            self.cap.release()
        event.accept()

最终完整的代码如下:

import ctypes
import sys
import time

import cv2
import numpy as np
import qdarkstyle
from PIL import Image
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.Qt import QThread
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from custom.graphicsView import GraphicsView
from custom.listWidgets import *
from custom.stackedWidget import *
from custom.treeView import FileSystemTreeView
from yolo import YOLO

ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")

# 多线程实时检测
class DetectThread(QThread):
    Send_signal = pyqtSignal(np.ndarray, int)

    def __init__(self, fileName):
        super(DetectThread, self).__init__()
        self.capture = cv2.VideoCapture(fileName)
        self.count = 0
        self.warn = False  # 是否发送警告信号

    def run(self):
        ret, self.frame = self.capture.read()
        while ret:
            ret, self.frame = self.capture.read()
            self.detectCall()

    def detectCall(self):
        fps = 0.0
        t1 = time.time()
        # 读取某一帧
        frame = self.frame
        # 格式转变,BGRtoRGB
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        # 转变成Image
        frame = Image.fromarray(np.uint8(frame))
        # 进行检测
        frame_new, predicted_class = yolo.detect_image(frame)
        frame = np.array(frame_new)
        if predicted_class == "face":
            self.count = self.count+1
        else:
            self.count = 0
        # RGBtoBGR满足opencv显示格式
        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
        fps = (fps + (1./(time.time()-t1))) / 2
        print("fps= %.2f" % (fps))
        frame = cv2.putText(frame, "fps= %.2f" % (
            fps), (0, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        if self.count > 30:
            self.count = 0
            self.warn = True
        else:
            self.warn = False
        # 发送pyqt信号
        self.Send_signal.emit(frame, self.warn)

class MyApp(QMainWindow):
    def __init__(self):
        super(MyApp, self).__init__()

        self.cap                 = cv2.VideoCapture()
        self.CAM_NUM             = 0
        self.thread_status       = False  # 判断识别线程是否开启
        self.tool_bar            = self.addToolBar('工具栏')
        self.action_right_rotate = QAction(
            QIcon("icons/右旋转.png"), "向右旋转90",睿智的目标检测52——keras搭建yolox目标检测平台(代码片段)

睿智的目标检测52——Keras搭建YoloX目标检测平台学习前言源码下载YoloX改进的部分(不完全)YoloX实现思路一、整体结构解析二、网络结构解析1、主干网络CSPDarknet介绍2、构建FPN特征金字塔进行加强特征提取3、利用YoloHead... 查看详情

睿智的目标检测60——pytorch搭建yolov7目标检测平台(代码片段)

睿智的目标检测60——Pytorch搭建YoloV7目标检测平台学习前言源码下载YoloV7改进的部分(不完全)YoloV7实现思路一、整体结构解析二、网络结构解析1、主干网络Backbone介绍2、构建FPN特征金字塔进行加强特征提取3、利用YoloHe... 查看详情

睿智的目标检测51——tensorflow2搭建yolo3目标检测平台(代码片段)

睿智的目标检测51——Tensorflow2搭建yolo3目标检测平台学习前言源码下载YoloV3实现思路一、整体结构解析二、网络结构解析1、主干网络Darknet53介绍2、构建FPN特征金字塔进行加强特征提取3、利用YoloHead获得预测结果三、预测结果的... 查看详情

睿智的目标检测65——pytorch搭建detr目标检测平台(代码片段)

睿智的目标检测65——Pytorch搭建DETR目标检测平台学习前言源码下载DETR实现思路一、整体结构解析二、网络结构解析1、主干网络Backbone介绍a、什么是残差网络b、什么是ResNet50模型c、位置编码2、编码网络Encoder网络介绍a、Transformer... 查看详情

睿智的目标检测——pytorch搭建yolov7-obb旋转目标检测平台(代码片段)

睿智的目标检测——Pytorch搭建[YoloV7-OBB]旋转目标检测平台学习前言源码下载YoloV7-OBB改进的部分(不完全)YoloV7-OBB实现思路一、整体结构解析二、网络结构解析1、主干网络Backbone介绍2、构建FPN特征金字塔进行加强特征提... 查看详情

睿智的目标检测56——pytorch搭建yolov5目标检测平台(代码片段)

睿智的目标检测56——Pytorch搭建YoloV5目标检测平台学习前言源码下载YoloV5改进的部分(不完全)YoloV5实现思路一、整体结构解析二、网络结构解析1、主干网络Backbone介绍2、构建FPN特征金字塔进行加强特征提取3、利用YoloHe... 查看详情

睿智的目标检测55——keras搭建yolov5目标检测平台(代码片段)

睿智的目标检测55——Keras搭建YoloV5目标检测平台学习前言源码下载YoloV5改进的部分(不完全)YoloV5实现思路一、整体结构解析二、网络结构解析1、主干网络Backbone介绍2、构建FPN特征金字塔进行加强特征提取3、利用YoloHead... 查看详情

使用pyqt5搭建yolov5目标检测平台(代码片段)

使用PyQt5搭建yoloV5目标检测平台一、资源包准备:​1、python3.7​3、Anaconda​4、cuda-10.2.89​5、VisualStudio2019​6、PyQt5-YOLOv5-master源码二、环境搭建1、PyQt5安装与部署:1、安装PyQt5:(1)、打开AnacondaPrompt终端࿰... 查看详情

pyqt搭建yolov5目标检测界面(代码片段)

Pyqt搭建YOLOV5目标检测界面(超详细+源代码)实现效果如下所示,可以检测图片、视频以及摄像头实时检测。实现效果如下所示,可以检测图片、视频以及摄像头实时检测。具体细节实现可以参考上一篇博客... 查看详情

实时车辆行人多目标检测与跟踪系统-上篇(ui界面清新版,python代码)

...如何利用深度学习中的YOLO及SORT算法实现车辆、行人等多目标的实时检测和跟踪,并利用PyQt5设计了清新简约的系统UI界面,在界面中既可选择自己的视频、图片文件进行检测跟踪,也可以通过电脑自带的摄像头进行实时处理,可... 查看详情

保研笔记八——yolov5项目复习(代码片段)

学习转载自:睿智的目标检测56——Pytorch搭建YoloV5目标检测平台_Bubbliiiing的博客-CSDN博客_睿智yolo Pytorch搭建自己的YoloV5目标检测平台(Bubbliiiing源码详解训练预测)-主干网络介绍_哔哩哔哩_bilibili还有一些视频的学习... 查看详情

深度学习目标检测ui界面-交通标志检测识别(代码片段)

深度学习目标检测ui界面-交通标志检测识别为了将算法封装起来,博主尝试了实验pyqt5的上位机界面进行封装,其中遇到了一些坑举给大家避开。这里加载的训练模型参考之前写的博客:自动驾驶目标检测项目实战(一... 查看详情

使用azure认知服务快速搭建一个目标检测平台(代码片段)

...这里记录一下如何基于Azure计算机视觉服务快速搭建一个目标检测平台。1.认知服务  认知服务使每个开发人 查看详情

基于yolov4的目标检测系统(附matlab代码+gui实现)(代码片段)

本文介绍了一种MATLAB实现的目标检测系统代码,采用YOLOv4检测网络作为核心模型,用于训练和检测各种任务下的目标,并在GUI界面中对各种目标检测结果可视化。文章详细介绍了YOLOv4的实现过程,包括算法原理、MATLAB实现代码、... 查看详情

睿智的目标检测61——tensorflow2focalloss详解与在yolov4当中的实现(代码片段)

睿智的目标检测61——Tensorflow2Focalloss详解与在YoloV4当中的实现学习前言什么是FocalLoss一、控制正负样本的权重二、控制容易分类和难分类样本的权重三、两种权重控制方法合并实现方式学习前言TF2的也补上咯。其实和Keras的一摸... 查看详情

openmmlab目标检测(代码片段)

OpenMMLab目标检测1.目标检测简介1.1滑窗2.基础知识2.1边界框(BoundingBox)2.2交并比IntersectionOverUnion2.3置信度ConfidenceScore2.4非极大值抑制Non-MaximumSuppression2.5边界框回归BoundingBoxRegression2.6边界框编码BboxCoding3.两阶段目标检测算... 查看详情

安全-telnet检测目标端口是否开启(代码片段)

...行窗口输入cmd进入dos界面再使用telnet[IP地址][端口]来检测目标系统是否开启了对应的端口,如果端口开启了就会跳到telnet界面如果该主机没有开启对应的端口会直接报错 查看详情

夏侯南溪搭建目标检测模型——数据读取篇(代码片段)

1介绍在PyTorch中定义自己的数据集类,需要继承父类Dataset,自定义的Dataset类需要实现以下三个函数:init():用来实现初始化的操作;len():用来返回数据集的样本数目;getitem():tosupporttheindexingsuchth... 查看详情