ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

森林防火检测系统实战:YOLO+Spring Boot+Vue与大模型研判

森林防火检测系统实战:YOLO+Spring Boot+Vue与大模型研判 监控大屏上突然弹出一条火焰报警我盯着画面看了十秒才发现那只是一辆红色集装箱车反射的夕阳。这种事在森林防火视频监控里太常见了——误报能把值班员的耐心磨光漏报又可能让我们错过扑救的黄金窗口。尤其烟雾目标远处林间的浅色薄烟又稀又透人和传统算法都容易漏。我做的这套系统目标就是把“看到火”和“看懂火”分开先用YOLO做检测再用Spring Boot、Vue搭业务闭环最后用DeepSeek和千问大模型自动生成火情研判简报。不管你是在研究YOLO模型对比还是被Spring Boot、Vue、Flask这几个词的集成方式卡住又或者只想给检测结果加个大模型“开口说话”的智能分析层这篇实现笔记都值得你看完。1. 森林防火检测系统的整体分工别让一个技术栈干所有活很多从算法转全栈的同学容易陷入一个误区看到一个Spring BootVueFlask组合第一反应是“为什么要搞这么多端直接一个Python服务不就能出页面了吗”真做过视频AI项目的人会理解这不是炫技是无奈。检测服务和业务服务对运行环境的要求是冲突的模型推理要GPU、要CUDA、要Python生态而业务系统要稳定的事务、权限、数据库连接池这两类东西硬塞进同一个进程后期维护会非常痛苦。项目早期的架构草稿里我确实试过用Python Flask直接写接口并管理用户和告警记录结果数据库迁移改一次就崩一次。后来整体拆成了四层。分层技术选型核心职责数据采集层摄像头RTSP、无人机视频流、M3U8拉流图像帧抽取、视频流接入AI推理层Flask Ultralytics YOLO火焰、烟雾目标检测返回标注框业务服务层Spring Boot Spring Data JPA设备管理、告警记录、权限、大模型调用展示层Vue 3 Element Plus ECharts实时视频预览、告警大屏、历史回放AI推理层是纯Python服务部署在一台单独的GPU机器上Spring Boot跑在应用服务器通过HTTP接口调用推理服务Vue负责把数据变成值班员看得懂的界面。刚开始我不理解为什么Spring Boot不直接读模型做推理后来想明白了训练好的模型只是PyTorch的torch.save结果Java端要对它做预处理、推理、后处理等于把YOLO的DNN结构在Java里重新实现一遍这个维护成本和坑深度远超想象。Flask服务的好处就是轻轻到可以随模型版本快速替换。这里要说明一个设计细节为什么用Flask而不是FastAPI。我在实际项目里两个都用过理论上FastAPI性能更好自带文档和参数校验但项目中推理服务本身没有高并发场景模型推理一帧就要20毫秒起步HTTP框架那点性能差距完全可以忽略。反而是Flask生态和已有脚本兼容性更直接团队里负责标注和训练的同学拿到代码几乎零学习成本。如果你的场景是大量并发请求可以换FastAPI但核心工程思想不变。2. 五个YOLO版本的选型对比看结构、看损失、看实际数据YOLOv8、v10、v11、v12、26光看版本号就能让人头皮发麻。网上铺天盖地的论文对比真正落到火焰烟雾场景下的参考反而不多。我在训练前把五个主流版本全部跑了一遍这里分享我自己的判断逻辑。2.1 版本演进背后的核心结构差异YOLOv8算是一个分水岭它真正把anchor-free做成了默认配置解耦头里分类和回归各管各的。YOLOv10最大的变化是端到端训练去掉了推理时对NMS的依赖用一对一匹配策略解决重复框问题。YOLOv11在v8的基础上重构了C3k2模块把一些注意力机制用得更节省参数。YOLOv12则把跨层注意力引入到检测头里对细微纹理特征的表达会好一些。到了YOLO26官方在实时检测的边缘设备优化和小目标处理上做了不少文章。对火焰烟雾这个具体场景这些结构差异意味着什么火焰目标比较“实”边缘清楚、颜色暖色占主导对任何版本的YOLO都不算太难烟雾是真正考验模型的类型它没有固定形状边缘渐变容易被当成背景模糊纹理。YOLOv12的注意力机制能稍微把烟雾轮廓和云层分开但代价是推理速度肉眼可见地下降在普通GPU上有点得不偿失。2.2 从损失函数看模型理念YOLO检测结构里监督信息分为三部分分类损失用BCE边界框回归损失用CIoU加DFL。在Ultralytics训练过程中你会在日志里看到cls_loss、box_loss、dfl_loss这三项。火焰烟雾检测最容易出现的问题不是分类错而是回归框不稳定烟雾目标太大或太小都会导致回归不收敛。实战处理时我会把box损失权重稍微调高默认配置往往是通用场景的折中值不一定适合大面积的烟柱。如果你打开YOLOv8的配置会发现损失函数不像传统论文那样可以随意替换。你真正能调的其实是数据端把烟雾标注框的大小分布控制均匀一些比调十个超参都管用。这是我训练到第三轮才悟出来的。2.3 五版本的实测结果与选型建议我在一个自建的森林火灾数据集中进行了公平对比训练轮次统一300轮图片尺寸统一1280不提前终止。模型参数量约平均推理耗时ms烟雾召回能力部署体积我的结论YOLOv8s11M8中等小最稳适合起步YOLOv10n2.7M5中等偏下极小低算力设备可以YOLOv11s9.4M7较强小性价比之王YOLOv12s12M12强中注意力结构提升细节YOLO26s约10M9强中小目标友好但生态较新这个结果不是让你无脑选v11或删掉其他而是说明一个道理每个版本迭代都会带来一些指标提升但在野火检测这类强背景复杂场景下“提升”不一定能体现在mAP上更多体现在漏检率上。我最终生产环境用的是YOLOv11s做日常YOLO26s作为备选模型做二次校验。为什么不用v12跑正式环境因为它的推理耗时在视频轮询场景中会造成队列积压为了一点烟雾召回提升牺牲实时性不划算。3. 数据标注、损失曲线与训练调参这个项目最大的坑不在模型本身网上教程喜欢一上来就让人跑demo但森林火灾检测这种目标明显、样本却极度不均衡的任务数据工作的优先级高于一切。我一开始从公开数据集里拉了一堆火焰烟雾图片直接训练发现模型在测试集上准确率很高一到真实林场视频就废了。根本原因在于公开数据里的烟基本都是浓烟、黑烟长度占据图片较大面积而野外监控里的初火烟雾往往是几公里外的一小团灰白透明区域压根不是一个分布。3.1 标注策略决定上限标注阶段我们用了X-AnyLabeling做辅助标注它可以把SAM模型接入先自动分割再人工确认。火焰很好标烟雾叫人头疼。可能同一个林间烟雾图三个人能标出三种完全不同的边界。后来我定了一个笨但有效的规矩只要能肉眼确认不是云、不是雾霾、不是镜头脏点就尽量把半透明烟雾区域完整框出来哪怕边缘模糊。对于远处若隐若现的烟宁可不标也不能过标成正常物体。漏标只会让模型变笨错标会让模型变瞎。类别建议用两个单独类别fire和smoke不要合并成“火灾”。虽然业务上最终都是报警但训练时合并会导致模型对“火焰和烟雾同时出现”的情况产生混淆。数据平衡上我按火焰:烟雾1:2.5的比例准备因为烟雾难检样本太少直接学不到。3.2 图片尺寸、增强与标签分配默认的640图片尺寸对火焰可以对远处烟雾不够。烟雾目标可能只有十几个像素在640分辨率下经过多次下采样特征图上的信息几乎没了。我把训练尺寸提到1280后烟雾召回率提升了约9个百分点。代价是显存占用几乎翻倍我的显卡训练一个模型从12GB涨到接近20GB只能用半精度和梯度累积硬扛。数据增强我重点用了Mosaic、MixUp、HSV微调。Mosaic对提升小目标感受野非常有用四张图拼到一起模型相当于在缩小版的图像里学习。烟雾的HSV增强要小心烟雾颜色很素过分调整饱和度会把白烟变成奇怪的颜色。我遇到过训练Loss一路下降但验证集mAP一直震荡的情况最后查下来就是增强参数开太猛模型学到的是“看起来像野火的颜色”而不是“结构上像烟雾”。3.3 用损失曲线和混淆矩阵调阈值在打死不改模型结构的前提下阈值策略比网络结构对业务影响更大。火焰的置信度阈值我设为0.5烟雾设成0.25为什么烟雾要低因为漏报一场火的代价比误报高得多低阈值换来的是更多疑似框这些框到业务层可以再通过“连续多帧确认”来过滤不直接报警就行。训练时会特别关注置信度矩阵里烟雾被误分成背景的概率。我用Ultralytics提供的混淆矩阵和PR曲线图判断如果烟雾召回率到了瓶颈但precision还有空间就下调置信度阈值如果误报太多就反向调整。别迷信某个固定阈值每个模型的输出分布都不一样。4. Flask推理服务的工程化细节稳定性比单帧速度更重要模型训练出来只是第一步真正上线跑7x24小时又是另一码事。我一开始就是简单写了个Flask接口模型在请求时加载一调用就卡十秒后来才知道模型初始化、权重加载、CUDA上下文创建在全过程非常耗时。正确的做法是在进程启动时就预加载模型。# app.py 核心骨架 from flask import Flask, request, jsonify from model_loader import ModelHub import base64, cv2 import numpy as np app Flask(__name__) hub ModelHub() hub.load_all(devicecuda:0, halfTrue) app.post(/api/v1/detect) def detect(): data request.get_json() image np.frombuffer(base64.b64decode(data[image]), dtypenp.uint8) image cv2.imdecode(image, cv2.IMREAD_COLOR) model_name data.get(model_name, yolo11s) results hub.predict(model_name, image, confdata.get(conf, 0.25)) return jsonify(results) if __name__ __main__: app.run(host0.0.0.0, port5000, threadedFalse)注意threadedFalse这个参数。有人说Flask默认单线程会卡并发但这里故意的底层一次只能处理一个CUDA推理如果你开启threadedTrue多个请求同时进来每个线程都抢显存和CUDA流反而更容易OOM和延迟尖刺。实测数据来看单线程加一个队列缓冲总吞吐量远高于多线程盲并发。模型加载用了一个ModelHub类把所有YOLO模型统一预载切换模型时也只是从字典里取。这样Spring Boot调用的时候可以动态传model_name参数方便线上做AB测试。启动时可以搞一个/healthz接口返回当前显存使用和模型状态Spring Boot的健康检查会定期来探活挂在GPU机器上了能第一时间发现。图像再强调一次OpenCV读的是BGRUltralytics推理内部会转RGB并做归一化但如果你自己写预处理再传入模型必须把通道顺序确认好。我曾经为了图省事把base64解码后直接扔进模型检测结果忽好忽坏查了两小时才发现颜色通道反了。生产环境别用Flask自带开发服务器跑真实流量我用gunicorn起单worker因为是GPU推理不需要也不建议多worker。多worker意味着每个进程都复制一份模型到显存显存直接爆掉。5. Spring Boot与Vue的联动数据库、报警推送、M3U8视频流实战业务端这一块Spring Boot负责的事情非常多摄像头的增删改查、组织结构管理、告警记录查询、用户权限、大模型调用的鉴权转发。别再纠结MyBatis还是Spring Data JPA了我在这个项目里直接用JPA因为大部分表关系简单JPA的JpaRepository天生支持方法名推导查询。比如public interface AlarmRecordRepository extends JpaRepositoryAlarmRecord, Long { ListAlarmRecord findByTypeAndStatusOrderByCreatedAtDesc(String type, int status); long countByCreatedAtAfter(LocalDateTime time); }这一段代码就能实现“查最近一小时烟雾报警数量”不需要手写XML。不过JPA做复杂多表统计确实麻烦这种场景我直接上Query写JPQL或者走本地SQL不硬扛。5.1 SSO与WebSocket报警推送值班大屏最核心的体验是告警实时性。报警不能靠前端轮询必须用WebSocket或SSE推。Spring Boot里用WebSocketFront端的Vue用原生WebSocket封装一下检测服务返回的标注框、置信度、截图地址都会通过消息推送给当前在线的值班员。我们的推送频率做了限流同一个摄像头、同一类告警五秒内只推一次。因为森林场景下火焰可能连续几十帧都被检测到如果你每一帧都推值班员会疯掉。5.2 M3U8视频接入与Vue播放业务上监控摄像头很多是RTSP推流浏览器不能直接播放RTSP所以我们在边缘侧把RTSP转成HLS和M3U8切片。Vue这边用video.js给它一个M3U8地址就能直接播放。流程是摄像头RTSP - 流媒体服务转HLS - Spring Boot通过/hls/{cameraId}/index.m3u8代理访问 - Vue通过video.js拉流显示。这中间最大的坑是跨域。Vue开发服务器走代理没问题但打包上线后如果M3U8地址指向另一个端口video.js往往拿不到TS分片。我最后在Spring Boot里做了一个静态资源映射把所有HLS切片文件统一走同一个域名彻底避开浏览器的CORS限制。Vue播放器配置上新版本video.js内置了HTTP Streaming支持不需要再额外引入Flash相关的HLS插件网上那些老教程可以跳过了。5.3 Vue打包后布局异常的排查热搜里有人问“vue 打包后 布局异常”我也踩过。根源基本是两种情况一是静态资源路径不对vite.config里的base没设成./上线后js和css加载404二是前端路由用了history模式nginx没配fallback用户一刷新页面就404看起来像布局崩了。前者修base路径后者在nginx的location /里加try_files $uri $uri/ /index.html;。这两个问题几乎能覆盖95%的Vue打包后异常。6. 接入DeepSeek和千问大模型从“能识别”到“会研判”很多人听到“检测系统接大模型”第一反应是让DeepSeek直接看图识别火焰。这里我必须泼一盆冷水DeepSeek这类文本模型不是视觉模型你给它一张图让它判断有没有火它根本看不见图。所以大模型在这个项目里的正确定位是“研判大脑”而不是“眼睛”。眼睛仍然是YOLO。6.1 大模型到底负责什么检测系统输出了一堆“置信度0.87的烟雾框”值班员看着它心里想的却是“这里要不要通知护林员火势扩散到哪个方向危险级别怎么定”这些推理判断YOLO做不了传统代码写规则又太僵硬。于是我把检测结果、摄像头编号、最近天气信息、历史报警频率都拼成一段文本传给DeepSeek或千问让模型输出结构化的火情研判简报。实际提示词模板大概是这样的你是一名森林防火值班研判员。以下是一段时间内的AI视觉检测结果 {detection_json} 当前天气{weather} 过去24小时同类报警次数{history_count} 请给出 1. 火情风险等级低/中/高及理由 2. 可能的发展趋势 3. 建议的处置措施 4. 对检测结果可信度的观察如置信度是否接近阈值这个模板的价值在于它把大模型的长处归纳推理、语言组织和短处视觉输入做了一次隔离。DeepSeek和千问都可以通过OpenAI兼容的接口调用只是模型名和API地址不同。我在Spring Boot里封装了一个LLMClient接口分别实现DeepSeekClient和QwenClient通过配置文件切换。这样做有一个额外好处如果某一天云端API不可用可以自动降级成预置模板不会让整个系统瘫痪。6.2 流式输出与业务融合值班员在界面上点击“生成研判”前端应该看到文字一个一个蹦出来而不是等待十几秒后一次性出现。所以前端通过SSE接收大模型的流式响应。Spring Boot里用SseEmitter把客户端请求转发给大模型接口再逐步推给浏览器。收到完整简报后系统会把这份简报关联到对应的告警记录里存入数据库后续可以按时间线和摄像头维度追溯。接入过程中最容易被忽略的是提示词注入和安全控制。因为大模型接收的检测结果里带有摄像头名称等文本这些文本可能被异常报文改写成恶意指令。所以我对传到提示词里的所有字段做了严格白名单只允许置信度、类别、坐标和少量枚举值把风险降到最低。6.3 千问视觉模型什么时候用如果确实希望“看图说话”千问有一系列多模态视觉模型可以直接传入base64图片。我把它的用途限定在“告警复核”上YOLO产生火焰告警后把抓拍的截图发给千问视觉模型让它描述画面里的物体和颜色分布帮值班员判断这是一团真火还是红色卡车。这种多级复核能显著降低误报但代价是每次调用有额外延迟和费用不适合对所有帧使用。7. 环境部署与高频踩坑从AMD显卡到Spring Boot 4.x兼容这个项目能顺利跑起来背后离不开一堆环境问题。我把最痛苦的几个问题整理出来都是被热搜反复点名的。7.1 AMD显卡能跑YOLOv8/v10/v11/v12/26吗能跑但要分清楚是训练还是推理。AMD显卡跑训练首选ROCm版的PyTorch而且要看显卡型号的官方支持列表。我用一张AMD卡在Ubuntu下折腾了三天环境变量HSA_OVERRIDE_GFX_VERSION反复试训练总算能跑起来但速度比同价位N卡慢不少。如果你的目标只是推理建议换个思路把Ultralytics模型导出成ONNX然后走ONNX Runtime的DirectML或ROCm执行器部署稳定性和性能都好很多。YOLO环境配置经典坑是版本错位。torch、torchvision、ultralytics三个包必须对应盲目装最新版会导致torchvision::nms崩溃。建议创建一个独立conda环境pip install ultralytics会自动拉取匹配的版本不要手动单独装torch除非你知道自己在做什么。7.2 训练OOM和线程卡死训练时显存不足最有效的三板斧降低batch size、启用半精度、减小图片尺寸。如果8张图OOM就降到2张再不行就关掉Mosaic或把缓存数据集的worker数降低。train_loader的num_workers设大了会卡在数据加载阶段尤其是Windows下还会报DataLoader worker错误我一般设成0或者2最稳。7.3 Spring Boot 3.x/4.x的配置漂移Spring Boot升级到3.x后原来很多javax包名变成了jakarta如果你从旧项目迁移导入语句要整体替换。到了4.x自动配置类的注册方式又有改变从spring.factories转向META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。很多人在4.x里配数据库连接池时发现DataSourceAutoConfiguration失效就是这个原因。如果只是做业务系统我目前的建议是老老实实留在Spring Boot 3.x稳定版没必要追新版本生产环境求稳。8. 最后说点项目之外的经验这套系统跑起来之后我最深的体会是单点模型指标再好如果没有完整的工程链路在森林防火这个场景下也是白搭。单纯一个YOLOv8检测器哪怕mAP很高到现场也会被夕阳、红色卡车、林间水雾反复打脸。但当你把连续帧确认、天气信息、历史报警频率和大模型研判都加进来以后整个系统的可用性完全不一样。模型承担“感知”Spring Boot承担“记忆”大模型承担“思考”Vue承担“表达”各司其职才是一个能被值班员信赖的AI系统。如果你接下来也想做类似项目我的建议是先花一周时间把数据标注规范定下来比什么都值。模型版本选型不要盲目追新把v8和v11训练好、部署稳定已经能解决绝大多数问题。大模型接入放在最后一步别在一开始就被“AI研判”这个概念带偏摄像头都还没接上就先研究提示词那是本末倒置。我在这套系统的后续规划里准备把边缘端部署换成更轻量的INT8模型再跑在Jetson设备上这样摄像头离得再远也能在场站内部完成初步检测。这条路还会踩很多坑但至少架构和业务闭环已经立住了后面要做的只是换引擎、调参数的事。
返回列表