YOLO系列+SpringBoot+大模型搭建密集行人检测系统实战指南

发布时间:2026/9/8 23:07:58
YOLO系列+SpringBoot+大模型搭建密集行人检测系统实战指南 从标题到落地我如何用YOLO系列SpringBoot大模型搭了一套密集行人检测系统如果你最近在刷目标检测方向的实战项目大概率会看到“YOLOv8/v10/v11/v12 SpringBoot 千问/DeepSeek 前后端分离”这种组合。这套技术栈几乎把当前最热的词都占齐了YOLO做检测、SpringBoot做后端服务、千问和DeepSeek做智能分析、Vue做前端界面最后还要配上YOLO格式的数据集。我前阵子正好按这个思路完整做了一套密集行人检测系统从算法训练到后端封装再到前端联调和大模型接入踩了不少坑也整理出一些可以直接抄作业的经验。这篇博客就把整个项目的架构思路、关键代码、训练细节和排查记录完整分享出来给正在做类似毕设或工程项目的朋友一个参考。先说这套系统到底能干什么。输入一段监控视频或一张密集人群图片前端页面上传后后端调用训练好的YOLO模型逐帧检测行人返回每个目标的坐标框、置信度、类别前端在视频画面上实时绘制检测框并统计人数。检测结果同步送入千问和DeepSeek接口自动生成一段自然语言分析当前场景大约多少人、密度等级是高是低、有没有局部拥挤风险、建议采取什么疏导措施。整个链路通过SpringBoot统一编排前端Vue单独部署前后端通过HTTPWebSocket通信属于典型的前后端分离架构。我为什么会选这套方案核心原因是它能覆盖一个完整AI应用的全部环节数据集处理、模型训练、服务化部署、Web交互、大模型集成。无论你是做毕业设计还是想入门AI工程化这套链路都能让你把“算法”和“工程”串起来而不是只停留在跑通一个notebook的层面。1. 项目整体设计与核心思路拆解1.1 这套系统解决的是什么问题密集行人检测不是普通的目标检测。日常我们做YOLO训练检测对象可能是车、猫、狗目标数量少、相互遮挡不严重。但密集行人场景完全不同一张图里可能出现几十甚至上百个人人体之间互相重叠、遮挡、尺度变化极大远处的行人可能只有十几个像素近处的却能占满半个画面。这种场景对模型的召回率、NMS策略、锚框设计都提出了更高要求。之前CrowdHuman数据集统计过一张密集人群图片中平均有23个人最多能到200多人。用普通检测模型直接去跑常见问题是漏检率偏高、遮挡目标的置信度被NMS压掉、小目标几乎完全丢失。所以这个项目里选模型、调参数、做后处理的思路都围绕“密集”两个字展开。1.2 技术选型为什么是YOLO系列而不是其他检测模型目标检测领域可选方案很多两阶段的Faster R-CNN精度高但速度慢实时性上完全撑不住视频流场景DETR系列效果不错但训练收敛慢、部署复杂真正适合做实时密集行人检测的还是YOLO这一条线。YOLOv8是目前存量项目最多的版本Ultralytics官方维护文档全、生态好训练和部署资料随处可查YOLOv10最大的改动是去掉了NMS推理时省去后处理耗时YOLOv11在C3K2、C2PSA等模块上做了优化分类和检测能力都有提升YOLOv12则是2025年新发布的版本引入了区域注意力机制在大目标和小目标兼顾上做了不少文章。我在项目里没有只锁定一个版本而是把四个模型都训练了同一份数据集用相同硬件环境做了横向对比。这样做的好处是论文或项目汇报时能有真实的对比数据支撑而不是只写“本系统采用YOLOv8”。最终部署时根据实测结果选择最优模型剩余模型可以作为消融实验数据。1.3 整体架构设计算法、后端、前端如何协同整个系统分成三层算法层、服务层、展示层。算法层负责模型训练和推理输出检测结果服务层用SpringBoot把模型封装成HTTP接口和WebSocket推送通道展示层用Vue3 ECharts构建上传、预览、实时轮询、分析报告展示的界面。三层之间通过标准接口通信。前端上传视频文件到SpringBootSpringBoot后台启动异步任务逐帧调用Python推理服务或通过Java调用ONNX模型每处理完一帧就把检测结果推送到前端。视频播放完成后SpringBoot汇总所有帧的检测数据调用千问和DeepSeek生成文本分析报告再返回给前端展示。选择前后端分离而不是传统单体架构主要考虑两点一是检测服务需要长连接实时推送数据分离架构下后端WebSocket服务和前端页面各自独立部署链路更清晰二是后续如果要换前端框架或增加管理端、大屏展示后端接口可以原样复用不需要改动检测逻辑。实际开发中前端跑在8080端口后端跑在9090端口通过Nginx配置反向代理解决跨域问题。2. YOLO训练与密集场景检测优化2.1 数据准备从原始标注到YOLO格式YOLO训练数据是核心中的核心。模型效果的上限由数据决定这句话做密集行人检测时体会尤其深。如果数据集里密集样本太少模型学不到遮挡特征检测效果必然拉胯。我使用的公开数据集以CrowdHuman为主挑选了约7600张密集场景图片同时补充了VisDrone数据集中包含行人密集的部分图片以及MOT17检测序列中的行人帧。之所以选这三个数据集是因为CrowdHuman的标注专门针对密集人体遮挡场景每张图平均超过20个行人头部和身体框都有标注VisDrone大量是高空视角下的极小目标能提升模型对远处小行人的召回MOT17补充了监控视频真实画面的多样性和清晰度。数据集中行人框的标注格式原始数据往往是JSON或XML需要统一转换成YOLO的txt格式。YOLO格式要求每行一个目标class_id x_center y_center width height坐标值均为归一化比例即绝对像素坐标除以图片宽高。转换脚本的核心思路是先读取原始标注提取每个行人框的左上角和右下角坐标再统一转换格式写入txt文件。转换完成后一定要做可视化检查把标注框画回原图肉眼扫一遍重点看是否有坐标越界、长宽比异常、类别错标。项目里还做了数据增强包括mosaic、随机翻转、色域变换、随机缩放并将训练集随机裁剪到640x640。数据增强让模型在同样数据量下见过更多变体缓解密集场景下目标重叠导致的学习困难。2.2 模型训练参数的选择与Loss曲线分析训练主要基于Ultralytics框架完成。YOLOv8到YOLOv12都支持统一的训练入口切换模型版本只需修改模型配置文件名。我的训练命令大致如下yolo train datacrowdhuman.yaml modelyolov8s.pt epochs150 imgsz640 batch16 device0batch size的选择取决于显卡显存。我用的是单张NVIDIA RTX 308010GB显存实测batch16可以稳定跑完YOLOv8s训练换成YOLOv10n或YOLOv11n时batch可以开到32。训练过程中的核心观察指标是val_box_loss和mAP50曲线。前30个epoch损失快速下降mAP50从0.2左右一路升到0.580个epoch之后曲线进入平台期loss下降变得非常缓慢。此时增大epoch数量收益有限反而有轻微过拟合风险。我在150个epoch后早停最终mAP50达到0.832mAP50-95为0.574。密集行人场景提升最大的一个技巧是调低置信度阈值。默认conf0.25适合常规目标但在密集场景中大量遮挡目标模型本来就给不出高置信度直接砍到0.25会漏掉很多真实行人。我最终推理时设置为conf0.1、iou0.45。代价是会产生少量误检但密集场景宁可多检几个框也不希望漏掉真实行人。这个取舍思路同样适用于流量统计类应用。下面是四个版本模型在测试集上的对比结果模型输入尺寸mAP50mAP50-95单帧推理耗时(ms)模型大小YOLOv8s6400.8260.5588.221.5MBYOLOv10s6400.8130.5397.420.1MBYOLOv11s6400.8380.5718.018.8MBYOLOv12n6400.8210.5457.015.4MB最终部署选用了YOLOv11smAP最高且模型最小。YOLOv10s的优势在推理速度但精度略低适合对实时性要求极高的场景。2.3 密集场景反直觉调参NMS阈值、锚框与TTA密集检测中有几个参数需要反常规调整。第一个是NMS的IoU阈值。默认iou0.45是为了把高度重叠的检测框合并但密集场景中两个行人靠得极近真实框的IoU可能本身就大于0.45直接合并就会造成漏检。把iou阈值降低到0.4可以保留更多互相靠近的目标框减少了把“两个人”并成“一个人”的概率。注意这个值不能无限低调太低会导致同一个目标产生大量重复框。第二个是推理时的TTATest-Time Augmentation。TTA通过对原图做翻转、多尺度缩放后分别推理再融合结果能提升2到4个点的mAP但推理耗时也会成倍增加。视频流检测场景一般不用离线分析单张图片时可以开起来获得最好效果。第三个是图片压缩策略。YOLO默认会把超过640x640的图片等比缩放密集场景中远处行人缩到640后可能只剩8x8像素直接丢失目标。后来我在预处理阶段对超过1280x1920的大图做切片推理整图按滑窗切成多个640x640的patch分别检测再把结果映射回原图坐标。这个操作下来VisDrone高空视角数据的小目标召回率提升了约11%。2.4 训练完的模型如何导出和部署训练完成后需要把模型导出成适合部署的格式。开发阶段直接用PyTorch权重推理最方便但进入SpringBoot工程集成时我建议导出为ONNX格式yolo export modelbest.pt formatonnx opset12 simplifyTrueONNX格式的好处是可以脱离PyTorch环境运行由Java直接通过ONNX Runtime加载推理部署链路更干净。Java端加载ONNX代码的核心逻辑是先读取模型输入节点的shape预处理图片为NCHW格式的float数组执行session.run()后将输出张量解析为检测框、类别、置信度三元组再做一次NMS后处理。如果追求性能可以进一步导出TensorRT engine格式但需要匹配特定显卡驱动和CUDA版本一般毕设和个人项目中ONNX Runtime的CPU/GPU推理已经足够。我实测用ONNX Runtime推理YOLOv11s单帧耗时约12ms完全满足25FPS的实时分析需求。3. SpringBoot后端架构与实时推送通道实现3.1 为什么选SpringBoot作为服务端目标检测模型的推理能力本身和SpringBoot没有直接关系但一个完整的系统必须有服务端来编排任务、管理请求、推送数据、对接大模型。选择SpringBoot的原因很实际Java生态成熟Maven管依赖极其省心内置Tomcat免去单独部署集成WebSocket、HTTP客户端等能力都是开箱即用。优秀组合是SpringBoot作为主服务负责接收前端请求、管理任务队列、调用Python推理进程或ONNX Runtime推理接口、把结果推送到前端。如果采用Python推理SpringBoot通过HTTP请求或子进程方式调用Python服务如果直接用Java推理ONNX就没有跨语言通信开销部署更简单。3.2 后端模块划分与核心接口设计我把后端拆成几个明确模块detection-controller接收视频上传、图片检测、分析报告请求detection-service业务逻辑编排调用推理组件inference-engine封装ONNX Runtime或外部Python服务调用websocket-server实时推送检测帧结果到前端analysis-service千问和DeepSeek对接生成智能分析报告configCORS配置、线程池配置、WebSocket配置核心HTTP接口设计如下接口方法功能说明/api/uploadPOST上传视频或图片返回任务ID/api/detect/imagePOST单张图片检测返回JSON结果/api/analysis/{taskId}GET获取大模型分析报告/api/tasks/{taskId}/progressGET查询视频任务进度/ws/detect-resultWebSocket服务端实时推送逐帧检测结果3.3 视频流检测异步任务 WebSocket实时推送视频检测是系统里最复杂的链路。视频文件上传后不能在前端同步等待结果因为一个几秒的短视频可能在GPU上跑几十秒甚至几分钟处理。解决方案是异步任务池 WebSocket推送。后端收到视频文件后保存到本地并生成UUID任务ID立即返回给前端。然后通过线程池异步处理视频帧Async(detectExecutor) public void processVideo(String taskId, Path videoPath) { ListFrameResult frameResults new ArrayList(); try (VideoCapture capture new VideoCapture(videoPath.toString())) { Mat frame new Mat(); int frameIndex 0; while (capture.read(frame)) { ListDetection detections inferenceEngine.detect(frame); FrameResult result new FrameResult(frameIndex, detections); frameResults.add(result); // 通过WebSocket实时推送当前帧结果 wsTemplate.convertAndSend(/topic/detect/ taskId, result); frameIndex; } } // 视频处理完成后汇总结果生成智能分析报告 String report analysisService.generateAnalysis(taskId, frameResults); wsTemplate.convertAndSend(/topic/analysis/ taskId, report); }WebSocket配置是SpringBoot的原生能力定义一个Handler或使用STOMP协议都行。我项目里用的是Spring WebSocket的STOMP方式前端通过SockJS连接接口路径是/ws端点订阅/detect/{taskId}频道的消息即可展示检测框。批量检测时也可以前端自己按时间戳轮询后端但实时性远不如WebSocket视频检测场景强烈建议用WebSocket。线程池参数也值得注意。我配置了核心线程数8、最大线程数16、队列容量2000。如果并发视频分析任务过多不能无限制创建线程否则内存和显存都会被打爆链接层直接熔断。3.4 Java调Python还是Java直接推理这是一个非常现实的工程选择我两种方式都试过。经验是原型阶段用Java调Python模块最方便因为Python端可以用现成的ultralytics库加载权重直接推理不需要额外扣格式生产或毕设演示阶段建议还是走Java ONNX Runtime。跨语言调用在并发请求频繁时会成为性能瓶颈HTTP请求体的图片序列化、反序列化会白白占用大量CPU时间。Java直接推理则把图片预处理、张量计算、后处理都在一个进程内完成链路短、延迟低。如果是Java调用Python子进程注意要在SpringBoot的配置文件中可配Python解释器和推理脚本路径切换环境时不用改代码。子进程的启动耗时很高后续仍然建议维护一个Python服务常驻用HTTP接口通信不要每次检测都去fork子进程。4. 前端交互界面与前后端分离联调实践4.1 Vue3 ECharts Canvas检测框渲染方案前端用的Vue3组合式APIUI库选了Element Plus。检测结果展示是系统的门面设计上需要同时展示视频画面、检测框、实时统计数据和分析报告。检测框的绘制我用了Canvas覆盖层而不是直接用DOM元素。原因很简单一帧可能有几十上百个检测框如果每个框都创建一个div绝对定位DOM节点数量暴增页面会明显卡顿。Canvas只需要一个画布在requestAnimationFrame回调中逐帧清除重绘性能非常稳定。视频播放时把视频帧同步绘制到Canvas上检测框跟着叠加画面和框保持严格对齐。统计面板用ECharts实时绘制人数变化折线图每收到一条WebSocket推送就向折线图追加一个数据点展示当前帧人数、平均置信度、累计峰值人数。ECharts的散点图也可以用来展示画面中人群分布热力图密度高低一眼就能看出来。4.2 跨域、文件上传与WebSocket连接配置前后端分离必须处理跨域问题。我后端在SpringBoot中全局配置了CORS允许8080端口的前端地址访问9090端口的后端接口。但需要注意WebSocket连接不走普通HTTP的CORS机制需要在注册STOMP端点时额外设置setAllowedOrigins否则浏览器控制台会疯狂报错。视频上传时前端使用FormData提交并配置了onprogress回调做上传进度条。这里有个容易被忽略的坑Nginx默认client_max_body_size只有1MB上传几十MB的测试视频直接返回413。需要在Nginx配置或后端配置中调大体积限制我设置的512MB否则前端上传大视频必失败。WebSocket前端连接示例如下const socket new SockJS(http://localhost:9090/ws); const stompClient Stomp.over(socket); stompClient.connect({}, (frame) { stompClient.subscribe(/topic/detect/ taskId, (message) { const frameData JSON.parse(message.body); drawDetections(frameData.detections); updateChart(frameData.frameIndex, frameData.detections.length); }); });4.3 从视频上传到分析报告展示的完整交互流程前端交互流程这样走用户选择视频文件点击上传后端返回taskId点击开始分析后进入分析页面视频逐帧播放Canvas叠加检测框ECharts统计曲线实时跳动视频处理完毕后页面右侧分析报告区域出现千问和DeepSeek生成的文字报告内容包括总人数统计、平均密度、拥挤时段分析、风险预警提示。如果只是图片检测交互更简单上传图片后直接POST到检测接口拿到JSON结果绘制检测框即可。视频流和图片检测的接口、页面路由分开设计前端路由/users/video和/users/image互不干扰。4.4 部署时的前端构建与Nginx静态资源托管前端开发完成后执行npm run build生成dist目录里面是纯静态文件。由Nginx托管这些静态文件并将 /api 路径代理到后端9090端口server { listen 8080; location / { root /data/dist; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:9090; proxy_set_header Host $host; } location /ws { proxy_pass http://127.0.0.1:9090; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; } }这段配置同时解决了前端路由history模式刷新404问题、API跨域转发、WebSocket升级握手三个问题。需要特别注意的是WebSocket的Upgrade请求必须带上Upgrade和Connection头否则无法建立长连接。5. 千问和DeepSeek接入将检测数据变成智能分析报告5.1 大模型在系统里的真正价值是什么很多人在项目里加大模型只是简单地把检测结果拼成一句话“检测到10个行人。”这样做意义不大。千问和DeepSeek真正的价值在于对检测结果做更深度的语义理解生成人话式的决策建议。比如模型检测出画面里左侧区域有密集人群且长时间滞留大模型可以结合时间序列数据给出判断“左侧通道区域在14:32到14:40之间出现持续性高密度聚集建议安排工作人员引导分流避免因通道阻塞引发踩踏风险。”这种输出才是有应用价值的智能分析。5.2 千问API调用与结构化Prompt设计千问的接口兼容OpenAI格式可以通过HTTP调用或使用官方SDK。我用的是HTTP调用方式构造一个包含system和user消息的请求体通过SpringBoot的RestTemplate发送POST请求到千问的接口地址带上API Key和消息内容解析返回的JSON即可。这里核心难点在于prompt模板设计。常规问法“这段视频有多少人”得到的回答可能完全是废话。我把检测得到的结构化JSON数据喂给大模型前会先做数据聚合。例如每帧检测结果按半分钟窗口聚合后统计出该时段的峰值人数、平均人数、人群聚集区域、滞留时长。然后把聚合结果作为上下文传给大模型。Prompt模板结构如下系统角色设定你是智慧安防系统分析员请基于检测数据给出客观分析。数据输入给出多时间窗口的行人数量、坐标分布、置信度概况。分析任务要求从以下三个维度输出结果——整体态势概览、密度与风险等级评估、具体处置建议。通过结构化Prompt大模型返回的分析质量明显提升不再是“今天有10个人”式流水账而是类似于专业报告中“分时段、分区域、分等级”的叙述。5.3 DeepSeek接入与双模型交叉验证思路千问负责实时分析和生成文字报告DeepSeek的接入作为双模型验证和补充。合理的设计是让两个模型分别回答同一个分析任务然后在后端做文本相似度或关键指标一致性校验。如果两边对密度等级的判断例如一边是“中等密度”另一边是“高密度”不一致系统会标记该数据段为“需要复核”提示调用方注意。双模型交叉校验在项目汇报时非常加分它说明系统不是简单调接口而是有一定的可靠性设计。同时两个模型都支持流式返回长文本报告可以先展示第一段后续内容逐步追加前端交互体验更好。流式场景下WebSocket同样可以发挥作用或者使用SSEServer-Sent Events技术向前端单向推送生成中的文本。5.4 大模型调用的延迟控制和降级兜底大模型接口的响应延迟往往在1到3秒之间视频流场景如果有双模型同时调用延迟叠加后体验会非常差。策略是异步化视频检测完成后后端立即推送“检测完成”消息大模型分析作为独立异步任务在后台运行前端先展示检测统计和轨迹图分析报告什么时候生成完毕再推送过来。用户不用干等系统整体节奏也更顺畅。降级兜底也要做准备。API Key额度用尽、网络波动、接口服务繁忙时系统要能返回一个预设模板的简要分析结果而不是直接报错。我在配置文件中维护了一套兜底文案当大模型接口异常时自动替换保证前端界面永远有内容展示。这个设计让我避免过几次演示时接口罢工的尴尬场面。6. 常见问题与排查技巧实录6.1 YOLO训练与推理阶段的高频错误训练时最常见的问题是显存溢出CUDA out of memory。解决思路就是降batch size或者使用梯度累积或者在代码里设置torch.cuda.empty_cache()。我训练时也遇到过数据集标签格式错误导致loss直接为NaN的情况排查方式是打印某一条训练样本的标签内容和图片尺寸肉眼检查是否出现了超过图片边界的框坐标。推理阶段的坑更多。用Java加载ONNX模型时报维度错误多半是预处理时通道顺序没搞对。YOLO训练时输入是RGB顺序但OpenCV默认读入的是BGR必须做cvtColor转换再归一化。还有归一化参数YOLO输入要求像素值除以255归一到0-1区间漏掉这一步会导致大量目标检测不到或置信度极低。6.2 SpringBoot集成检测时的性能瓶颈点我实际运行中遇到的性能瓶颈不是模型本身而是图片编码JSON传输和线程池配置。检测结果每个框包含x、y、w、h、confidence、class_id六个字段一帧有100个目标时序列化后也有上万字节。视频30FPS的情况下前端收到的JSON数据量会非常大。解决方案是服务端只在关键帧推送完整检测框数据中间帧只推送人数统计前端用固定时间间隔刷新检测框。实践下来在保持流畅性的同时能大幅降低WebSocket的消息体。线程池参数同样值得反复调试。核心线程数设置过高会导致任务排队设置过低则CPU利用率不足。我最终调整为核心4线程最大12线程队列容量1000。过大的线程池会让Java应用频繁进行线程切换不是越大越快这一点在AI任务场景中尤其明显。6.3 前端联调时的接口对接细节前端和后端联调最常遇到的是字段名不一致。后端返回的字段是camelCase前端拿到后忘记做映射导致页面一片空白。解决方式是前后端约好统一的API契约把检测结果的data class单独放在一个模块中共享前后端都基于它生成代码而不是靠人手对齐字段。另一个高频问题则是WebSocket在Nginx代理下连不上通常就是缺少Upgrade请求头的转发配置。6.4 大模型接口稳定性和成本问题大模型的API调用不是免费的毕设级项目的免费额度有限密集视频一次分析很可能就要发送数十次API请求。成本控制的核心思路是将检测结果先本地聚合压缩成极简的数据摘要再发送。比如1000帧视频不发送1000条检测明细而是按时间窗口聚合成30条统计摘要token消耗直接降一个数量级。对本项目而言合理的token预算应控制在每次分析2000到3000 token以内。方法就是改变prompt设计让大模型只回答“分析结论”而不是“复述数据”。7. 写在最后这套系统后续还能怎么扩展整个系统从最初的单一YOLOv8检测demo逐步迭代成了一条覆盖数据、算法、服务、前端、大模型的完整链路。做这个项目最有价值的体会是AI应用开发的核心能力不只是训练模型或调参而是把模型嵌入到实际业务链路里让用户能低成本地使用它。技术选型上YOLO系列成熟稳定SpringBoot生态完整前后端分离架构清晰大模型作为分析增强层又赋予了传统检测系统语义理解能力——这套组合无论用来做毕设还是做原型系统都能产出足够完整和可信赖的方案。如果你正在复现类似项目建议按这个顺序推进先跑通单张图片检测链路再接入视频流WebSocket推送然后封装大模型分析最后再打磨前端交互细节。顺序反了容易陷入“前端调了一周后端还是mock数据”的尴尬状态。另外数据集质量永远值得花最多时间打磨模型换版本带来的提升可能只有两三个点但数据清洗和增强带来的提升可以超过十个百分点。希望这篇整理能让你少踩几个坑如果你也在折腾密集行人检测或者有其他更好的方案思路欢迎一起交流。

相关新闻