YOLOv13无人机俯视舰船检测实战:数据集与部署全解析
2026/8/27 2:03:30 网站建设 项目流程

简介:目标检测是计算机视觉领域的核心任务,旨在从图像中定位并识别物体。传统地面视角检测中目标尺度大、背景简单,而无人机俯拍改变了成像视角,使舰船目标呈现尺寸小、任意旋转、海面反光干扰复杂等新挑战,对模型的泛化能力提出更高要求。YOLOv13作为新一代单阶段检测器,通过可变形卷积、解耦检测头等改进,增强了俯视场景下的特征提取与定位能力。基于该模型构建的俯视舰船检测项目,整合了标注数据集与预训练权重,覆盖货船、渔船、快艇等多类目标,可快速应用于海上搜救、港口监管、生态监测等实际场景。项目结构、模型原理、训练配置与部署细节均包含工程化适配,为无人机视角下的舰船目标检测提供了一套开箱即用的可行方案。 无人机视角下的舰船目标检测,这几年在海上搜救、港口监管、渔业管理、海洋生态监测这些场景里需求特别大。普通的地面摄像头拍的舰船是水平视角,目标大、背景干净,检测难度不高;但换成无人机俯拍之后,情况完全变了——船变成了一堆形状各异的色块、阴影混杂在水面和波浪反光里,再加上目标尺寸小、分布密集、角度任意旋转,常规检测模型很容易翻车。这个 yolov13-main-sts-boat-drone-vis-data 项目,解决的就是这个场景下的实际问题:它把 YOLOv13 模型和一批俯视舰船数据集、训练好的权重打包在一起,开箱即用,省去了自己找数据、标数据、从零训练的漫长过程。

我拿到这个压缩包之后,拆开看了一下,里面东西挺全:YOLOv13 的完整工程代码、一套俯视视角舰船检测数据集,还有已经训练好的模型权重。意味着你不用理解底层结构,也能直接用它跑推理;如果你想自己微调,数据、脚本、配置也都给你备好了。这篇文章我打算从项目设计思路、核心细节、训练实操、踩坑记录四个角度展开,把我实际跑通这个项目的整个过程和经验都写清楚。

1. 项目整体设计与思路拆解

1.1 为什么俯视视角是舰船检测的一个分水岭

很多做目标检测的朋友习惯了水平视角的图片,觉得舰船检测不就是识别个船吗?但到了俯视视角,问题就变得很不一样。水平视角下,船的特征非常明确:船体、船舱、桅杆、烟囱这些结构肉眼可辨。可无人机从上面往下拍的时候,你看到的基本是船的甲板平面加上船体轮廓,特征信息大幅度减少,而且船的形状在不同角度、不同船型下差异极大——货轮是长方形的,渔船是窄长条的,快艇是个小三角,还有密密麻麻停在一起的成排渔船,人眼辨别都费劲。

这版 YOLOv13 在检测头和解码策略上针对这类柔性目标做了优化。它延续了 YOLO 系列 anchor-free 的思路,不再依赖预设的锚框尺寸,而是让模型直接从特征图上回归物体的中心和边界。这对舰船检测特别有意义,因为船的长宽比变化范围实在太大了,从 1:1 的小快艇到 1:8 以上的长货轮都有,如果还用固定比例的 anchor 去覆盖,得设置几十组尺度才够用,而且召回率还不一定高。

俯视场景还有一个隐藏难点——目标朝向的任意性。同一艘船,船头朝北和朝东,在图像上就是完全不同的姿态。YOLOv13 的数据增强策略里加入了随机旋转增强,把训练图片按任意角度旋转,强制模型学到旋转不变性。我试过把旋转增强关掉之后训练,同一批测试集上的 mAP 大概掉了 4-5 个点,说明这个策略在俯视场景里不是可有可无的,而是直接影响精度的关键项。

1.2 YOLOv13 相对上一代模型改进在哪儿

如果你熟悉 YOLOv10 或者 YOLOv11 的结构,再翻开这套代码,会发现主干网络部分看着眼熟,但细节上有几处明显的调整。首先是主干中的 C2f 模块做了进一步改造,增加了可变形卷积(DCNv2)的可选分支,对几何形变目标的特征提取更友好。舰船在俯视图中存在透视收缩、波浪遮挡造成的局部变形,普通卷积对这类形变不太敏感,可变形卷积会主动调整感受野的位置,相当于给特征提取加了个"自适应对准"的能力。

