拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

高分辨率遥感船舶检测数据集构建与YOLOv8实战指南

高分辨率遥感船舶检测数据集构建与YOLOv8实战指南 简介本资源为面向深度学习目标检测任务的船舶遥感数据集适合从事遥感图像识别、海上目标监测的科研人员与算法工程师使用。数据采用VOC2007格式JPG影像与XML标注文件一一对应可直接接入YOLO、Faster R-CNN等主流检测框架进行训练与验证。影像来自高分2号与谷歌卫星分辨率介于0.5至0.8米之间覆盖油轮、集装箱船、快艇、小型游艇、邮轮及杂货船共六类船舶类别分布丰富便于开展多类别检测与细粒度识别研究。压缩包内共约2000个文件以7046个XML标注与7046张JPEG影像为主整体约945.16MB数据量充足可满足科研实验与论文复现需求。目前已有678人学习下载适合需要高质量遥感船舶样本的读者快速构建训练集与测试集。1. 高分辨率遥感影像船舶检测数据集从0到1构建与YOLOv8实战拿到“基于高分辨率遥感影像的船舶目标检测数据集”这个题目很多人第一反应是去搜现成的数据集下载。但现实很骨感公开的遥感船舶数据集要么分辨率不够要么标注质量参差不齐要么场景单一直接拿来训练模型在真实港口、近海、岛礁场景下翻车是常态。我见过太多团队花两周时间调模型最后发现是数据集里的标注框把浪花和尾迹都框进去了模型学到的全是噪声。这篇文章不讲空泛的“数据集很重要”而是从影像获取、标注策略、格式转换到YOLOv8训练把一条能跑通的链路拆开让你能自己产出一份可用的高分辨率遥感船舶检测数据集。适合手里有遥感影像源、需要定制化检测任务的算法工程师和遥感应用开发者。2. 高分辨率遥感船舶数据集的核心构成与选型逻辑2.1 为什么船舶检测不能直接套用通用目标检测数据集通用目标检测数据集如COCO、VOC里面的船大多是自然场景下的近景拍摄船体占画面比例大背景是水面和天空。但高分辨率遥感影像的视角是正下视或倾斜俯视船舶目标通常只有几十到几百像素背景是复杂海面、港口设施、岛礁、云层阴影。直接把COCO预训练模型拿来跑遥感影像mAP能掉到0.1以下。核心差异在三点目标尺度分布、背景纹理复杂度、目标朝向多样性。遥感船舶的宽高比从1:1到1:8都有且朝向任意通用检测器的锚框设计根本不匹配。所以自建数据集时必须针对遥感场景重新设计类别定义、标注规则和尺度增强策略。2.2 影像源选择分辨率、波段与重访周期的权衡高分辨率遥感影像的来源决定了数据集的上限。常见来源分三类商业卫星影像如WorldView、GeoEye系列分辨率0.3-0.5米、开源卫星影像Sentinel-2分辨率10米不适合船舶检测Landsat 30米更不行、无人机航拍影像分辨率可达厘米级但覆盖范围小。做船舶检测最低要求是空间分辨率优于1米否则小型渔船和浪花无法区分。波段方面全色波段分辨率最高但只有灰度信息多光谱波段能提供颜色特征辅助区分船舶与暗礁但分辨率通常低4倍。我一般建议如果做港口内大型船舶检测用全色波段0.5米数据足够如果要做近海小型船舶优先选多光谱融合后的0.8米数据颜色信息对降低虚警很关键。重访周期影响数据多样性单时相数据训练的模型在云影、海况变化时容易失效至少覆盖3个不同时相。2.3 标注规范从“框住船”到“框住可判别区域”标注质量是数据集的生命线。遥感船舶标注最容易犯的错是把尾迹、浪花、系泊设施一起框进去。正确的标注规则是边界框应紧贴船体最外轮廓包括船首尾和舷侧但不包括尾迹和浪花。对于并排停靠的船舶如果船体之间有明显间隙分别标注如果紧贴无法区分合并为一个框并在属性中标记“多船”。对于部分被云层遮挡的船舶如果可见部分超过船体面积的60%标注并标记“部分遮挡”低于60%则不标注避免引入噪声。小目标短边小于10像素单独标记为“小目标”属性训练时可通过过采样增强。标注工具推荐用LabelImg或CVAT导出格式统一为YOLO格式。下面是一个标注文件示例和对应的类别映射表。# 类别映射表dataset.yaml # 路径根据实际存放位置修改 path: ./ship_dataset train: images/train val: images/val test: images/test names: 0: cargo_ship # 货船长度100米 1: fishing_boat # 渔船长度50米 2: warship # 军舰含航母、驱逐舰 3: small_boat # 小艇长度10米 4: partial_ship # 部分遮挡船舶# YOLO格式标注文件示例image_001.txt # 格式class_id x_center y_center width height归一化到0-1 # 以下为一条货船和一条渔船 0 0.4523 0.6712 0.0821 0.0345 1 0.7834 0.2198 0.0456 0.0189参数说明x_center和y_center是边界框中心点相对于图像宽高的比例width和height是边界框宽高相对于图像宽高的比例。归一化操作必须在标注时完成否则训练时YOLO会报错。类别ID从0开始连续编号不能跳号。如果后续要合并类别直接修改names映射并重新生成标注文件即可。2.4 数据增强策略针对遥感船舶的几何与光度变换遥感影像的船舶检测数据增强不能照搬通用策略。水平翻转和垂直翻转是安全的因为卫星视角下船舶朝向没有绝对上下之分。旋转增强要谨慎0-180度随机旋转可以但旋转后要同步调整标注框且旋转角度不宜过大导致船舶宽高比失真。马赛克增强Mosaic对遥感小目标很有效把4张图拼成1张能增加小目标在单张图中的出现次数。但要注意拼接边界处如果正好切到船舶会产生不完整的标注框需要在增强后过滤掉面积小于原面积30%的框。光度变换方面随机调整亮度和对比度可以模拟不同光照和云影但色调变换要限制在±10%以内因为海面颜色是重要判别特征。下面是一个基于Albumentations的增强管道配置。import albumentations as A transform A.Compose([ A.HorizontalFlip(p0.5), A.VerticalFlip(p0.5), A.RandomRotate90(p0.5), A.Rotate(limit45, p0.3, border_mode0), A.RandomBrightnessContrast(brightness_limit0.2, contrast_limit0.2, p0.5), A.HueSaturationValue(hue_shift_limit10, sat_shift_limit15, val_shift_limit10, p0.3), A.Mosaic(p0.5, grid_size(2, 2)), # 需自定义实现或使用YOLO内置 ], bbox_paramsA.BboxParams(formatyolo, min_area100, min_visibility0.3))逻辑说明min_area100过滤掉增强后面积过小的框min_visibility0.3过滤掉被裁剪掉超过70%的框。Rotate的border_mode0表示用黑色填充边界避免引入虚假纹理。Mosaic增强在YOLOv8中已内置只需在训练配置中设置mosaic1.0即可不需要在Albumentations中重复实现。3. 从原始影像到YOLOv8可训练数据集的完整操作流程3.1 影像切片大图裁小与重叠率设置高分辨率遥感影像单张动辄上万像素直接送入网络不现实。必须切片成512×512或1024×1024的小图。切片时有两个关键参数切片尺寸和重叠率。切片尺寸取决于目标尺度如果船舶目标短边普遍在20-100像素用512×512切片目标占比4%-20%适合YOLOv8的P3-P5特征层。如果目标更小10-30像素用1024×1024切片并配合更密集的锚框。重叠率一般设20%-30%目的是避免船舶正好落在切片边界被截断。重叠率太低边界目标丢失太高重复样本过多导致训练过拟合。我一般用25%重叠即步长切片尺寸×0.75。下面是一个切片脚本。import cv2 import os import numpy as np def slice_image(image_path, output_dir, slice_size512, overlap0.25): img cv2.imread(image_path) h, w img.shape[:2] stride int(slice_size * (1 - overlap)) count 0 for y in range(0, h, stride): for x in range(0, w, stride): # 确保切片不超出边界 y1 min(y slice_size, h) x1 min(x slice_size, w) y0 max(0, y1 - slice_size) x0 max(0, x1 - slice_size) patch img[y0:y1, x0:x1] if patch.shape[0] slice_size or patch.shape[1] slice_size: patch cv2.copyMakeBorder(patch, 0, slice_size-patch.shape[0], 0, slice_size-patch.shape[1], cv2.BORDER_CONSTANT, value(0,0,0)) out_name f{os.path.splitext(os.path.basename(image_path))[0]}_{count:04d}.jpg cv2.imwrite(os.path.join(output_dir, out_name), patch) count 1 return count参数说明slice_size根据GPU显存和目标尺度选8G显存建议51216G以上可以1024。overlap0.25表示相邻切片有25%区域重叠。copyMakeBorder用于处理边缘不足一个切片的情况用黑色填充训练时这些黑色区域不会产生有效梯度但能保证输入尺寸一致。切片后需要同步处理标注文件根据切片在原图中的坐标偏移重新计算每个标注框在新切片中的归一化坐标超出切片边界的框按可见比例决定是否保留。3.2 标注格式转换从LabelImg XML到YOLO TXTLabelImg默认输出Pascal VOC格式的XML文件需要转成YOLO的TXT格式。转换时注意三点坐标归一化、类别ID映射、边界框裁剪。下面是一个批量转换脚本。import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_dir, output_dir, class_map): if not os.path.exists(output_dir): os.makedirs(output_dir) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] bbox obj.find(bndbox) xmin max(0, float(bbox.find(xmin).text)) ymin max(0, float(bbox.find(ymin).text)) xmax min(img_w, float(bbox.find(xmax).text)) ymax min(img_h, float(bbox.find(ymax).text)) if xmax xmin or ymax ymin: continue x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) out_file os.path.join(output_dir, xml_file.replace(.xml, .txt)) with open(out_file, w) as f: f.write(\n.join(lines)) class_map {cargo_ship: 0, fishing_boat: 1, warship: 2, small_boat: 3, partial_ship: 4} voc_to_yolo(./annotations_xml, ./labels_yolo, class_map)逻辑说明class_map必须与dataset.yaml中的names顺序一致。坐标裁剪确保框不超出图像边界。归一化保留6位小数精度足够。如果标注文件中有旋转框OBB需要额外处理角度信息YOLOv8-OBB格式为class_id x_center y_center width height angle转换时需从XML中读取robndbox节点。3.3 数据集划分与YOLOv8训练配置数据集按7:2:1划分训练集、验证集、测试集。划分时要保证同一区域、同一时相的影像不跨集否则验证集精度虚高。比如同一景影像切片出的多张小图必须全部放在同一个集合。下面是一个划分脚本和YOLOv8训练命令。import os import random import shutil def split_dataset(image_dir, label_dir, output_dir, ratios(0.7, 0.2, 0.1)): images [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.shuffle(images) n len(images) n_train int(n * ratios[0]) n_val int(n * ratios[1]) splits { train: images[:n_train], val: images[n_train:n_trainn_val], test: images[n_trainn_val:] } for split, files in splits.items(): img_out os.path.join(output_dir, images, split) lbl_out os.path.join(output_dir, labels, split) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for f in files: shutil.copy(os.path.join(image_dir, f), os.path.join(img_out, f)) lbl f.replace(.jpg, .txt) if os.path.exists(os.path.join(label_dir, lbl)): shutil.copy(os.path.join(label_dir, lbl), os.path.join(lbl_out, lbl)) split_dataset(./sliced_images, ./labels_yolo, ./ship_dataset)# YOLOv8训练命令 yolo detect train \ data./ship_dataset/dataset.yaml \ modelyolov8s.pt \ epochs200 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ mosaic1.0 \ mixup0.1 \ copy_paste0.1 \ degrees45 \ translate0.1 \ scale0.5 \ fliplr0.5 \ flipud0.5 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4 \ patience50 \ device0参数说明imgsz640是输入尺寸如果切片是512可以设为512以节省显存。batch16根据显存调整8G显存用816G用16。lr0初始学习率0.01lrf最终学习率因子0.01即最终学习率0.01×0.010.0001。mosaic1.0表示始终启用马赛克增强最后10个epoch建议关闭以稳定收敛。copy_paste0.1对小目标船舶有效但需要分割掩码如果只有检测框则设为0。patience50表示50个epoch验证集mAP不提升则早停。device0指定第一块GPU。4. 船舶检测数据集构建中的避坑与排查清单4.1 标注框包含尾迹导致模型学偏现象训练loss正常下降但验证集mAP卡在0.3左右可视化预测结果发现模型把浪花和尾迹也框进去了。原因标注时图省事把船体和尾迹一起框了模型学到“长条形白色泡沫船”。解决重新标注严格按船体轮廓框尾迹和浪花不标注。如果尾迹与船体难以区分用分割标注替代检测框先分割船体再转检测框。排查方法随机抽100个标注框统计宽高比分布如果大量框的宽高比超过8:1大概率包含了尾迹。4.2 切片重叠率不足导致边界目标丢失现象训练集mAP很高但测试时港口边缘的船舶漏检严重。原因切片时重叠率设了10%船舶正好落在切片边界一半在A切片一半在B切片两个切片中的标注框都不完整模型学不到完整船舶特征。解决重叠率提高到25%-30%并在切片后检查每个标注框的可见面积低于原面积60%的框直接丢弃避免不完整样本进入训练集。排查方法统计训练集中标注框的宽高分布如果出现大量异常小的框短边5像素可能是边界截断导致的。4.3 类别不平衡导致小类别召回率极低现象货船和渔船检测效果很好但军舰和小艇的召回率不到0.2。原因数据集中货船样本占80%军舰和小艇各占5%模型偏向多数类。解决三种策略组合使用过采样小类别复制小类别样本2-3倍、类别加权损失YOLOv8中通过cls_pw参数调整但官方未直接暴露可修改损失函数、马赛克增强中强制包含小类别。排查方法训练前统计每个类别的实例数如果最大类别与最小类别比例超过10:1必须做平衡处理。4.4 验证集与训练集同源导致精度虚高现象验证集mAP达到0.85但部署到新区域影像上mAP只有0.4。原因划分数据集时随机打乱同一景影像的切片同时出现在训练集和验证集模型记住了背景纹理而非船舶特征。解决按影像景号或地理区域划分同一景影像的所有切片只进一个集合。如果数据来自多个港口按港口划分留一个港口做测试。排查方法检查训练集和验证集的影像文件名前缀如果有相同前缀说明同源。4.5 归一化坐标计算错误导致框偏移现象训练时loss震荡不收敛可视化标注框发现框整体偏移或尺寸不对。原因VOC转YOLO时xmin/ymin/xmax/ymax的顺序搞反或者除以了错误的宽高。解决转换后随机抽10张图用OpenCV画出标注框与原图叠加肉眼检查框是否贴合船体。排查方法写一个校验脚本检查所有标注文件的坐标是否在0-1范围内宽高是否大于0。import os def validate_yolo_labels(label_dir): errors [] for f in os.listdir(label_dir): if not f.endswith(.txt): continue with open(os.path.join(label_dir, f)) as file: for i, line in enumerate(file): parts line.strip().split() if len(parts) ! 5: errors.append(f{f} line {i}: 字段数不对) continue cls_id, x, y, w, h parts vals [float(x), float(y), float(w), float(h)] if any(v 0 or v 1 for v in vals): errors.append(f{f} line {i}: 坐标超出0-1范围) if float(w) 0 or float(h) 0: errors.append(f{f} line {i}: 宽高非正) return errors errors validate_yolo_labels(./labels_yolo) for e in errors[:20]: print(e) print(f总错误数: {len(errors)})5. 用mAP与混淆矩阵验证数据集质量以及一个提升小目标召回率的技巧数据集建好后不要急着调模型先用YOLOv8的验证命令跑一遍基线看mAP和混淆矩阵。命令很简单yolo detect val data./ship_dataset/dataset.yaml modelruns/detect/train/weights/best.pt imgsz640 batch16。重点看三个指标mAP50、mAP50-95、每个类别的AP。如果某个类别AP低于0.3先别改模型回去查该类别的标注质量和样本数量。混淆矩阵能看出类别混淆情况比如渔船和小艇容易混说明两个类别的尺度重叠严重考虑合并或重新定义边界。提升小目标召回率的一个实用技巧是在验证集上统计漏检目标的尺寸分布如果漏检集中在短边20像素的目标可以在训练时把imgsz从640提到1280同时把batch减半。YOLOv8支持多尺度训练设置imgsz640,1280会让模型在两种尺度间随机切换小目标在1280尺度下特征更清晰。但注意imgsz1280时显存占用是640的4倍8G显存跑不动需要16G以上。另一个技巧是修改锚框尺寸YOLOv8默认锚框基于COCO最小锚框对应8×8像素遥感小目标可能只有4×4需要重新聚类锚框。用k-means对训练集标注框的宽高聚类得到适合自己数据集的锚框替换模型配置文件中的anchors参数。我自己的习惯是每建完一个数据集先跑50个epoch的快速训练看mAP曲线和混淆矩阵确认数据集没有硬伤再投入长时间训练。这个习惯帮我省下了至少三次“训练三天发现标注全错”的血泪教训。数据集的质量决定了模型的上限模型调参只能逼近这个上限永远无法突破。希望帮到你。本文还有配套的精品资源点击获取
返回列表