跳到主要内容
基于 YOLOv5 的深度学习火焰检测识别系统 | 极客日志
Python AI 算法
基于 YOLOv5 的深度学习火焰检测识别系统 基于 YOLOv5 的深度学习火焰检测系统利用卷积神经网络提取火灾场景特征。通过 LabelImg 工具构建 VOC 格式数据集,配置 YOLOv5 网络参数进行训练。系统支持图片、视频及摄像头实时检测,并集成 PyQt5 界面。该方法能自动快速识别火焰,降低火灾损失。
Eee_123 发布于 2026/3/21 更新于 2026/5/6 7 浏览1 项目运行效果
视频效果:
2 基于 YOLO 的火焰检测与识别
系统实现效果如下,精度不错!下面用一个小 demo 做大致原理讲解,实际工程要相对复杂。
3 课题背景
火灾事故的频发给社会造成不必要的财富损失以及人员伤亡,在当今这个社会消防也是受到越来越多的注视。火灾在发生初期是很容易控制的,因此,如何在对可能发生灾害的场所进行有效监控,使得潜在的损失危害降到最低是当前研究的重点内容。传统的探测器有较大的局限性,感温、感烟的探测器的探测灵敏度相对瞬息万变的灾情控制来说有着时间上的不足,而且户外场所的适用性大大降低。随着计算机视觉的发展,基于深度学习的图像处理技术已经愈发成熟并且广泛应用在当今社会的许多方面,其在人脸识别、安防、医疗、军事等领域已经有相当一段时间的实际应用,在其他领域也展现出更广阔的前景。利用深度学习图像处理技术对火灾场景下火焰的特征学习、训练神经网络模型自动识别火焰,这项技术可以对具有监控摄像头场景下的火灾火焰进行自动、快速、准确识别并设置预警装置,从而在火灾发生的初期及时响应,赢得更多的时间,把损失降到最低。
4 卷积神经网络
受到人类大脑神经突触结构相互连接的模式启发,神经网络作为人工智能领域的重要组成部分,通过分布式的方法处理信息,可以解决复杂的非线性问题,从构造方面来看,主要包括输入层、隐藏层、输出层三大组成结构。每一个节点被称为一个神经元,存在着对应的权重参数,部分神经元存在偏置,当输入数据 x 进入后,对于经过的神经元都会进行类似于:y=w*x+b 的线性函数的计算,其中 w 为该位置神经元的权值,b 则为偏置函数。通过每一层神经元的逻辑运算,将结果输入至最后一层的激活函数,最后得到输出 output。
4.1 卷积层 卷积核相当于一个滑动窗口,示意图中 3x3 大小的卷积核依次划过 6x6 大小的输入数据中的对应区域,并与卷积核滑过区域做矩阵点乘,将所得结果依次填入对应位置即可得到右侧 4x4 尺寸的卷积特征图,例如划到右上角 3x3 所圈区域时,将进行 00+1 1+21+1 1+00+1 1+10+2 01 1=6 的计算操作,并将得到的数值填充到卷积特征的右上角。
4.2 池化层 池化操作又称为降采样,提取网络主要特征可以在达到空间不变性的效果同时,有效地减少网络参数,因而简化网络计算复杂度,防止过拟合现象的出现。在实际操作中经常使用最大池化或平均池化两种方式,如下图所示。虽然池化操作可以有效的降低参数数量,但过度池化也会导致一些图片细节的丢失,因此在搭建网络时要根据实际情况来调整池化操作。
4.3 激活函数 激活函数大致分为两种,在卷积神经网络的发展前期,使用较为传统的饱和激活函数,主要包括 sigmoid 函数、tanh 函数等;随着神经网络的发展,研究者发现了饱和激活函数的弱点,并针对其存在的潜在问题,研究了非饱和激活函数,其主要含有 ReLU 函数及其函数变体。
4.4 全连接层 在整个网络结构中起到'分类器'的作用,经过前面卷积层、池化层、激活函数层之后,网络已经对输入图片的原始数据进行特征提取,并将其映射到隐藏特征空间,全连接层将负责将学习到的特征从隐藏特征空间映射到样本标记空间,一般包括提取到的特征在图片上的位置信息以及特征所属类别概率等。将隐藏特征空间的信息具象化,也是图像处理当中的重要一环。
4.5 使用 tensorflow 中 keras 模块实现卷积神经网络 class CNN (tf.keras.Model):
def __init__ (self ):
super ().__init__()
self .conv1 = tf.keras.layers.Conv2D(
filters=32 ,
kernel_size=[5 ,5 ],
padding='same' ,
activation=tf.nn.relu
)
self .pool1 = tf.keras.layers.MaxPool2D(pool_size=[2 ,2 ], strides=2 )
self .conv2 = tf.keras.layers.Conv2D(
filters=64 ,
kernel_size=[5 ,5 ],
padding='same' ,
activation=tf.nn.relu
)
self .pool2 = tf.keras.layers.MaxPool2D(pool_size=[2 ,2 ], strides=2 )
self .flatten = tf.keras.layers.Reshape(target_shape=(7 *7 *64 ,))
self .dense1 = tf.keras.layers.Dense(units=1024 , activation=tf.nn.relu)
self .dense2 = tf.keras.layers.Dense(units=10 )
def call (self, inputs ):
x = self .conv1(inputs)
x = self .pool1(x)
x = self .conv2(x)
x = self .pool2(x)
x = self .flatten(x)
x = self .dense1(x)
x = self .dense2(x)
output = tf.nn.softmax(x)
return output
5 YOLOV5 我们选择当下 YOLO 最新的卷积神经网络 YOLOv5 来进行火焰识别检测。Ultralytics 公司开源了 YOLOv5,完全基于 PyTorch 实现。YOLOv5 带来了更强实时目标检测技术。按照官方给出的数目,现版本的 YOLOv5 每个图像的推理时间最快 0.007 秒,即每秒 140 帧(FPS),但 YOLOv5 的权重文件大小只有 YOLOv4 的 1/9。
目标检测架构分为两种,一种是 two-stage,一种是 one-stage,区别就在于 two-stage 有 region proposal 过程,类似于一种海选过程,网络会根据候选区域生成位置和类别,而 one-stage 直接从图片生成位置和类别。今天提到的 YOLO 就是一种 one-stage 方法。YOLO 是 You Only Look Once 的缩写,意思是神经网络只需要看一次图片,就能输出结果。YOLO 一共发布了五个版本,其中 YOLOv1 奠定了整个系列的基础,后面的系列就是在第一版基础上的改进,为的是提升性能。
5.1 网络架构图 YOLOv5 是一种单阶段目标检测算法,该算法在 YOLOv4 的基础上添加了一些新的改进思路,使其速度与精度都得到了极大的性能提升。主要的改进思路如下所示:
5.2 输入端 在模型训练阶段,提出了一些改进思路,主要包括 Mosaic 数据增强、自适应锚框计算、自适应图片缩放;
Mosaic 数据增强 :Mosaic 数据增强的作者也是来自 YOLOv5 团队的成员,通过随机缩放、随机裁剪、随机排布的方式进行拼接,对小目标的检测效果很不错
5.3 基准网络 融合其它检测算法中的一些新思路,主要包括:Focus 结构与 CSP 结构;
5.4 Neck 网络 在目标检测领域,为了更好的提取融合特征,通常在 Backbone 和输出层,会插入一些层,这个部分称为 Neck。Yolov5 中添加了 FPN+PAN 结构,相当于目标检测网络的颈部,也是非常关键的。
这样结合操作,FPN 层自顶向下传达强语义特征(High-Level 特征),而特征金字塔则自底向上传达强定位特征(Low-Level 特征),两两联手,从不同的主干层对不同的检测层进行特征聚合。
FPN+PAN 借鉴的是 18 年 CVPR 的 PANet,当时主要应用于图像分割领域,但 Alexey 将其拆分应用到 Yolov4 中,进一步提高特征提取的能力。
5.5 Head 输出层 输出层的锚框机制与 YOLOv4 相同,主要改进的是训练时的损失函数 GIOU_Loss,以及预测框筛选的 DIOU_nms。
对于 Head 部分,可以看到三个紫色箭头处的特征图是 40×40、20×20、10×10。以及最后 Prediction 中用于预测的 3 个特征图:
①==>40×40×255 ②==>20×20×255 ③==>10×10×255
class Detect (nn.Module):
stride = None
onnx_dynamic = False
def __init__ (self, nc=80 , anchors=( ), ch=( ), inplace=True ):
super ().__init__()
self .nc = nc
self .no = nc + 5
self .nl = len (anchors)
self .na = len (anchors[0 ]) // 2
self .grid = [torch.zeros(1 )] * self .nl
self .anchor_grid = [torch.zeros(1 )] * self .nl
self .register_buffer('anchors' , torch.tensor(anchors).float ().view(self .nl,-1 ,2 ))
self .m = nn.ModuleList(nn.Conv2d(x, self .no * self .na,1 ) for x in ch)
self .inplace = inplace
def forward (self, x ):
z = []
for i in range (self .nl):
x[i] = self .m[i](x[i])
bs, _, ny, nx = x[i].shape
x[i] = x[i].view(bs, self .na, self .no, ny, nx).permute(0 ,1 ,3 ,4 ,2 ).contiguous()
if not self .training:
if self .onnx_dynamic or self .grid[i].shape[2 :4 ] != x[i].shape[2 :4 ]:
self .grid[i], self .anchor_grid[i] = self ._make_grid(nx, ny, i)
y = x[i].sigmoid()
if self .inplace:
y[...,0 :2 ] = (y[...,0 :2 ]*2 -0.5 +self .grid[i])*self .stride[i]
y[...,2 :4 ] = (y[...,2 :4 ]*2 )**2 *self .anchor_grid[i]
else :
xy = (y[...,0 :2 ]*2 -0.5 +self .grid[i])*self .stride[i]
wh = (y[...,2 :4 ]*2 )**2 *self .anchor_grid[i]
y = torch.cat((xy, wh, y[...,4 :]),-1 )
z.append(y.view(bs,-1 , self .no))
return x if self .training else (torch.cat(z,1 ), x)
def _make_grid (self, nx=20 , ny=20 , i=0 ):
d = self .anchors[i].device
if check_version(torch.__version__,'1.10.0' ):
yv, xv = torch.meshgrid([torch.arange(ny).to(d), torch.arange(nx).to(d)], indexing='ij' )
else :
yv, xv = torch.meshgrid([torch.arange(ny).to(d), torch.arange(nx).to(d)])
grid = torch.stack((xv, yv),2 ).expand((1 , self .na, ny, nx,2 )).float ()
anchor_grid = (self .anchors[i].clone()*self .stride[i]) .view((1 , self .na,1 ,1 ,2 )).expand((1 , self .na, ny, nx,2 )).float ()
return grid, anchor_grid
6 数据集准备 由于目前针对多源场景下的火焰数据并没有现成的数据集,我们使用 Python 爬虫利用关键字在互联网上获得的图片数据,爬取数据包含室内场景下的火焰、写字楼和房屋燃烧、森林火灾和车辆燃烧等场景下的火焰图片。经过筛选后留下 3000 张质量较好的图片制作成 VOC 格式的实验数据集。
深度学习图像标注软件众多,按照不同分类标准有多种类型,本文使用 LabelImg 单机标注软件进行标注。LabelImg 是基于角点的标注方式产生边界框,对图片进行标注得到 xml 格式的标注文件,由于边界框对检测精度的影响较大因此采用手动标注,并没有使用自动标注软件。
6.1 数据标注简介 打开你所需要进行标注的文件夹,点击红色框区域进行标注格式切换,我们需要 yolo 格式,因此切换到 yolo
点击 Create RectBo -> 拖拽鼠标框选目标 -> 给上标签 -> 点击 ok
6.2 数据保存 打开具体的标注文件,你将会看到下面的内容,txt 文件中每一行表示一个目标,以空格进行区分,分别表示目标的类别 id,归一化处理之后的中心点 x 坐标、y 坐标、目标框的 w 和 h。
7 模型训练 预训练模型和数据集都准备好了,就可以开始训练自己的 yolov5 目标检测模型了,训练目标检测模型需要修改两个 yaml 文件中的参数。一个是 data 目录下的相应的 yaml 文件,一个是 model 目录文件下的相应的 yaml 文件。
7.1 修改数据配置文件 修改 data 目录下的相应的 yaml 文件。找到目录下的 voc.yaml 文件,将该文件复制一份,将复制的文件重命名,最好和项目相关,这样方便后面操作。我这里修改为 fire.yaml。
打开这个文件夹修改其中的参数,需要检测的类别数,我这里是识别有无火焰,所以这里填写 2;最后箭头 4 中填写需要识别的类别的名字(必须是英文,否则会乱码识别不出来)。到这里和 data 目录下的 yaml 文件就修改好了。
7.2 修改模型配置文件 由于该项目使用的是 yolov5s.pt 这个预训练权重,所以要使用 models 目录下的 yolov5s.yaml 文件中的相应参数(因为不同的预训练权重对应着不同的网络层数,所以用错预训练权重会报错)。同上修改 data 目录下的 yaml 文件一样,我们最好将 yolov5s.yaml 文件复制一份,然后将其重命名
打开 yolov5s.yaml 文件,主要是进去后修改 nc 这个参数来进行类别的修改,修改如图中的数字就好了,这里是识别两个类别。
7.3 开始训练模型 如果上面的数据集和两个 yaml 文件的参数都修改好了的话,就可以开始 yolov5 的训练了。首先我们找到 train.py 这个 py 文件。
然后找到主函数的入口,这里面有模型的主要参数。修改 train.py 中的 weights、cfg、data、epochs、batch_size、imgsz、device、workers 等参数
至此,就可以运行 train.py 函数训练自己的模型了。
训练代码成功执行之后会在命令行中输出下列信息,接下来就是安心等待模型训练结束即可。
8 实现效果 我们实现了图片检测,视频检测和摄像头实时检测接口,用 PyQt 自制了简单 UI
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Win_mask (object ):
def setupUi (self, Win_mask ):
Win_mask.setObjectName("Win_mask" )
Win_mask.resize(1107 ,868 )
Win_mask.setStyleSheet("QString qstrStylesheet = \"background-color:rgb(43, 43, 255)\";\n" "ui.pushButton->setStyleSheet(qstrStylesheet);" )
self .frame = QtWidgets.QFrame(Win_mask)
self .frame.setGeometry(QtCore.QRect(10 ,140 ,201 ,701 ))
self .frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self .frame.setFrameShadow(QtWidgets.QFrame.Raised)
self .frame.setObjectName("frame" )
self .pushButton = QtWidgets.QPushButton(self .frame)
self .pushButton.setGeometry(QtCore.QRect(10 ,40 ,161 ,51 ))
font = QtGui.QFont()
font.setBold(True )
font.setUnderline(True )
font.setWeight(75 )
self .pushButton.setFont(font)
self .pushButton.setStyleSheet("QPushButton{background-color:rgb(151, 191, 255);}" )
self .pushButton.setObjectName("pushButton" )
self .pushButton_2 = QtWidgets.QPushButton(self .frame)
self .pushButton_2.setGeometry(QtCore.QRect(10 ,280 ,161 ,51 ))
font = QtGui.QFont()
font.setBold(True )
font.setUnderline(True )
font.setWeight(75 )
self .pushButton_2.setFont(font)
self .pushButton_2.setStyleSheet("QPushButton{background-color:rgb(151, 191, 255};}" )
self .pushButton_2.setObjectName("pushButton_2" )
self .pushButton_3 = QtWidgets.QPushButton(self .frame)
self .pushButton_3.setGeometry(QtCore.QRect(10 ,500 ,161 ,51 ))
QtCore.QMetaObject.connectSlotsByName(Win_mask)
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
随机西班牙地址生成器 随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online