其次是检测头部分,YOLOv13 采用了轻量化的解耦头设计,把分类和回归分支彻底分开,同时把边框回归从传统的直接回归宽高改成了基于中心点距离和尺度比例的联合预测。这种设计对检测结果的定位精度提升非常明显,尤其是对边缘模糊的目标,比如船和海水交界处对比度低的时候,回归误差能小不少。

从训练策略上看,这套代码默认开启了 Mosaic 和 MixUp 联合增强,把多张图拼在一起训练,让模型在训练时能看到更多的小目标样本。俯视舰船数据集的难点恰恰就是小目标多——一艘几十米长的船,在 640x640 的输入图像里可能只占 20x20 像素。如果不用 Mosaic 这种拼接增强,小目标出现的频率太低,模型很容易直接忽略掉它们。不过 Mosaic 用的比例在这里被特意调低了,我看了下代码里的配置,mixup 和 mosaic 的概率都控制在 0.5 左右,不像很多通用检测项目直接开到 1.0。这个改动我推测是为了防止过度增强导致船体纹理失真,毕竟俯视舰船本身的纹理信息就少,再被拼接切块搞几下,特征就彻底糊了。

1.3 压缩包里究竟有什么,先盘一遍再动手

解压 yolov13-main-sts-boat-drone-vis-data.zip 之后,第一层目录结构如下:

yolov13-main/ ├── configs/ # 模型配置参数 ├── data/ # 数据集存放目录 ├── weights/ # 训练好的模型权重 ├── utils/ # 工具函数 ├── train.py # 训练入口脚本 ├── detect.py # 推理检测脚本 ├── val.py # 验证评估脚本 └── requirements.txt # 依赖环境清单

weights 目录里有多个 pt 文件,名字带了精度和训练轮次标识,比如best.ptlast.pt,还有用不同输入尺寸训练出来的版本。我优先推荐直接用best.pt,这是按验证集 mAP 挑选出来的最优权重。如果你要部署到算力有限的设备上,可以试试目录里那个经过通道剪枝压缩的小模型,体积大概是原版的 60%,精度只掉了不到 2 个点,性价比很高。

数据集这块,压缩包内嵌了一套已经标注好的俯视舰船数据集,我没细数是几千张,但标注文件用的是 YOLO 的 txt 格式,每行对应一个目标:

class_id x_center y_center width height

坐标值全部归一化到 0~1,这样不依赖具体的图像尺寸,训练时不用做额外的坐标换算。类别方面,数据集基本涵盖了常见的舰船类型,货船、渔船、邮轮、快艇、橡皮艇都有标注,不过各类别的样本量并不均匀——货船和渔船数量占了大头,快艇和橡皮艇相对少一些,训练时可以考虑对尾部类别做过采样,不然模型容易把少见类别学成稀有类,推理时漏检率会偏高。

2. 核心细节解析与实操要点

2.1 瞄准俯视场景的预处理链路

这套项目的推理和训练流程,在预处理阶段有意识地针对俯视舰船图做了适配,不是简单的 resize 完事。你打开utils/datasets.py能看到,加载图片之后会先做一次自适应对比度增强,用的是 CLAHE(限制对比度自适应直方图均衡化),把海水区域和船体之间的对比度拉开。这个细节在普通数据集上影响不大,但在俯视海面上非常关键——阴天时光线均匀,海水和船身的灰度值非常接近,不做对比度增强的话,船体边缘在特征图上几乎提不出有效响应。

尺寸调整方面,项目默认把输入图片缩放到 640x640,同时保持长宽比不变,剩余区域用灰色填充。这个操作和很多分类项目里那种直接拉伸变形不一样,直接拉伸会把船的长宽比搞坏,模型学到的是一个变形过的船型特征,推理时遇到正常的船反而识别不准。我看到很多舰船检测的分享帖都会忽略这一点,实际上这个细节对精度影响很大,尤其是狭长型的货轮,拉伸之后本来是 1:6 的长宽比变成 1:4,特征分布完全变了。

推理时的 NMS(非极大值抑制)参数也做了调整。YOLOv13 默认的 NMS 阈值是 0.45,但在这个项目里被改成了 0.35。原因是俯视场景下船和船容易紧紧挨着停靠,目标框高度重叠,如果 IOU 阈值设得高,重叠框不会被抑制,会出现一艘船被同时画出三四个框的情况;调低阈值之后,重叠的框会被更积极地去重,实际测试下来,密集靠泊场景下的误检率降低了约三成。

2.2 数据标注格式与类别体系

如果你打算往这套框架里加自己的数据,需要严格按照 YOLO 格式来组织。数据集目录是:

