
简介无人机视角下的船只检测与水上目标识别是海上搜救、港口监控等任务的关键环节。这套基于Ultralytics YOLO11的完整资源包面向目标检测初学者与无人机视觉研究者内置标注数据集、训练好的模型权重及配套使用教程可直接用于YOLOv5/v8/v9/v10/v11/v12等算法的训练与推理。压缩包共2000个文件、约676.5MB以txt标注文件、yaml配置、Python脚本为主并含jpg示例图像、md说明文档及C/JS部署代码覆盖数据、训练、评估、部署全链路。数据集已划分train/val/test并附带data.yaml提供YOLO与VOC格式标签类别为boat船只同时包含模型评价指标曲线图。目前已有89人学习适合从零上手无人机水面目标检测与搜救场景应用的开发者。1. 无人机视角船只检测一个压缩包能不能直接扛起海上搜救的活搜救无人机飞出去图传画面里一艘救生艇往往只有十几个像素通用目标检测模型在陆地上跑得不错到了水面上几乎全漏。YOLO11 无人机视角船只检测这个方向核心就是把检测能力从「能看见船」推进到「在复杂水面上认出船、找到人、支撑搜救决策」。标题这个压缩包把三样东西打包在一起无人机视角的水上目标识别数据集、训练好的 YOLO11 权重、以及可以直接落地的检测流程。对刚入手航拍视觉的开发者它省掉了最耗时的采集和标注环节对已经在做海上搜救项目的工程师它是评估这个方向值不值得投入的现成基准。这篇笔记按「为什么难 → 怎么跑通 → 坑在哪 → 怎么调优」往下拆命令可以直接执行参数说明和踩坑记录放在对应章节。中间我加了不少自己踩过的坑尤其最后那章的建议建议先看完再动手调参。2. 为什么无人机视角的船只检测这么难任务拆解与 YOLO11 选型逻辑把通用目标检测模型直接搬到水上航拍先死掉的往往不是网络结构而是任务假设。通用检测默认目标「直立、纹理清晰、占画面比例不小」无人机视角这三条全不满足。下面从成像、网络、数据三个层面拆开看。2.1 无人机视角的成像特点目标小、背景杂、尺度跨度大无人机飞行高度从 50 米到 300 米不等同一艘船的成像宽度可能相差 6 倍以上。50 米高度能看清甲板纹理和船名300 米高度就只是一个明暗块。海上搜救里更极端的情况是 10 米长的橡皮艇在 1080p 画面里只占约 20×10 像素和一层浪花碎末在尺度上几乎没有区别。这让「按目标尺寸设计特征」的通用检测器非常吃力漏检几乎不可避免。背景复杂度是第二个杀手。水面不是单一颜色有波纹、有太阳耀斑、有云影、有船行尾迹还有海岸线上的防波堤、栈桥和岸上建筑物。陆上模型把「矩形 纹理 边缘」当船到了水面上这些线索全部失真而搜救任务的低空机动飞行还会带来运动模糊和视角突变画面质量比车载摄像头还低一档。第三个特点是目标形状极度离散。货轮是长方形拖船近似方形帆船是细长三角形落水人员几乎就是一个点。固定的 anchor 设计很难同时覆盖这些几何形态所以做水上目标识别时类别设计和数据分布往往比网络选型更先决定成败。尤其是「人员落水」这类目标它在图像里的语义信息极弱模型能做的更多是「疑似目标定位」而不是真正「认出人」。2.2 YOLO11 的架构改进对水上目标识别意味着什么YOLO11 是 Ultralytics 在单阶段检测器上的最新迭代几个关键结构变化对航拍场景是有实际增益的。backbone 里引入了注意力机制模块让网络在大量水面背景中更容易聚焦到稀疏的目标区域特征融合结构做了轻量化改造参数量和计算量比上一代更小这对无人机机载算力非常友好。检测头仍保持无 anchor 的 decoupled 设计分类和回归分支独立训练收敛更稳。对做海搜的工程师来说YOLO11 最实用的特性是「预训练权重 微调」的路径非常短。直接拿通用基准数据集上训练的权重跑无人机画面效果通常不理想因为预训练数据里几乎没有俯视小目标样本但这个权重作为初始化在船只数据集上微调几十个 epoch 就能快速收敛远比从零训练省时间。单阶段检测器的推理速度也保证了实时的处理余量搜救飞行的图传回传链路里这是硬指标。需要提醒的是YOLO11 的精度优势主要体现在常规尺度目标上。对 20 像素以下的落水人员这类极端小目标网络结构本身只能「少漏」不能做到「全检」最终要靠推理分辨率、图像预处理和跟踪后处理一起补。选型时也不要只看精度数字同一套数据下n/s 这类轻量模型跑高分辨率往往比 l/x 大模型跑低分辨率更实用因为航拍小目标对分辨率更敏感。2.3 数据集里应该有什么标注格式、类别设计和训练/验证划分拿到压缩包先别急着跑命令先摸清数据集结构。一个合格的 YOLO 风格水上目标数据集至少包含 images 目录、labels 目录、一个 data.yaml 类别描述文件以及训练/验证划分。labels 下每个 txt 文件名与对应图片名一致每行描述一个目标共 5 列数字。字段含义取值范围class_id类别索引必须与 data.yaml 中 names 顺序一致0 到类别数减 1cx目标框中心点 x 坐标相对图片宽度归一化0~1cy目标框中心点 y 坐标相对图片高度归一化0~1w目标框宽度相对图片宽度归一化0~1h目标框高度相对图片高度归一化0~1类别设计直接决定模型能否支撑海搜任务。如果 data.yaml 里只有「船」一个类模型学出来就是一个「有没有物体」的判别器指挥员拿到结果还得自己判断是货轮还是救生艇没有决策价值。我一般会至少拆成三类大型船只货轮、客轮、小型船只橡皮艇、救生艇、渔船、落水人员。如果数据量撑不住三类至少要把小型船只单独拆出来因为它是搜救任务里优先级最高的目标。训练/验证划分在这里有个典型陷阱无人机视频常是同一架次连续拍摄的如果随机划分同一段航线的相邻帧会同时进训练集和验证集验证指标虚高到没有参考意义。划分前要先按视频片段分组同一个架次的帧只能进一边。另一个检查点是标签质量框是否贴边、倒影和浪花有没有被标进去、类别标号是否从 0 开始。这类问题训练时不会报错只会静默拉低指标属于最典型的黑匣子。3. 从解压到跑通推理YOLO11 船只检测模型的最小复现路径解压 zip 后目录里通常会有 weights/best.pt、images、labels、data.yaml 这几样。第一步不是急着训练而是先用训练好的模型做一次推理确认压缩包内容完好、环境可用再谈微调和部署。3.1 环境准备虚拟环境、依赖安装与可复现性建议用 Python 3.10 到 3.12单独建虚拟环境不要直接装到系统 Python。航拍项目的依赖经常互相打架独立环境是最便宜的后悔药。# 解压之后先建独立环境避免污染系统 Python python -m venv venv_drone source venv_drone/bin/activate # Windows PowerShell 用 venv_drone\Scripts\Activate.ps1 pip install ultralytics # 会自动带上 torch、torchvision 等依赖 python -c import ultralytics; print(ultralytics.__version__)pip install ultralytics 会拉取 torch安装包体积比较大耐心等。没有 NVIDIA GPU 的机器会自动装 CPU 版推理能跑但速度慢有 GPU 先确认 nvidia-smi 输出的驱动和 CUDA 版本再决定要不要手动装对应 torch 版本。装完后打印 ultralytics 版本号能正常输出就说明基础环境通了。import torch print(CUDA 可用:, torch.cuda.is_available()) print(设备:, torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU)注意如果 torch.cuda.is_available() 返回 False先检查驱动和 CUDA 版本是否匹配不要急着重装整个环境。3.2 用训练好的权重跑一次无人机视角推理环境就绪后先用命令行跑一张图验证权重文件没有损坏。结果图会默认存到 runs/detect/predict 目录打开看框是不是贴住目标。# 对单张图片或整个目录推理结果默认存到 runs/detect/predict yolo predict modelweights/best.pt sourcesamples/ imgsz1280 conf0.25 iou0.5 saveTrue这里几个参数后面会反复用到。imgsz1280 是航拍小目标的关键设置默认 640 在无人机画面上会漏掉大量小艇conf0.25 表示置信度低于 0.25 的框直接丢弃阈值越低召回越高误检也越多iou0.5 是 NMS 去重阈值港口密集场景需要降。第一次跑完先别急着调参看结果图里框的贴合程度再决定。处理视频或批量帧时我会用 Python API方便把检测结果结构化输出到日志里from ultralytics import YOLO model YOLO(weights/best.pt) results model.predict( sourcesea_rescue_clip.mp4, # 无人机视频或图片目录 imgsz1280, # 航拍小目标建议不低于 1280 conf0.3, # 置信度阈值按场景在 0.2~0.5 之间调 iou0.5, # NMS 阈值密集停靠场景降到 0.3~0.4 streamTrue, # 视频逐帧返回避免一次载入全部帧爆内存 ) for frame_id, r in enumerate(results): boxes r.boxes.xyxy.cpu().numpy() # 目标框坐标格式 [x1, y1, x2, y2] scores r.boxes.conf.cpu().numpy() # 每个框的置信度 cls_ids r.boxes.cls.cpu().numpy().astype(int) for s, b, c in zip(scores, boxes, cls_ids): if s 0.3: # model.names[c] 是类别名检查这里和 data.yaml 是否一致 print(f第{frame_id}帧: 类{model.names[c]} 置信度{s:.2f} 框{b})streamTrue 会让 predict 逐帧生成结果而不是一次性加载整个视频长航拍视频必须开否则内存会被撑爆。xyxy 坐标是像素值cpu().numpy() 是把 GPU 上的 tensor 转成普通数组方便后面做轨迹关联或地理编码。model.names 保存了类别名列表如果打印出来的类别名和 data.yaml 对不上说明标签错位后面训练会出问题。3.3 检查数据集完整性目录结构、标签格式和类别文件推理跑通后回头把数据集完整检查一遍。这个步骤花十分钟能省掉训练跑了一半发现数据有问题的翻车。tree -L 2 -d . # 看整体目录结构 head -5 train/labels/000001.txt # 抽查标签格式应为 5 列数字 wc -l train/labels/*.txt | tail -1 # 统计标签文件总行数粗看目标总数 find train/labels -size 0 | head -5 # 找空标签文件空文件要清理 cat data.yaml # 确认类别名称、数量、路径标签每行必须是「class_id cx cy w h」五个数空格或 Tab 分隔坐标都归一化到 0~1。wc -l 统计出来的总行数就是目标总数拿这个数除以类别数能粗看有没有类别不平衡目标总数只有几百的话不要指望微调后指标有多高。空标签文件会让训练时该图直接跳过如果空文件占了三分之一说明采集时大量帧没内容训练集会虚胖。data.yaml 检查要重点看两处names 列表的顺序和 labels 里的 class_id 是否从 0 开始且一一对应path 字段指向的目录在当前机器上是否存在。如果 zip 里没有独立 val 目录可以自己写脚本从 train 里划 10%~20% 出来但注意按视频架次分组不能随机抽帧。数据集检查完整个复现路径才算真正闭环。4. 水上目标识别避坑清单海上搜救场景里最容易翻车的 5 个地方这 5 个坑是无人机视角船只检测复现时最常见的翻车点全部按「现象 → 原因 → 解决」记录。前三个在推理参数和数据集层面就能修后两个要回到训练和数据采集。4.1 小目标漏检为什么 imgsz640 在无人机画面上不够用现象微调时验证集 mAP 看着有 0.8把模型拿到 300 米高度实拍视频上小艇全程没框误检反而集中在大船周围。原因训练和推理分辨率不匹配。imgsz640 时20 像素的小艇在下采样后的特征图上只剩 1~2 个像素特征几乎丢光而验证集里的目标往往比实拍更大尺度分布对不上于是指标虚高。解决推理 imgsz 提到 1280 或 1536召回肉眼可见提升微调用同样分辨率。显存不够时用 n/s 小模型配高分辨率而不是大模型配低分辨率。另外训练时把 Mosaic 增强关掉或降启用概率——Mosaic 会把小目标切碎对航拍小目标检测常常是负优化这个参数值得单独实验。4.2 水面反光和倒影导致的误检现象平静海面上船头正下方多出一个船的框晴天太阳耀斑区域被识别成白色船体且置信度还不低。原因倒影和水面反光在纹理上真的和船体很像模型学到的是「竖长结构 高亮区域 船」。训练集里如果有大比例带倒影的样本且被标注成船这个错误模式会被固化。解决训练时把倒影区域显式标为背景或单独加一个 ignore 类推理后处理用形状过滤船体宽高比一般在 1:1 到 4:1倒影通常是细长结构按宽高比直接滤掉视频场景加 ByteTrack 这类轻量跟踪器闪烁出现又消失的框大概率是反光误检丢弃即可。这个坑在太阳高度角低的清晨和黄昏最严重。4.3 港口密集停靠场景下 NMS 把相邻船只压掉现象港口里并排停靠的船输出框把两三艘船圈成一个大框中间的船被吞掉统计船舶数量时误差很大。原因相邻目标重叠度高默认 NMS IoU 阈值0.5~0.7把两个预测当成对同一目标的重复检测置信度稍低的框被删除。这在港口、锚地这类高密度场景特别常见。解决推理时把 iou 降到 0.3~0.4保留相邻预测训练时确保数据集里有足够多的密集停靠样本让模型学到对相邻目标输出错开的中心点多类别场景不要开 agnostic_nms否则不同类别的重叠目标也会互相压制。4.4 白天训练的模型在黄昏和阴雨天失效现象同一套权重中午实拍没问题黄昏低角度阳光下漏检率明显上升阴天浪花多时误检变多海况差的时候几乎不可用。原因光照色温和对比度变化导致特征分布偏移训练数据的时间分布太集中。航拍画面里水面颜色随太阳高度角变化极大模型没见过的光照条件就是另一个域泛化无从谈起。解决训练时把 HSV 增强参数调大h 从 0.02 提到 0.05 以上s 和 v 从 0.5 提高到 0.8模拟不同时段采集数据按架次覆盖早、中、晚和阴、晴至少保证验证集里有黄昏样本推理侧可以用 CLAHE 做预处理增强对比度。别指望模型泛化到完全没见过的光照条件数据覆盖才是根治办法。4.5 类别不平衡搜救目标被货轮样本淹没现象货轮、客轮检测很稳救生艇和落水人员类别的召回率只有个位数训练损失正常下降但小类的指标纹丝不动。原因数据集中大目标类别样本多、小目标类别样本少分类损失被大样本类别主导网络把容量都花在学货轮上。搜救任务最关心的两类恰好是样本最少的两类这个错位很致命。解决最直接的是给 loss 加类别权重训练配置里设 class_weights把救生艇和人员的权重拉到其余类的 5~10 倍数据层面做小类过采样或把含小艇的图重复进训练集条件允许的话单独训练一个高分辨率专用小目标模型只负责找小艇和人员和大船模型做级联。级联方案在海搜项目里最常见也最可靠代价是推理链路多一跳。5. 让模型在海搜任务里更可靠微调、推理参数与部署的进阶技巧5.1 用自己的数据微调时的参数建议拿到压缩包只是起点。把模型用到自己的辖区海域我一般会用自己的航拍视频抽帧标注然后以压缩包里的 best.pt 为初始化跑一轮微调。关键参数如下from ultralytics import YOLO model YOLO(weights/best.pt) # 以压缩包权重为初始化而不是通用预训练权重 model.train( datadatasets/sea/data.yaml, epochs60, imgsz1280, # 与推理分辨率保持一致 batch8, freeze10, # 冻结前 10 层小数据下收敛更稳 lr00.0005, # 微调学习率要比默认低避免破坏已有特征 class_weights{0: 1.0, 1: 1.0, 2: 6.0}, # 索引对应 data.yaml 的 names 顺序 namesea_finetune, )freeze10 适合几百张量级的微调数据量过千后可以降为 0 全量微调lr0 我习惯从默认值往下调一个数量级用已有权重起步时这个差别很大。class_weights 的索引要和 data.yaml 里的 names 顺序严格对应顺序错了损失权重就张冠李戴。5.2 部署验证别只盯着 mAPyolo export modelruns/train/sea_finetune/weights/best.pt formatonnx imgsz1280导出 ONNX 后推理速度明显提升适合机载端部署等模型稳定了再考虑量化到 int8海上低对比度画面量化后掉点比常规场景更狠要实测后再决定。验证方面我每轮微调完不是先看 mAP而是先跑一遍最难的那段黄昏实拍视频肉眼过一遍漏框和误检再回来看指标表格。mAP 平均掉几个点可能无所谓黄昏小艇一框不漏才是海搜真正要的指标。我自己踩过一回mAP 涨了 0.03实拍视频里落水人员却全漏原因是验证集和实拍场景根本不同域。后来我把验证流程固定成「最难视频优先」小模型先过大模型再过这个习惯一直沿用到现在。干这一行指标是给别人看的最难那段视频是自己心里的一根弦。希望帮到你。本文还有配套的精品资源点击获取