
开头无人机 AI 视觉识别已经不是什么新鲜概念了但真把一套 YOLOv12 模型跑在河道巡检这种实际业务场景里踩过的坑和趟过的路还是比较有代表性。这个项目做的就是“智慧河道巡检基于 YOLOv12 的大疆无人机河面塑料垃圾检测”核心目标很明确——让无人机飞出去自动识别河面上漂浮的塑料瓶、泡沫、塑料袋这类水面垃圾实时回传位置并生成巡检报告代替原来靠人肉眼盯着屏幕或者定期人工巡河的低效方式。这套方案适合谁如果你正在做智慧水利、环保监测、河道治理相关的信息化项目或者手里正好有一台大疆无人机、想在视觉识别方向快速产出可落地成果这篇复盘值得你照着走一遍。我会把从数据采集、标注、训练到部署上机的完整链路全部拆开讲包括每个环节为什么这么选、参数怎么定、哪些地方极易翻车基本是按“能直接复现”的标准来写。先说结论模型本身只是整个链路的一环真正影响效果的是数据质量、部署硬件的匹配程度以及巡检飞行的航线设计。单纯在服务器上把 mAP 刷到 0.9 是没有意义的飞出去一测全崩的情况我见过太多。下面开始正题。1. 项目整体思路与方案选型1.1 为什么是“无人机 YOLOv12”而不是其他组合做河道漂浮物检测其实技术选型上有几条路径传统图像处理、语义分割模型、通用目标检测模型。传统图像处理对光照和水面纹理极其敏感稍微有点波纹就会产生大量误检我最早用颜色阈值分割试过一轮晴天顺光还行阴天或者水面反光一出来基本全废。语义分割模型能给出精细的轮廓但标注成本高、推理速度慢对于河道巡检这种需要快速扫描大面积水面的场景性价比不高。剩下的就是目标检测路线也是当前平衡速度和精度的最优解。YOLO 系列在工业界普及程度最高从 v5 到 v8 到 v11每一代都在工程易用性上做加法。这次选择 YOLOv12核心原因有三点一是它引入了 N/A 注意力机制N/A 代表一种新的注意力结构简单理解就是把注意力计算拆解为区域级别的聚合而不是逐点计算显著降低显存占用在大尺度输入下仍然能保持较高帧率二是官方权重基于大规模数据预训练迁移到水面垃圾这类垂直场景时收敛速度明显快于从零训练三是 ultralytics 框架直接支持 YOLOv12 的导出和部署省去了大量模型转换的体力活。这里有个容易被忽略的点无人机拍到的河面画面绝大多数目标都是小目标有时候一个塑料瓶在 4K 画面里只占十几个像素。YOLOv12 的 N/A 注意力配合可变形卷积的局部建模能力对小目标召回率比前代模型有提升。但注意这只是“相对提升”小目标问题从来不是单靠模型结构能解决的后面标注策略和推理裁剪才是大头。1.2 整体架构从采集到告警的完整闭环这个项目不是只做一个模型就完事而是为了给河道管理部门提供一套可用的巡检工具。系统分成几个模块我直接按流程列一下无人机采集端大疆机型按固定航线飞行云台俯仰角、航高、重叠率按采集规范设定。数据标注端使用图像标注工具对原始视频抽帧图进行框选标注统一输出 COCO 格式数据集。模型训练端基于 YOLOv12在 GPU 服务器上训练检测模型通过验证集指标筛选最优权重。部署推理端将模型导出为 TensorRT 引擎部署在机载计算模组比如 Jetson Orin接入无人机图像数据流实时输出检测框。定位与上报结合无人机的经纬度、姿态角、云台角度和检测框在画面中的位置推算出垃圾目标的坐标形成巡检告警记录。这套架构的核心思想是“端侧实时检测 坐标换算 后台管理”而不是把全部视频流传回服务器再检测那样延迟高、对网络依赖强。实测下来端侧推理延时可控制在 50ms 量级完全满足飞行过程中的实时告警需求。1.3 方案选型对比YOLOv12 与 YOLOv8/YOLOv11 的取舍很多人问我为什么不直接用更成熟的 YOLOv8。说实话YOLOv8 的社区资料最多、坑最少如果项目周期只有两周、且数据量不大选 v8 完全没问题。但这次项目有持续迭代和部署到多台设备的需求我对比了三代模型的实测表现模型输入尺寸mAP50自建验证集推理耗时Jetson OrinTensorRT FP16显存占用说明YOLOv8n640x6400.7812ms1.1GB小目标召回偏弱YOLOv11n640x6400.8213ms1.2GB提升有限YOLOv12n640x6400.8615ms1.4GB小目标提升明显数据量是同一份训练超参保持基本一致YOLOv12n 在 mAP50 上的优势确实存在代价是推理耗时略高一些。但对于河道巡检这种不是极限竞速的场景15ms 和 12ms 的差异在飞行过程中完全感知不到。如果是对延迟极度敏感的场景再考虑剪枝蒸馏否则 v12 是更优解。提示选择模型不要只看精度跑分一定要在目标部署硬件上做实测。我之前就是只看服务器上 TensorRT 的 benchmark结果换到 Jetson 上发现某些算子不支持被迫重新导出浪费了两天时间。2. 数据采集无人机飞行方案与图像获取2.1 大疆机型选择与相机参数设置无人机平台选用的是大疆 Mavic 3E行业版它有几个特性非常适合河道巡检机械快门能有效减少高速飞行时的果冻效应多向避障让它能在桥洞、树冠等复杂环境里安全穿梭RTK 模块可以提供厘米级定位配合网络 RTK 服务这对后续坐标换算至关重要。预算有限的话 Mavic 3 Classic 也能用但定位精度差一些坐标换算出来的垃圾点会有偏差巡河面积大时误差会累积。相机参数是影响数据质量的头号因素建议按以下标准设置视频录制使用 4K/30fps、码率选择最高档照片拍摄使用 JPEGRAW 双格式便于后期处理快门速度保证在 1/1000s 以上避免螺旋桨振动和飞行位移造成拖影ISO 尽量压低控制在 100-400 之间防止水面高光溢出。云台俯仰角推荐设置在 -30 度到 -45 度之间这个角度既能看清水面目标又能保留部分岸线作为参照物方便后期标注和校验。我踩过的一个典型坑是云台角度设置成 -90 度垂直朝下拍摄。垂直视角虽然视野整齐但极度缺少空间参照标注员对着纯水面图像很难判断目标类型比如远处的水草和塑料袋在正射视角下极其相似标注一致性会大幅下降。改成斜视角后目标有了一定长宽形态特征标注质量明显提高。2.2 航线规划与采集时间窗口航线规划用大疆 Pilot 软件生成测区航线关键参数如下飞行高度建议 30-60 米太高了目标太小太低了覆盖效率差航线间距设置 70% 重叠率确保相邻航线的画面有足够重合方便后期拼接或补采飞行速度建议 6-8m/s超过 10m/s 后动态模糊明显增加航向尽量与河道走向平行减少无效飞行。采集时间窗口我只能说“宁缺毋滥”。最理想的条件是晴天的上午 9 点到 11 点、下午 3 点到 5 点这个时段太阳高度角适中水面反光相对可控。正午阳光垂直照射水面时高光区域会掩盖目标导致标注员看不清、模型学不到。阴天虽然光照均匀但目标对比度低模型训练出来的特征鲁棒性一般。我建议每个测区至少采集三个不同时间段的视频让数据覆盖顺光、侧光、逆光和多云条件。采集时还要注意风速。水面垃圾分布受风影响很大常常聚集在下风口和岸边回流区这些“重点区域”要单独增加采集架次。另外雨后的第一天往往是垃圾被冲刷进河道的高峰期这个时间窗特别适合采集正样本不要错过。2.3 原始素材的清洗与帧提取采集回来的视频不能直接拿去标注必须先清洗。我按以下优先级筛掉无用素材画面模糊的帧、被水花或飞鸟遮挡的帧、无人机自身浆影入画帧、纯岸线无人帧、严重过曝帧。清洗做得好不好直接影响标注阶段的有效工作量。一般来说清洗后能留下 40%-60% 的可用帧已经算不错了。帧提取直接用 OpenCV 脚本完成每 5 秒抽 1 帧这样既能保证画面独立性又不会产生太多近重复样本。抽帧分辨率保持原图比例不缩放。之前有人先把 4K 图缩到 1280 再标注结果训练时想用大图输入反而没有原始信息属于自己给自己挖坑。模型训练要不要用原图不是这里要考虑的标注数据保留全分辨率永远是正确选择。3. 数据集构建标注、清洗与增强策略3.1 类别定义与标注规范河面垃圾的种类五花八门但类别定义不能太碎。我最终定了 4 个类别PET 瓶塑料瓶、泡沫白色泡沫块、塑料袋、水生植物干扰项。之所以把水生植物单独作为一个类别是因为它在画面中和部分垃圾极度相似模型如果完全不认识它就会把水草误检成垃圾导致大量虚警。单独建类让模型学会区分“目标”和“易混淆干扰物”这是工程化落地非常实用的一招。标注规范上目标面积占整张图 5% 以上的框“必须标”被遮挡超过 50% 的只标可见部分多个粘连目标分别标框不使用大框套小框边界模糊时按视觉主体类别判定。所有图像统一用“图片名 类别名 坐标框”的格式记录。整个标注过程用到了两轮核对第一轮初标第二轮专门处理争议样本。标注工作量大概是每张图 2-30 个目标平均每张 8 个左右。整批数据集 8600 张图像其中带目标的正样本 6200 张纯背景负样本 2400 张。负样本很重要我在项目初期忽视了它结果模型在水面无垃圾但有大片波纹的场景疯狂误报加入负样本后误报率直线下降。3.2 数据增强策略与参数选择无人机航拍数据的增强不能乱来。常规目标检测增强里有很多操作对航拍场景不适用比如随机旋转 90 度因为飞行器姿态相对稳定目标在画面中不会出现倒置强行旋转会让模型学到错误的空间先验。我采用的增强策略是Mosaic拼接 HSV 扰动调整饱和度以模拟不同水色 缩放模拟不同飞行高度下的目标尺寸变化 平移模拟目标出现在画面不同位置。其中 Mosaic 的比例不要超过 0.6因为 Mosaic 生成的合成图会破坏真实水位线背景比例太高反而影响收敛。对于小目标比较多的数据集还有一个增强技巧值得尝试使用 2 倍率的“贴图复制”即把小目标从一张图上裁剪出来复制粘贴到同一张图的其他位置同时生成对应的标签。这个方法能有效增加小目标样本数量代价是如果原图目标密度本来就高会有些假样本的感觉。实测提升 mAP50 约 2 个百分点对小目标召回率提升更明显。3.3 训练集、验证集、测试集的划分逻辑划分数据集时我特别强调“按采集航次划分”而不是“按图像随机划分”。原因很简单同一航次下相邻帧高度相似如果随机分到训练集和验证集验证集指标虚高模型实际泛化能力被高估。按航次划分后验证集的图像与训练集来自不同时间、不同地理位置能更真实地反映模型面对新水面的表现。最终划分比例为训练 6800 张、验证 1100 张、测试 700 张。测试集完全独立只在全部模型训练完成后使用一次用于最终效果评估。这里再补充一个做基线测试的建议先用 YOLOv8n 在相同数据上跑一遍得到基线指标再换 YOLOv12 训练对比在同一口径下的提升幅度这样才公平。4. 模型训练全流程实战4.1 训练环境配置与依赖安装训练环境是单卡 NVIDIA RTX 409024GB 显存系统为 Ubuntu 22.04Python 3.10。依赖安装没什么特别关键在于 ultralytics 框架的版本要支持 YOLOv12这里直接 pull 最新的 ultralytics 包即可。我用的核心依赖如下pip install ultralytics pip install torch2.1.0 torchvision0.16.0 pip install opencv-python数据放在本地目录结构按 ultralytics 约定的格式组织images 目录放图像labels 目录放同名的 txt 标注文件YOLO 格式类别 中心点 x/y 宽高二者一一对应。为了统一图像尺寸我写了一个预处理脚本将图像最长边缩放到 1280 并等比缩放短边避免模型在大尺寸输入上爆显存。4.2 超参数选取与训练过程详解YOLOv12 训练的超参数和之前 YOLO 系基本版本一致但有几个关键项需要针对航拍小目标场景做调整img_size输入尺寸设为 1280而非默认的 640。航拍小目标密集加大输入分辨率是召回率提升的最直接手段代价是训练和推理耗时增加。实测 1280 相比 640 的 mAP50 提升约 8 个百分点。batch_size24G 显存跑 YOLOv12n 配 1280 输入batch 设为 8 比较稳。batch 过大容易显存溢出过小则批次归一化不稳定。epochs300 个 epoch配合早停机制patience 设为 40。workers数据加载线程数设为 8避免 CPU 成为瓶颈。lr初始学习率 0.01配合 cosine 衰减策略warmup 前 3 个 epoch 线性上升至设定值。mosaic设 0.5hsv_h、hsv_s、hsv_v 分别设 0.015、0.5、0.4轻微色彩扰动比大幅扰动更有利于保持真实水色一致性。训练过程中需要盯住两个曲线训练损失下降曲线的抖动程度以及验证集上 mAP50 和 mAP50-95 的变化趋势。正常情况是前期 mAP 快速上升中后期进入平台期这时不要急着加大学习率去冲指标而是保存最优权重ultralytics 会自动保存 best.pt 和 last.pt。我这次训练到第 180 个 epoch 时 mAP50 达到 0.86再往上提升很有限见好就收防止过拟合。4.3 模型效果评估与阈值调整评估模型时不能只看 mAP还要关心业务层面的两个参数每个垃圾目标的置信度阈值conf_thres和 IoU 阈值iou_thres。conf_thres 默认 0.25实测时发现水面垃圾目标小、对比度低置信度普遍偏低如果把阈值提到 0.5 会漏掉很多真目标。最终我在端侧推理设置为 0.2配合“目标存在时间连续性”逻辑同一点连续 3 帧都有检测框才确认是真实目标有效控制误报。iou_thres 在 NMS 阶段保持默认 0.45 即可对大量重叠框的抑制效果足够。测试集评估结果如下mAP50 0.86mAP50-95 0.54PET 瓶单类召回率 0.91泡沫类召回率 0.82塑料袋类召回率 0.79。塑料袋的召回率较低原因是它在水中形态多变有时完全展开、有时揉成一团特征不稳定这类目标是后续数据扩充的主要方向。注意单独看每类召回率不要被平均 mAP 蒙蔽。我见过平均 mAP 0.85 但是某一类召回率只有 0.6 的情况这种模型到现场一飞就露馅。5. 模型部署与端侧推理实现5.1 导出 TensorRT 引擎并在 Jetson 上部署模型训练完成后需要从 PyTorch 权重转成可高效部署的格式。端侧推理平台选的是 Jetson Orin Nano运行 JetPack 5.1自带 TensorRT 8.5。在导出的时候建议先经 ONNX 中间格式再转 TensorRT中间可以顺手做算子融合。yolo export modelbest.pt formatonnx dynamicTrue imgsz1280 trtexec --onnxbest.onnx --saveEnginebest.engine --fp16两个细节值得注意导出 ONNX 时将 opset 设为 12 以上否则一些 YOLOv12 特定的注意力算子无法正确映射TensorRT 生成引擎时一次性指定 batch size运行时固定 batch 为 1 最稳妥动态 batch 在 Jetson 上很容易触发内存碎片问题。部署时用 Python TensorRT Python API 加载引擎做数据预处理读取帧 - 缩放至 1280 - 归一化 - 转 CHW - 推理 - 解析输出。输出解析时注意 YOLOv12 的输出格式与其他 YOLO 版本略有不同通道数包含 4 类目标 1 个置信度再加上类别概率。为了保险我写了后处理脚本将输出张量转成单列表后解析框、分数和类别。5.2 无人机图像输入链路与实时检测流程无人机实时画面接入方式参考了常见的低成本方案通过大疆遥控器 HDMI 输出连接采集卡或者直接通过网络推流获取视频流。我更推荐后者因为省掉了物理连接和采集卡驱动。启动检测服务后从视频流中按 1 帧/秒的频率抽帧这个频率对巡检足够不要贪高送入 TensorRT 引擎推理对检测结果做后处理。整个流程按如下步骤展开接收视频流帧。抽帧缩放预处理送入推理引擎。拿到检测框和置信度后先做基础过滤置信度低于 0.2 的丢弃面积小于 16x16 像素的丢弃。对剩余目标做空间坐标换算将像素坐标映射到经纬度坐标。同一点连续 3 帧都出现目标才作为有效垃圾点记录写入巡检报表并推送告警。GPS 坐标换算是整个链路里比较容易出错的一环正确做法是用无人机的经度、纬度、相对起飞点高度、云台俯仰角、偏航角、检测框中心点像素坐标联合相机内参做共线方程解算。简化实现中可以直接调用大疆的移动 SDK 的坐标转换接口把像素坐标和飞行参数传入。实测下来在 50 米高度下定位误差约 3-5 米能满足人工后续清理的寻找范围。5.3 推理性能实测数值在 Jetson Orin Nano 上跑 FP16 TensorRT 引擎输入 1280 分辨率单帧推理平均耗时约 35ms加上预处理和后处理整体耗时在 50ms 左右稳定跑出 20FPS。这个性能对巡检场景绰绰有余毕竟我们不会每帧都检测只做按秒采样且定位解算也能同步完成。如果后续需要提高效率可以尝试降到 960 分辨率推理时间能进一步缩短到 25ms 左右mAP 下降约 2-3 个百分点。这个取舍要看业务需求不是一律追求高分。6. 常见问题与排查技巧实录6.1 水面反光引起的误检水面反光是最常见的误检来源。强光下水面形成的高光区域纹理和白色泡沫类垃圾长得很像模型容易把光圈区域识别成泡沫。解决办法有三个采集数据时尽量避开强反光时段前面提到的 9-11 点、15-17 点训练数据里加入一定比例的强反光负样本推理端加上一层简单的亮度/饱和度过滤逻辑对高亮区域做抑制。实测三个手段叠加后强光误检率下降 70%。6.2 小目标漏检问题无人机在 60 米高空飞行时一个标准矿泉水瓶在画面里大约只有 20x45 像素属于典型的小目标。我试过在模型层面加 TALTask-Aware Learning相关策略也有一定提升但最直接的手段还是加大输入分辨率、加大数据集中小目标样本的占比。在采样阶段刻意多录制垃圾聚集区域的低空20-30 米视频小目标样本量翻倍后漏检率显著下降。6.3 标注不一致导致的训练震荡这个坑藏在数据里。不同标注员对“框到哪算边界”的理解不一致导致同一类目标的框时大时小训练时模型损失波动收敛不稳定。我的解决办法是标注规范里写明“包含目标可见轮廓的最小外接矩形为准不预留边距”标注完成后随机抽 200 张图做二次审查集中修正偏差较大的框。这一步便宜但极其有效。6.4 常见问题速查表问题现象可能原因排查与解决建议训练损失不降数据标签错乱、类别数不匹配、学习率过高检查 labels 目录 txt 文件首列类别号是否从 0 开始打印一张增强图检查标注是否对齐部署后推理结果全为空TensorRT 输出解析维度错误、预处理归一化方式不对用相同图片对比 PyTorch 和 TensorRT 的输出结果逐层排查误检集中在水岸交接处岸线背景被误识别为垃圾加入更多岸线负样本后处理时把靠近图像边缘 5% 区域的目标过滤视频流卡顿、掉帧采集缓冲不足、解码线程阻塞改用内存队列做帧缓存解码和推理分离到不同线程GPS 定位点漂移大云台角度未读取、RTK 未固定解确认使用定点模式飞行检查角度单位是弧度还是角度读数前先转统一7. 避坑心得与经验总结这个项目做下来最大的体会是“模型只是整套系统的一部分而不是全部”。很多人一上来就抱着模型调参刷分刷到好看的数字就以为完事了结果真飞到河面上被反光、水波、小目标、抖动画面折磨得怀疑人生。真正靠谱的流程一定是从数据端、采集端、部署端联合优化。数据不干净调什么都白搭部署硬件不跑一遍精度再高也落不了地。另外一个很深的体会是小目标的处理没有银弹。不要寄希望于换一个更大的模型就能解决更大的模型在 Jetson 上往往跑不动而你真正要做的是让数据里出现更多的小目标、让分辨率更高、让推理更省。这三件事同时发力小目标的效果才会肉眼可见地变好。如果你也想复现这个方案我的建议是分成三步走第一步找一小段河道两三公里用无人机按标准采集一趟拿到 1000 张左右底图第二步跑通标注到训练的最小闭环先跑出能用的模型第三步再把部署和定位功能逐步叠加。不要一开始就想着建一个百万级数据集能把 1000 张图用透再慢慢扩你会发现这条路顺畅得多。最后再分享一个细节巡检报表里除了记录每个垃圾点的位置我还额外记录了检测框的置信度和截图帧这样后续人工复核时可以直接回看原图不用再翻无人机原始的飞行视频。这个设计很小但真正用起来时能省下现场巡查人员大量的翻找时间。项目迭代了几个版本后我才意识到很多“好功能”不是靠算法复杂度堆出来的而是靠贴近业务流程的一个个小细节。