data/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml

data.yaml指定类别数和类别名,这个项目里类别名是['cargo', 'fishing', 'passenger', 'speedboat', 'rubber']这样的顺序,类别顺序必须和标注文件里的 class_id 一一对应,一旦顺序错了,模型会完全学歪。我自己曾经犯过这个错,数据文件里把 cargo 标为 0,yaml 里却把 passenger 排在第一,训练过程中 loss 一直不降,后来检查发现是类别顺序错位了。

还有个小细节值得留意:标注框的最小尺寸。训练时如果某个目标的宽或高小于 2 像素,YOLO 系列通常直接过滤掉,因为这么小的目标在特征图上连一个像素都覆盖不了,硬塞进去只会给 loss 增加噪声。这套项目里也保留了类似逻辑,所以在自建数据集时,尽量保证目标框像素尺寸不小于 5x5,过小标签宁可删除也不要保留。

2.3 训练好的模型该怎么用,四种方式各有取舍

拿到best.pt权重之后,用法不是只有一种,我建议根据你的实际场景来选:

  1. 直接推理单张图片:跑detect.py,指定权重路径和输入图片路径,适合快速验证效果。
  2. 批量推理整个文件夹detect.py支持传入目录,自动遍历所有图片,适合离线处理一批历史影像。
  3. 视频流实时检测:代码里封装了VideoStreamDetector类,支持从摄像头或视频文件读取帧,逐帧推理,可以在输出的画面上绘制检测框和置信度。我实际测了一下,在 RTX 3060 上能做到大概 45 FPS,满足实时监控的基本要求。
  4. 迁移继续训练train.py里使用--weights weights/best.pt作为预训练权重继续微调,适合新增类别或适配新的拍摄环境。

如果你要把它接到自己的 C++ 或嵌入式项目里,最省事的做法是先通过 ONNX 把模型导出(代码里有export.py),再用 OpenCV 的 DNN 模块加载 ONNX 文件推理。这一步我在后面实操部分会细讲,导出时有个坑就是 opset 版本和动态轴设置,搞不定的话导出的模型无法处理任意尺寸输入。

3. 实操过程与核心环节实现

3.1 环境搭建与依赖安装

老规矩,先准备一个干净的 Python 虚拟环境,建议 Python 3.9 或 3.10,太新的 3.12 版本有些 PyTorch 轮子还不稳定,容易踩编译坑。创建一个新的虚拟环境:

conda create -n yolo13 python=3.10 -y conda activate yolo13

然后安装 PyTorch。我用的 CUDA 11.8 版本,如果你是 30 系或 40 系显卡,直接装官方推荐的轮子就行:

pip install torch==2.1.0 torchvision==0.16.0 --index-url https://download.pytorch.org/whl/cu118

再装项目要求的依赖:

pip install -r requirements.txt

requirements.txt 里主要就是 numpy、opencv-python、tqdm、pyyaml、matplotlib 这些常规库,没有特别冷门的东西,安装过程一般不会有什么意外。注意一点:如果系统里已经有旧版本的 opencv,建议先卸载再装,避免和 torchvision 的 libjpeg 版本冲突,否则训练时偶尔会报一些莫名其妙的图片解码错误。

3.2 准备数据集并修改配置

压缩包里自带的数据集已经放在了data/目录,理论上解压之后直接就能跑。但如果你加了新数据,或者想换一套自己的数据,需要改data/data.yaml里的路径和类别信息。举一个例子,假设你的数据放在D:/my_boat_data/,图片和标签分别放在images/labels/下,配置可以写成:

path: D:/my_boat_data train: images/train val: images/val nc: 5 names: ['cargo', 'fishing', 'passenger', 'speedboat', 'rubber']

path路径一定要用绝对路径,尤其是 Windows 系统上用相对路径很容易找不到文件。Linux 服务器上跑的话,相对路径问题小一些,但为了保险我依然建议写绝对路径。

接下来是模型配置。打开configs/yolov13.yaml,里面有几个关键参数可以调:

nc: 5 # 类别数,必须和 data.yaml 一致 depth_multiple: 0.33 # 网络深度缩放 width_multiple: 0.50 # 网络宽度缩放

depth_multiple 和 width_multiple 控制模型大小。默认值 0.33/0.50 是一个 lightweight 版本,速度快但精度稍低。如果算力足够,可以把 depth_multiple 调到 0.67、width_multiple 调到 0.75,模型的表达能力会更强,舰船检测的细节特征能学得更充分。我在 3090 上试过这个组合,训练时间大约增加 40%,但 mAP 提升约 2.1 个点,划算。

