所有YOLOv10源码免费获取(私信留下联系方式,项目名+邮箱)
唯一要求 一键四连:点赞+收藏+评论+免费订阅
免费项目包含:
- 确保项目可以运行(图片识别、视频识别、摄像头实时识别和结果保存)。
- 训练好的pt模型文件
- 完整的ui界面
- 完整代码
- 环境配置教程
- 训练结果分析图
软件主要功能
1. 支持图片、视频及摄像头
进行检测,同时支持图片的批量检测
;
2. 界面可实时显示目标位置
、目标总数
、置信度
、用时
等信息;
3. 支持图片
或者视频
的检测结果保存
;
目录
摘要
火焰与烟雾的快速检测对于早期火灾预警具有重要意义。基于YOLOv10模型的火焰烟雾实时检测系统集成了深度学习、目标检测和实时数据处理的优势,为火灾监测提供了一种高效的解决方案。本文设计并实现了一个火焰与烟雾的实时检测系统,该系统包括了火焰与烟雾数据集、YOLOv10模型、用户界面(UI)和完整的可运行环境。
本文基于YOLOv10深度学习框架,通过6744张图片,训练了一个进行火焰烟雾的目标检测模型,准确率高达93.2%。并基于此模型开发了一款带UI界面的火焰烟雾检测系统,可用于实时检测场景中的火焰及烟雾,更方便进行功能的展示。该系统是基于python与PyQT5开发的,支持图片、视频以及摄像头进行实时目标检测,并保存检测结果。
系统的主要流程包括以下几个模块:
1) 数据集准备:收集并标注了大量火焰与烟雾的样本数据,涵盖多种场景和环境。
2) 模型训练与优化:基于YOLOv10进行火焰烟雾检测模型的训练,通过数据增强与超参数调优提升模型的检测精度与响应速度。
3) 实时检测与UI展示:利用摄像头实时捕捉图像输入系统,经过YOLOv10模型处理后快速识别火焰与烟雾区域,同时在用户界面上同步显示检测结果和警报信息。
4) 系统集成与部署:该系统实现了从数据采集、模型加载到检测结果输出的全自动流程,支持不同设备平台上的应用部署,确保检测系统能够24小时稳定运行。
前言
在当今社会,火灾安全已经成为全球关注的重大问题,每年因火灾造成的生命财产损失不可估量。随着科技的发展,火焰检测技术在防灾减灾体系中扮演着越来越重要的角色。传统的火焰检测方法,如烟雾探测器和温度传感器,虽然在一定程度上能够实现早期火灾的检测,但在处理大规模或开放空间的火灾检测时,存在诸多局限性,如反应时间慢、易受环境因素干扰、检测范围有限等。这些限制促使研究者探索更高效、更智能的火焰检测解决方案。
YOLOv10的优点
过去几年中,由于YOLO在计算成本和检测性能之间的有效平衡,它已经成为实时目标检测领域的主要范式。研究人员探索了YOLO的架构设计、优化目标、数据增强策略等方面,取得了显著进展。然而,YOLO依赖于非极大值抑制(NMS)进行后处理,这阻碍了YOLO的端到端部署,并对推理延迟产生了不利影响。此外,YOLO的各种组件设计缺乏全面深入的检查,导致明显的计算冗余,限制了模型的能力。这导致了效率不佳,同时也有很大的性能提升潜力。在这项工作中,我们旨在从后处理和模型架构两方面进一步提升YOLO的性能-效率边界。为此,我们首先提出了一致的双重分配策略,用于YOLO的NMS-free训练,这同时带来了竞争力的性能和低推理延迟。此外,我们引入了整体效率-精度驱动的模型设计策略。我们从效率和精度的角度全面优化了YOLO的各个组件,大大减少了计算开销并增强了能力。我们的努力成果是一个新的YOLO系列,用于实时端到端目标检测,称为YOLOv10。大量实验表明,YOLOv10在各种模型规模上都达到了最先进的性能和效率。例如,在COCO数据集上,YOLOv10-S在相似AP的情况下比RT-DETR-R18快1.8倍,同时参数和FLOPs减少了2.8倍。与YOLOv9-C相比,YOLOv10-B在相同性能下的延迟减少了46%,参数减少了25%。
我们的YOLOv10在各种模型规模上实现了最先进的性能和端到端延迟。我们首先将YOLOv10与我们的基线模型YOLOv8进行比较。在N / S / M / L / X五种变体上,YOLOv10分别实现了1.2% / 1.4% / 0.5% / 0.3% / 0.5%的AP提升,同时参数减少了28% / 36% / 41% / 44% / 57%,计算量减少了23% / 24% / 25% / 27% / 38%,延迟降低了70% / 65% / 50% / 41% / 37%。
与其他YOLO模型相比,YOLOv10在准确性和计算成本之间也表现出更优的权衡。具体来说,对于轻量级和小型模型,YOLOv10-N / S比YOLOv6-3.0-N / S分别高出1.5 AP和2.0 AP。
表1中列出了与最先进方法的比较。延迟是使用官方预训练模型测量的。Latencyf表示模型在没有后处理时前向过程的延迟。†表示YOLOv10使用原始一对多训练并采用NMS的结果。为了公平比较,所有结果均未使用诸如知识蒸馏或PGI等额外的高级训练技术。
相比于AP,YOLOv10在参数量和计算量上分别减少了51% / 61%。对于中等规模的模型,YOLOv10-B / M相较于YOLOv9-C / YOLO-MS,在相同或更好的性能下分别减少了46% / 62%的延迟。对于大型模型,相较于Gold-YOLO-L,我们的YOLOv10-L减少了68%的参数量和32%的延迟,同时显著提升了1.4%的AP。此外,与RT-DETR相比,YOLOv10在性能和延迟上均有显著提升。值得注意的是,YOLOv10-S / X在类似性能下推理速度分别比RT-DETR-R18 / R101快1.8倍和1.3倍。这些结果充分证明了YOLOv10作为实时端到端检测器的优越性。
1. 数据集介绍-6744张图像
在构建用于火焰烟雾检测的深度学习模型时,一个全面和精确标注的数据集是至关重要的。我们的数据集共包含6744张图像,其中包括4832张训练图像,1000张验证图像,以及912张测试图像。这样的划分旨在确保模型能在充足的数据上进行训练,同时留出足够的样本来验证和测试模型的性能。
在数据预处理阶段,我们采取了几项关键步骤以确保数据集的质量。首先,所有图像都经过了自动方向校正,并剥离了EXIF方向信息,这是为了消除因摄影设备的不同拍摄角度而带来的方向差异。接着,所有图像都被统一调整至640x640像素,通过拉伸的方式来适配这一分辨率。虽然这可能导致一些图像的比例失真,但这样做能确保所有图像都适合模型的输入需求,并且可以在不牺牲处理速度的情况下保持图像特征的辨识度。
在我们的数据集中,火焰和烟雾的实例数量基本持平,这有助于防止模型在训练过程中偏向于更频繁标注的类别。此外,数据集中的图像被标记为包含火焰和烟雾两个类别,每个类别的边界框均精确地标注在图像中。这些标注对于训练模型来说非常关键,因为它们为模型提供了识别和定位目标的必要信息。
通过分析数据集的标注分布图,我们发现大部分标注框集中在图像的中心区域。这表明数据采集过程中存在一个偏向性:火焰和烟雾大多出现在画面中央。虽然这种分布有助于模型更好地学习识别中心区域的目标,但也可能导致模型在检测图像边缘的火焰和烟雾时表现欠佳。为此,我们采用了多种数据增强方法,包括随机旋转、缩放、裁剪以及颜色变化等,以模拟不同的视角和环境条件,从而提升模型在各种情况下对烟雾的检测能力。
此外,标注框的大小分布表明火焰和烟雾在图像中的尺寸具有较大差异。为了使模型能够识别各种大小的火焰和烟雾,我们在数据集的宽度和高度分布中充分考虑了这一点。
总体而言,本数据集经过精心准备和处理,旨在为研究人员和从业者提供坚实的基础,以支持深度学习模型的训练和评估。借助本数据集的使用,我们可以深入研究 YOLOv10 等先进目标检测算法在烟雾检测任务中的应用潜力,并期望在实际应用中实现更高的检测准确性和效率。
数据集配置文件data.yaml
train: D:\yolov10火焰烟雾检测系统\datasets\images\train
val: D:\yolov10火焰烟雾检测系统\datasets\images\val
test: # test images (optional)
names: ['fire','smoke']
2、模型训练、评估和推理
2.1 模型训练(train.py)
from ultralytics import YOLOv10
model_path = 'yolov10s.pt'
data_path = 'datasets/data.yaml'
if __name__ == '__main__':
model = YOLOv10(model_path)
results = model.train(data=data_path,
epochs=500,
batch=64,
device='0',
workers=0,
project='runs/detect',
name='exp',
)
1. 模型选择
代码注释列出了YOLOv10模型的不同版本,分别适用于不同需求的任务:
- yolov10n.yaml (nano):最轻量化的模型,适合嵌入式设备,速度较快,但精度可能稍低。
- yolov10s.yaml (small):小型模型,适合需要一定精度的实时任务。
- yolov10m.yaml (medium):中等大小的模型,平衡了速度和精度。
- yolov10b.yaml (base):基本版模型,适合大多数应用。
- yolov10l.yaml (large):大型模型,适合高精度需求的任务。
在代码中,model_path
指定了使用的模型权重文件yolov10s.pt
,即小型模型(small),适合实时任务。
2. 训练过程
主程序块中,YOLOv10模型被实例化,并调用了.train()
方法以启动训练,关键参数包括:
- data: 指定数据集配置文件路径。
- epochs: 训练轮数,这里设定为500轮。
- batch: 每批次数据量,设定为64。
- device: 指定训练设备为GPU('0'表示使用第一个GPU)。
- workers: 数据加载时的子进程数,这里设定为0,适合简单测试或资源有限的设备。
- project: 训练结果存储的主目录。
- name: 实验名称,每次训练的结果会保存在以该名称为子目录的文件夹中。
2.2 训练结果
PR曲线体现精确率和召回率的关系,本文训练结果的PR曲线如下。mAP表示Precision和Recall作为两轴作图后围成的面积,m表示平均,@后面的数表示判定iou为正负样本的阈值。[email protected]:表示阈值大于0.5的平均mAP,火焰和烟雾的[email protected]已经达到0.95和0.915,平均值为0.932 。
在性能指标方面,图表中的metrics/precision、metrics/recall、metrics/mAP50和metrics/mAP50-95展示了模型性能的逐步提升。随着训练迭代的增加,准确率(Precision)和召回率(Recall)不断提高,这表明模型在识别正样本时变得更加精确,且能捕捉到更多的正样本。mAP(mean Average Precision)是目标检测领域中重要的评估指标之一,其中metrics/mAP50和metrics/mAP50-95的提升说明模型在不同IoU阈值下的检测性能均在提高。具体而言,mAP50表示IoU为0.5时的平均精度,而mAP50-95则涵盖了IoU从0.5到0.95不同阈值下的平均精度,这更加全面地反映了模型在各种重叠程度下的表现。这些指标的稳步上升表明模型在整个训练过程中不断优化,性能逐渐增强。
在机器学习中,F1分数也是一个非常重要的性能指标,结合了模型的准确率和召回率,提供了对分类性能的全面视角。尤其在正负样本分布不均的情况下,F1分数有助于评估模型在区分困难类别时的表现,从而更好地理解其实际应用效果。
3、 系统界面效果
3.1图片检测
3.2视频检测
3.3摄像头实时检测
3.4结果保存
4、项目源码
data.yaml
train: ..\yolov10火焰烟雾检测系统(ui界面+数据集)\yolov10火焰烟雾检测系统\datasets\images\train
val: ..\yolov10火焰烟雾检测系统(ui界面+数据集)\yolov10火焰烟雾检测系统\datasets\images\val
test: # test images (optional)
names: ['fire','smoke']
train.py
#coding:utf-8
#根据实际情况更换模型
# yolov10n.yaml (nano):轻量化模型,适合嵌入式设备,速度快但精度略低。
# yolov10s.yaml (small):小模型,适合实时任务。
# yolov10m.yaml (medium):中等大小模型,兼顾速度和精度。
# yolov10b.yaml (base):基本版模型,适合大部分应用场景。
# yolov10l.yaml (large):大型模型,适合对精度要求高的任务。
from ultralytics import YOLOv10
model_path = 'yolov10s.pt'
data_path = 'datasets/data.yaml'
if __name__ == '__main__':
model = YOLOv10(model_path)
results = model.train(data=data_path,
epochs=500,
batch=64,
device='0',
workers=0,
project='runs/detect',
name='exp',
)
main.py
# -*- coding: utf-8 -*-
import time
from PyQt5.QtWidgets import QApplication , QMainWindow, QFileDialog,QMessageBox,QWidget,QHeaderView,QTableWidgetItem, QAbstractItemView
import sys
import os
from PIL import ImageFont
from ultralytics import YOLOv10
sys.path.append('UIProgram')
from UIProgram.UiMain import Ui_MainWindow
import sys
from PyQt5.QtCore import QTimer, Qt, QThread, pyqtSignal,QCoreApplication
import detect_tools as tools
import cv2
import Config
from UIProgram.QssLoader import QSSLoader
from UIProgram.precess_bar import ProgressBar
import numpy as np
# import torch
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(QMainWindow, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.initMain()
self.signalconnect()
# 加载css渲染效果
style_file = 'UIProgram/style.css'
qssStyleSheet = QSSLoader.read_qss_file(style_file)
self.setStyleSheet(qssStyleSheet)
def signalconnect(self):
self.ui.PicBtn.clicked.connect(self.open_img)
self.ui.comboBox.activated.connect(self.combox_change)
self.ui.VideoBtn.clicked.connect(self.vedio_show)
self.ui.CapBtn.clicked.connect(self.camera_show)
self.ui.SaveBtn.clicked.connect(self.save_detect_video)
self.ui.ExitBtn.clicked.connect(QCoreApplication.quit)
self.ui.FilesBtn.clicked.connect(self.detact_batch_imgs)
def initMain(self):
self.show_width = 700
self.show_height = 500
self.org_path = None
self.is_camera_open = False
self.cap = None
# self.device = 0 if torch.cuda.is_available() else 'cpu'
# 加载检测模型
self.model = YOLOv10('runs/detect/exp/weights/best.pt', task='detect')
self.model(np.zeros((48, 48, 3))) #预先加载推理模型
self.fontC = ImageFont.truetype("Font/platech.ttf", 25, 0)
self.colors = tools.Colors()
self.timer_camera = QTimer()
# 更新检测信息表格
# self.timer_info = QTimer()
# 保存视频
self.timer_save_video = QTimer()
# 表格
self.ui.tableWidget.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
self.ui.tableWidget.verticalHeader().setDefaultSectionSize(40)
self.ui.tableWidget.setColumnWidth(0, 80) # 设置列宽
self.ui.tableWidget.setColumnWidth(1, 200)
self.ui.tableWidget.setColumnWidth(2, 150)
self.ui.tableWidget.setColumnWidth(3, 90)
self.ui.tableWidget.setColumnWidth(4, 230)
self.ui.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows) # 设置表格整行选中
self.ui.tableWidget.verticalHeader().setVisible(False) # 隐藏列标题
self.ui.tableWidget.setAlternatingRowColors(True) # 表格背景交替
def open_img(self):
if self.cap:
# 打开图片前关闭摄像头
self.video_stop()
self.is_camera_open = False
self.ui.CaplineEdit.setText('摄像头未开启')
self.cap = None
file_path, _ = QFileDialog.getOpenFileName(None, '打开图片', './', "Image files (*.jpg *.jepg *.png)")
if not file_path:
return
self.ui.comboBox.setDisabled(False)
self.org_path = file_path
self.org_img = tools.img_cvread(self.org_path)
# 目标检测
t1 = time.time()
self.results = self.model(self.org_path)[0]
t2 = time.time()
take_time_str = '{:.3f} s'.format(t2 - t1)
self.ui.time_lb.setText(take_time_str)
location_list = self.results.boxes.xyxy.tolist()
self.location_list = [list(map(int, e)) for e in location_list]
cls_list = self.results.boxes.cls.tolist()
self.cls_list = [int(i) for i in cls_list]
self.conf_list = self.results.boxes.conf.tolist()
self.conf_list = ['%.2f %%' % (each*100) for each in self.conf_list]
total_nums = len(location_list)
cls_percents = []
for i in range(2):
res = self.cls_list.count(i) / total_nums
cls_percents.append(res)
self.set_percent(cls_percents)
now_img = self.results.plot()
self.draw_img = now_img
# 获取缩放后的图片尺寸
self.img_width, self.img_height = self.get_resize_size(now_img)
resize_cvimg = cv2.resize(now_img,(self.img_width, self.img_height))
pix_img = tools.cvimg_to_qpiximg(resize_cvimg)
self.ui.label_show.setPixmap(pix_img)
self.ui.label_show.setAlignment(Qt.AlignCenter)
# 设置路径显示
self.ui.PiclineEdit.setText(self.org_path)
# 目标数目
target_nums = len(self.cls_list)
self.ui.label_nums.setText(str(target_nums))
# 设置目标选择下拉框
choose_list = ['全部']
target_names = [Config.names[id]+ '_'+ str(index) for index,id in enumerate(self.cls_list)]
choose_list = choose_list + target_names
self.ui.comboBox.clear()
self.ui.comboBox.addItems(choose_list)
if target_nums >= 1:
self.ui.type_lb.setText(Config.CH_names[self.cls_list[0]])
self.ui.label_conf.setText(str(self.conf_list[0]))
self.ui.label_xmin.setText(str(self.location_list[0][0]))
self.ui.label_ymin.setText(str(self.location_list[0][1]))
self.ui.label_xmax.setText(str(self.location_list[0][2]))
self.ui.label_ymax.setText(str(self.location_list[0][3]))
else:
self.ui.type_lb.setText('')
self.ui.label_conf.setText('')
self.ui.label_xmin.setText('')
self.ui.label_ymin.setText('')
self.ui.label_xmax.setText('')
self.ui.label_ymax.setText('')
# # 删除表格所有行
self.ui.tableWidget.setRowCount(0)
self.ui.tableWidget.clearContents()
self.tabel_info_show(self.location_list, self.cls_list, self.conf_list,path=self.org_path)
def detact_batch_imgs(self):
if self.cap:
# 打开图片前关闭摄像头
self.video_stop()
self.is_camera_open = False
self.ui.CaplineEdit.setText('摄像头未开启')
self.cap = None
directory = QFileDialog.getExistingDirectory(self,
"选取文件夹",
"./") # 起始路径
if not directory:
return
self.org_path = directory
img_suffix = ['jpg','png','jpeg','bmp']
for file_name in os.listdir(directory):
full_path = os.path.join(directory,file_name)
if os.path.isfile(full_path) and file_name.split('.')[-1].lower() in img_suffix:
# self.ui.comboBox.setDisabled(False)
img_path = full_path
self.org_img = tools.img_cvread(img_path)
# 目标检测
t1 = time.time()
self.results = self.model(img_path)[0]
t2 = time.time()
take_time_str = '{:.3f} s'.format(t2 - t1)
self.ui.time_lb.setText(take_time_str)
location_list = self.results.boxes.xyxy.tolist()
self.location_list = [list(map(int, e)) for e in location_list]
cls_list = self.results.boxes.cls.tolist()
self.cls_list = [int(i) for i in cls_list]
self.conf_list = self.results.boxes.conf.tolist()
self.conf_list = ['%.2f %%' % (each * 100) for each in self.conf_list]
total_nums = len(location_list)
cls_percents = []
for i in range(2):
res = self.cls_list.count(i) / total_nums
cls_percents.append(res)
self.set_percent(cls_percents)
now_img = self.results.plot()
self.draw_img = now_img
# 获取缩放后的图片尺寸
self.img_width, self.img_height = self.get_resize_size(now_img)
resize_cvimg = cv2.resize(now_img, (self.img_width, self.img_height))
pix_img = tools.cvimg_to_qpiximg(resize_cvimg)
self.ui.label_show.setPixmap(pix_img)
self.ui.label_show.setAlignment(Qt.AlignCenter)
# 设置路径显示
self.ui.PiclineEdit.setText(img_path)
# 目标数目
target_nums = len(self.cls_list)
self.ui.label_nums.setText(str(target_nums))
# 设置目标选择下拉框
choose_list = ['全部']
target_names = [Config.names[id] + '_' + str(index) for index, id in enumerate(self.cls_list)]
choose_list = choose_list + target_names
self.ui.comboBox.clear()
self.ui.comboBox.addItems(choose_list)
if target_nums >= 1:
self.ui.type_lb.setText(Config.CH_names[self.cls_list[0]])
self.ui.label_conf.setText(str(self.conf_list[0]))
self.ui.label_xmin.setText(str(self.location_list[0][0]))
self.ui.label_ymin.setText(str(self.location_list[0][1]))
self.ui.label_xmax.setText(str(self.location_list[0][2]))
self.ui.label_ymax.setText(str(self.location_list[0][3]))
else:
self.ui.type_lb.setText('')
self.ui.label_conf.setText('')
self.ui.label_xmin.setText('')
self.ui.label_ymin.setText('')
self.ui.label_xmax.setText('')
self.ui.label_ymax.setText('')
# # 删除表格所有行
self.tabel_info_show(self.location_list, self.cls_list, self.conf_list, path=img_path)
self.ui.tableWidget.scrollToBottom()
QApplication.processEvents() #刷新页面
def draw_rect_and_tabel(self, results, img):
now_img = img.copy()
location_list = results.boxes.xyxy.tolist()
self.location_list = [list(map(int, e)) for e in location_list]
cls_list = results.boxes.cls.tolist()
self.cls_list = [int(i) for i in cls_list]
self.conf_list = results.boxes.conf.tolist()
self.conf_list = ['%.2f %%' % (each * 100) for each in self.conf_list]
for loacation, type_id, conf in zip(self.location_list, self.cls_list, self.conf_list):
type_id = int(type_id)
color = self.colors(int(type_id), True)
# cv2.rectangle(now_img, (int(x1), int(y1)), (int(x2), int(y2)), colors(int(type_id), True), 3)
now_img = tools.drawRectBox(now_img, loacation, Config.CH_names[type_id], self.fontC, color)
# 获取缩放后的图片尺寸
self.img_width, self.img_height = self.get_resize_size(now_img)
resize_cvimg = cv2.resize(now_img, (self.img_width, self.img_height))
pix_img = tools.cvimg_to_qpiximg(resize_cvimg)
self.ui.label_show.setPixmap(pix_img)
self.ui.label_show.setAlignment(Qt.AlignCenter)
# 设置路径显示
self.ui.PiclineEdit.setText(self.org_path)
# 目标数目
target_nums = len(self.cls_list)
self.ui.label_nums.setText(str(target_nums))
if target_nums >= 1:
self.ui.type_lb.setText(Config.CH_names[self.cls_list[0]])
self.ui.label_conf.setText(str(self.conf_list[0]))
self.ui.label_xmin.setText(str(self.location_list[0][0]))
self.ui.label_ymin.setText(str(self.location_list[0][1]))
self.ui.label_xmax.setText(str(self.location_list[0][2]))
self.ui.label_ymax.setText(str(self.location_list[0][3]))
else:
self.ui.type_lb.setText('')
self.ui.label_conf.setText('')
self.ui.label_xmin.setText('')
self.ui.label_ymin.setText('')
self.ui.label_xmax.setText('')
self.ui.label_ymax.setText('')
# 删除表格所有行
self.ui.tableWidget.setRowCount(0)
self.ui.tableWidget.clearContents()
self.tabel_info_show(self.location_list, self.cls_list, self.conf_list, path=self.org_path)
return now_img
def combox_change(self):
com_text = self.ui.comboBox.currentText()
if com_text == '全部':
cur_box = self.location_list
cur_img = self.results.plot()
self.ui.type_lb.setText(Config.CH_names[self.cls_list[0]])
self.ui.label_conf.setText(str(self.conf_list[0]))
else:
index = int(com_text.split('_')[-1])
cur_box = [self.location_list[index]]
cur_img = self.results[index].plot()
self.ui.type_lb.setText(Config.CH_names[self.cls_list[index]])
self.ui.label_conf.setText(str(self.conf_list[index]))
# 设置坐标位置值
self.ui.label_xmin.setText(str(cur_box[0][0]))
self.ui.label_ymin.setText(str(cur_box[0][1]))
self.ui.label_xmax.setText(str(cur_box[0][2]))
self.ui.label_ymax.setText(str(cur_box[0][3]))
resize_cvimg = cv2.resize(cur_img, (self.img_width, self.img_height))
pix_img = tools.cvimg_to_qpiximg(resize_cvimg)
self.ui.label_show.clear()
self.ui.label_show.setPixmap(pix_img)
self.ui.label_show.setAlignment(Qt.AlignCenter)
def get_video_path(self):
file_path, _ = QFileDialog.getOpenFileName(None, '打开视频', './', "Image files (*.avi *.mp4 *.jepg *.png)")
if not file_path:
return None
self.org_path = file_path
self.ui.VideolineEdit.setText(file_path)
return file_path
def video_start(self):
# 删除表格所有行
self.ui.tableWidget.setRowCount(0)
self.ui.tableWidget.clearContents()
# 清空下拉框
self.ui.comboBox.clear()
# 定时器开启,每隔一段时间,读取一帧
self.timer_camera.start(1)
self.timer_camera.timeout.connect(self.open_frame)
def tabel_info_show(self, locations, clses, confs, path=None):
path = path
for location, cls, conf in zip(locations, clses, confs):
row_count = self.ui.tableWidget.rowCount() # 返回当前行数(尾部)
self.ui.tableWidget.insertRow(row_count) # 尾部插入一行
item_id = QTableWidgetItem(str(row_count+1)) # 序号
item_id.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter) # 设置文本居中
item_path = QTableWidgetItem(str(path)) # 路径
# item_path.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
item_cls = QTableWidgetItem(str(Config.CH_names[cls]))
item_cls.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter) # 设置文本居中
item_conf = QTableWidgetItem(str(conf))
item_conf.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter) # 设置文本居中
item_location = QTableWidgetItem(str(location)) # 目标框位置
# item_location.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter) # 设置文本居中
self.ui.tableWidget.setItem(row_count, 0, item_id)
self.ui.tableWidget.setItem(row_count, 1, item_path)
self.ui.tableWidget.setItem(row_count, 2, item_cls)
self.ui.tableWidget.setItem(row_count, 3, item_conf)
self.ui.tableWidget.setItem(row_count, 4, item_location)
self.ui.tableWidget.scrollToBottom()
def video_stop(self):
self.cap.release()
self.timer_camera.stop()
# self.timer_info.stop()
def open_frame(self):
ret, now_img = self.cap.read()
if ret:
# 目标检测
t1 = time.time()
results = self.model(now_img)[0]
t2 = time.time()
take_time_str = '{:.3f} s'.format(t2 - t1)
self.ui.time_lb.setText(take_time_str)
location_list = results.boxes.xyxy.tolist()
self.location_list = [list(map(int, e)) for e in location_list]
cls_list = results.boxes.cls.tolist()
self.cls_list = [int(i) for i in cls_list]
self.conf_list = results.boxes.conf.tolist()
self.conf_list = ['%.2f %%' % (each * 100) for each in self.conf_list]
total_nums = len(location_list)
cls_percents = []
for i in range(2):
if total_nums!= 0 :
res = self.cls_list.count(i) / total_nums
else :
res=0
cls_percents.append(res)
self.set_percent(cls_percents)
now_img = results.plot()
# 获取缩放后的图片尺寸
self.img_width, self.img_height = self.get_resize_size(now_img)
resize_cvimg = cv2.resize(now_img, (self.img_width, self.img_height))
pix_img = tools.cvimg_to_qpiximg(resize_cvimg)
self.ui.label_show.setPixmap(pix_img)
self.ui.label_show.setAlignment(Qt.AlignCenter)
# 目标数目
target_nums = len(self.cls_list)
self.ui.label_nums.setText(str(target_nums))
# 设置目标选择下拉框
choose_list = ['全部']
target_names = [Config.names[id] + '_' + str(index) for index, id in enumerate(self.cls_list)]
choose_list = choose_list + target_names
self.ui.comboBox.clear()
self.ui.comboBox.addItems(choose_list)
if target_nums >= 1:
self.ui.type_lb.setText(Config.CH_names[self.cls_list[0]])
self.ui.label_conf.setText(str(self.conf_list[0]))
self.ui.label_xmin.setText(str(self.location_list[0][0]))
self.ui.label_ymin.setText(str(self.location_list[0][1]))
self.ui.label_xmax.setText(str(self.location_list[0][2]))
self.ui.label_ymax.setText(str(self.location_list[0][3]))
else:
self.ui.type_lb.setText('')
self.ui.label_conf.setText('')
self.ui.label_xmin.setText('')
self.ui.label_ymin.setText('')
self.ui.label_xmax.setText('')
self.ui.label_ymax.setText('')
self.tabel_info_show(self.location_list, self.cls_list, self.conf_list, path=self.org_path)
else:
self.cap.release()
self.timer_camera.stop()
def vedio_show(self):
if self.is_camera_open:
self.is_camera_open = False
self.ui.CaplineEdit.setText('摄像头未开启')
video_path = self.get_video_path()
if not video_path:
return None
self.cap = cv2.VideoCapture(video_path)
self.video_start()
self.ui.comboBox.setDisabled(True)
def camera_show(self):
self.is_camera_open = not self.is_camera_open
if self.is_camera_open:
self.ui.CaplineEdit.setText('摄像头开启')
self.cap = cv2.VideoCapture(0)
self.video_start()
self.ui.comboBox.setDisabled(True)
else:
self.ui.CaplineEdit.setText('摄像头未开启')
self.ui.label_show.setText('')
if self.cap:
self.cap.release()
cv2.destroyAllWindows()
self.ui.label_show.clear()
def get_resize_size(self, img):
_img = img.copy()
img_height, img_width , depth= _img.shape
ratio = img_width / img_height
if ratio >= self.show_width / self.show_height:
self.img_width = self.show_width
self.img_height = int(self.img_width / ratio)
else:
self.img_height = self.show_height
self.img_width = int(self.img_height * ratio)
return self.img_width, self.img_height
def save_detect_video(self):
if self.cap is None and not self.org_path:
QMessageBox.about(self, '提示', '当前没有可保存信息,请先打开图片或视频!')
return
if self.is_camera_open:
QMessageBox.about(self, '提示', '摄像头视频无法保存!')
return
if self.cap:
res = QMessageBox.information(self, '提示', '保存视频检测结果可能需要较长时间,请确认是否继续保存?',QMessageBox.Yes | QMessageBox.No , QMessageBox.Yes)
if res == QMessageBox.Yes:
self.video_stop()
com_text = self.ui.comboBox.currentText()
self.btn2Thread_object = btn2Thread(self.org_path, self.model, com_text)
self.btn2Thread_object.start()
self.btn2Thread_object.update_ui_signal.connect(self.update_process_bar)
else:
return
else:
if os.path.isfile(self.org_path):
fileName = os.path.basename(self.org_path)
name , end_name= fileName.rsplit(".",1)
save_name = name + '_detect_result.' + end_name
save_img_path = os.path.join(Config.save_path, save_name)
# 保存图片
cv2.imwrite(save_img_path, self.draw_img)
QMessageBox.about(self, '提示', '图片保存成功!\n文件路径:{}'.format(save_img_path))
else:
img_suffix = ['jpg', 'png', 'jpeg', 'bmp']
for file_name in os.listdir(self.org_path):
full_path = os.path.join(self.org_path, file_name)
if os.path.isfile(full_path) and file_name.split('.')[-1].lower() in img_suffix:
name, end_name = file_name.rsplit(".",1)
save_name = name + '_detect_result.' + end_name
save_img_path = os.path.join(Config.save_path, save_name)
results = self.model(full_path)[0]
now_img = results.plot()
# 保存图片
cv2.imwrite(save_img_path, now_img)
QMessageBox.about(self, '提示', '图片保存成功!\n文件路径:{}'.format(Config.save_path))
def update_process_bar(self,cur_num, total):
if cur_num == 1:
self.progress_bar = ProgressBar(self)
self.progress_bar.show()
if cur_num >= total:
self.progress_bar.close()
QMessageBox.about(self, '提示', '视频保存成功!\n文件在{}目录下'.format(Config.save_path))
return
if self.progress_bar.isVisible() is False:
# 点击取消保存时,终止进程
self.btn2Thread_object.stop()
return
value = int(cur_num / total *100)
self.progress_bar.setValue(cur_num, total, value)
QApplication.processEvents()
def set_percent(self, probs):
# 显示各表情概率值
items = [self.ui.progressBar, self.ui.progressBar_2]
labels = [self.ui.label_20, self.ui.label_21]
prob_values = [round(each * 100) for each in probs]
label_values = ['{:.1f}%'.format(each * 100) for each in probs]
for i in range(len(probs)):
items[i].setValue(prob_values[i])
labels[i].setText(label_values[i])
class btn2Thread(QThread):
update_ui_signal = pyqtSignal(int,int)
def __init__(self, path, model, com_text):
super(btn2Thread, self).__init__()
self.org_path = path
self.model = model
self.com_text = com_text
# 用于绘制不同颜色矩形框
self.colors = tools.Colors()
self.is_running = True # 标志位,表示线程是否正在运行
def run(self):
# VideoCapture方法是cv2库提供的读取视频方法
cap = cv2.VideoCapture(self.org_path)
# 设置需要保存视频的格式“xvid”
# 该参数是MPEG-4编码类型,文件名后缀为.avi
fourcc = cv2.VideoWriter_fourcc(*'XVID')
# 设置视频帧频
fps = cap.get(cv2.CAP_PROP_FPS)
# 设置视频大小
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
# VideoWriter方法是cv2库提供的保存视频方法
# 按照设置的格式来out输出
fileName = os.path.basename(self.org_path)
name, end_name = fileName.split('.')
save_name = name + '_detect_result.avi'
save_video_path = os.path.join(Config.save_path, save_name)
out = cv2.VideoWriter(save_video_path, fourcc, fps, size)
prop = cv2.CAP_PROP_FRAME_COUNT
total = int(cap.get(prop))
print("[INFO] 视频总帧数:{}".format(total))
cur_num = 0
# 确定视频打开并循环读取
while (cap.isOpened() and self.is_running):
cur_num += 1
print('当前第{}帧,总帧数{}'.format(cur_num, total))
ret, frame = cap.read()
if ret == True:
# 检测
results = self.model(frame)[0]
frame = results.plot()
out.write(frame)
self.update_ui_signal.emit(cur_num, total)
else:
break
# 释放资源
cap.release()
out.release()
def stop(self):
self.is_running = False
if __name__ == "__main__":
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
标签:烟雾,img,self,list,setText,火焰,ui,path,源码 From: https://blog.csdn.net/m0_68036862/article/details/143441291