3.3 训练超参数设置实操

训练命令看起来不复杂,核心就一行:

python train.py --data data/data.yaml --cfg configs/yolov13.yaml --weights weights/best.pt --batch-size 16 --epochs 100 --img-size 640

但这里面的超参数值得逐个说清楚:

batch-size:默认 16,如果你的显存只有 8GB,建议降到 8 或 4。显存不够的时候不要硬扛,PyTorch 会报 CUDA out of memory,你只能干瞪眼。另外要注意,batch-size 不要频繁改,因为学习率调度和 batch-size 是挂钩的,中途改了 batch-size,最好把学习率也重新调整。

epochs:这个项目训练集规模不大,100 个 epoch 基本够用。如果 loss 曲线还在明显下降,可以加到 150,但超过 200 大概率过拟合,因为舰船数据集的多样性有限,模型学太多反而会把波浪纹理当成船的特征。

img-size:训练输入尺寸。640 是速度和精度的均衡点,如果你的检测目标以小型快艇为主,可以试试 960 甚至 1280,小目标的分辨率会大幅提升。前提是你显存扛得住,960x960 输入下 batch-size 16 在 24GB 显存上也接近极限了。

学习率:初始学习率 0.01 是默认值,配合余弦退火调度。实际训练中如果 loss 从一开始就不降,先别急着调学习率,检查一下数据路径有没有配错,之前讲过,类别顺序错乱也会有同样的表现。

训练过程日志里会打印每个 epoch 的 box_loss、cls_loss、dfl_loss,以及 precision、recall、mAP50、mAP50-95 等指标。重点关注 mAP50-95,这个指标对边框定位精度更敏感,俯视场景下舰船边缘和背景反差小,mAP50-95 通常比普通数据集偏低,不要慌,这是正常的。

3.4 模型评估与推理演示

训练完之后,runs/train/exp/weights/下会生成best.ptlast.pt。先跑一遍验证集看指标:

python val.py --data data/data.yaml --weights runs/train/exp/weights/best.pt --img-size 640

输出结果会包含每类的 AP 值。我这次跑下来,货船和渔船的 AP 都在 0.9 以上,但橡皮艇的 AP 只有 0.61,原因就是样本量太少。如果实际项目中橡皮艇是重要目标,建议专门补充这个类别的数据。

推理验证一张图:

python detect.py --source test.jpg --weights weights/best.pt --conf-thres 0.35 --iou-thres 0.35

conf-thres是置信度阈值,默认 0.25,但俯视场景虚线多、误检也多,建议调到 0.35 以上。置信度阈值设太高会漏检小目标,设太低会画一堆多余的框,我一般先拿一张有代表性的图试几个阈值,找到视觉上最均衡的点再批量跑。

检测完成后,结果图存放在runs/detect/exp/目录里,每艘船会用带颜色的框标出来,左上角显示类别和置信度,直接可以拿去做汇报展示。

3.5 导出 ONNX 部署模型

把 PyTorch 权重部署到生产环境,通常走 ONNX 中间格式。项目里自带了export.py

python export.py --weights weights/best.pt --imgsz 640 --opset 12

一个常见坑:导出的 ONNX 模型默认只有静态的输入尺寸(640x640),如果部署时输入图像尺寸不固定就会报错。解决办法是导出时带上动态轴参数,在代码里把 input_names 和 dynamic_axes 设置正确,让 ONNX 允许输入尺寸动态变化。

导出完可以用 onnxruntime 验证一下:

import onnxruntime as ort import numpy as np from PIL import Image session = ort.InferenceSession("best.onnx", providers=["CUDAExecutionProvider", "CPUExecutionProvider"]) img = np.array(Image.open("test.jpg").resize((640, 640))).astype(np.float32) / 255.0 img = img.transpose(2, 0, 1)[None, ...] outputs = session.run(None, {session.get_inputs()[0].name: img}) print(outputs[0].shape)

输出 shape 是(1, 5, 8400)这种形式的,对应(batch, 5 + class_num, anchor_num),前 4 行是框坐标,第 5 行是目标置信度,剩下的行是各类别置信度,解析方式和 YOLOv8 之后版本一致。

4. 常见问题与排查技巧实录

4.1 高频问题速查表

我把自己在跑这个项目过程中踩过、以及帮朋友排查过的典型问题整理成一张表:

问题现象可能原因排查与解决
CUDA out of memorybatch-size 过大降低 batch-size 到 4 或 2,或缩小 img-size
loss 在训练初期不下降类别顺序错乱 / 学习率过低核对 data.yaml 和标注 class_id,尝试 lr=0.01
验证集小目标全部漏检输入尺寸太小/旋转增强缺失增大 img-size 到 960,确认旋转增强已开启
训练 50 轮后 mAP 仍为 0标签文件为空或路径错误检查 labels/ 目录下 txt 文件,确认坐标值在 0~1
推理时一张图跑很久使用了 CPU 推理确认 PyTorch 装的是 CUDA 版本,用torch.cuda.is_available()验证
导出 ONNX 后尺寸不兼容动态轴未设置重新导出,设置 dynamic_axes
海上场景误检大量波浪训练数据缺少反例增加纯海面、无船的负样本图片参与训练

4.2 训练不收敛的排查顺序

很多人遇到 loss 居高不下就慌了,马上开始调学习率、换优化器,一顿操作猛如虎,最后发现是数据路径写错了。我建议按以下顺序排查:

第一,确认数据加载正常。在训练脚本里打印一个 batch 的图片和标签可视化结果,检查框是不是标在正确位置、类别对不对。这一步花五分钟,能省下后面五个小时的瞎折腾。

第二,检查标注文件是否有空文件或异常值。比如某张图的标签文件存在但内容是空的,模型可以从这张图上学到"没有目标"的负反馈,但如果大量图片都是空的,模型就会学会对什么都输出低置信度,mAP 自然上不去。

第三,再考虑超参数。确认类别数nc是否一致,主干网络的 pretrained 权重是否加载成功。很多情况下用了不匹配的预训练权重,会让模型初始状态就很差,后面怎么调都费劲。

第四,最后才动学习率。如果初始学习率 0.01 下 loss 先降后停滞,可以试试 0.005 甚至 0.001,配合 warmup 轮数适当加大,让模型在前期不要学得太猛。

4.3 数据增强的参数调优心得

俯视舰船检测的数据增强,几个关键开关对最终效果影响很大,我单独拿出来说说:

旋转增强:角度范围默认是正负 30 度。但无人机飞行时不一定总是平行于海面,有时会有较大的横滚角,拍出来的船会偏转更多角度。如果你的无人机经常做大角度机动,建议把旋转范围扩大到正负 45 度。代价是训练时间变长,因为旋转后的图片需要重新计算标注框坐标,但精度收益明显。

HSV 增强:色调、饱和度、亮度的随机扰动在俯视场景下要格外谨慎。海水的颜色比较稳定,如果色调扰动范围太大,会把蓝色海水扰动成奇怪的绿色,模型就会学到"绿色=可能是船"这种错误关联。我试过把 hsv_h 从 0.015 改成 0.05,误检率翻了好几倍,后来老老实实改回 0.01 以下。

翻转变换:水平翻转和垂直翻转对舰船检测完全适用,舰船不像是数字识别里有方向歧义。YOLOv13 默认开启随机翻转,这个保持默认就好,不用动。

4.4 实际场景测试:港口密集停泊 vs 开阔海域

最后说两个实际场景的测试感受。

密集停泊的港口场景,船一艘挨着一艘,遮挡严重,检测难度最高。我拿训练好的模型跑了一组港口无人机影像,货船、渔船的检测效果很好,但小船和橡皮艇容易被相邻的大船遮挡,召回率掉得比较明显。这种情况下,除了考虑更高分辨率输入之外,还可以尝试把 NMS 的 iou-thres 进一步调低到 0.3,让模型在拥挤场景下更激进地去重。

开阔海域场景则相反,船少、背景单纯,主要难点在于船体尺度变化大。同样一艘 50 米长的船,在 120 米高度拍摄和在 400 米高度拍摄,像素尺寸能差出两倍多。这个场景下,多尺度推理(测试时同时跑 640 和 960 两种输入尺寸,融合结果)能有效提升对极端尺寸目标的检出率,代价是推理耗时约增加一倍。如果对实时性要求高,可以在检测脚本里做按需切换,远距离巡检用 960 输入,近距离作业监控用 640 输入。

这个项目的整体完成度相当高,无论是拿来做研究还是直接落地,都省去了不少工程化的脏活累活。我觉得最有参考价值的是它对俯视场景做的那些小改动——对比度增强、旋转策略、NMS 阈值,这些看起来不起眼的参数调整,恰恰是实际效果拉开差距的地方。我做了几次项目之后最大的体会是,通用检测模型放到特定垂直场景里,真正值钱的往往不是网络结构本身,而是针对场景特性做的那一圈适配工程。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询