1. 为什么需要旋转目标检测在传统的目标检测任务中我们通常使用水平矩形框axis-aligned bounding box来标注物体。但实际场景中很多物体是倾斜或旋转的比如遥感图像中的飞机、停车场里的车辆、航拍图像中的建筑物等。这时候如果强行用水平框标注会引入大量背景噪声影响检测精度。YOLOv8 OBBOriented Bounding Box就是为了解决这个问题而生。它允许我们使用旋转矩形框来更精确地标注物体特别适合处理倾斜物体的检测任务。比如在DOTA数据集中飞机、船只等目标通常以各种角度出现使用旋转框能显著提升检测效果。2. 环境准备与项目部署2.1 基础环境配置我强烈建议使用conda创建独立的Python环境避免依赖冲突。这是我常用的配置命令conda create -n yolov8_obb python3.8 conda activate yolov8_obb pip install torch torchvision --extra-index-url https://download.pytorch.org/whl/cu118 # 根据CUDA版本调整2.2 安装Ultralytics库官方推荐直接从源码安装最新版git clone https://github.com/ultralytics/ultralytics cd ultralytics pip install -e . # 可编辑模式安装如果下载慢可以换用国内镜像源pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -e .3. 理解OBB数据格式3.1 YOLOv8 OBB标注规范YOLOv8 OBB要求的标注格式为class_id x1 y1 x2 y2 x3 y3 x4 y4其中四个点(x,y)按顺时针或逆时针顺序排列坐标值是归一化后的0-1之间不需要标注旋转角度模型会从四个点自动学习3.2 常见数据格式转换很多公开数据集如DOTA使用不同的标注格式。比如DOTA原始标注是x1 y1 x2 y2 x3 y3 x4 y4 class_name difficult我们需要去掉最后的difficult标记并将类别名称转换为数字ID。4. 实战构建自定义数据集4.1 数据检查脚本优化原始文章的数据检查脚本已经很实用我做了些增强def validate_dataset(img_dir, label_dir, img_ext.jpg, label_ext.txt): 增强版数据校验 img_files {f.replace(img_ext, ) for f in os.listdir(img_dir) if f.endswith(img_ext)} label_files {f.replace(label_ext, ) for f in os.listdir(label_dir) if f.endswith(label_ext)} # 找出不匹配的文件 missing_labels img_files - label_files missing_images label_files - img_files if missing_labels: print(f警告{len(missing_labels)}张图片缺少对应标注) if missing_images: print(f错误{len(missing_images)}个标注文件没有对应图片) return False # 检查标注内容 for label_file in label_files: with open(os.path.join(label_dir, f{label_file}{label_ext})) as f: for line in f: parts line.strip().split() if len(parts) ! 9: # 检查OBB格式 print(f错误{label_file}中存在格式不正确的行) return False return True4.2 坐标归一化处理这是最容易出错的部分。我改进的转换函数增加了错误处理def convert_to_yolo_obb(src_label, dst_label, img_path): 带错误处理的OBB转换 try: img Image.open(img_path) w, h img.size except Exception as e: print(f无法打开图片{img_path}: {str(e)}) return False with open(src_label) as src, open(dst_label, w) as dst: for line in src: parts line.strip().split() if len(parts) 8: # 至少需要8个坐标值 continue try: coords [float(x) for x in parts[:8]] # 归一化处理 normalized [ format(coords[i]/w, .6f) if i%20 else format(coords[i]/h, .6f) for i in range(8) ] # 写入转换后的标注 dst.write(f{class_mapping[parts[-1]]} { .join(normalized)}\n) except Exception as e: print(f转换错误{line.strip()} - {str(e)}) return True5. 数据集划分策略5.1 智能数据集划分原始文章使用了随机划分但对于小数据集我推荐分层抽样def stratified_split(img_dir, label_dir, output_dir, ratios(0.7, 0.2, 0.1)): 按类别比例划分数据集 # 先统计每个类别的样本数 class_counts defaultdict(int) for label_file in os.listdir(label_dir): with open(os.path.join(label_dir, label_file)) as f: for line in f: class_id int(line.split()[0]) class_counts[class_id] 1 # 按类别组织文件列表 class_files defaultdict(list) for img_file in os.listdir(img_dir): base_name os.path.splitext(img_file)[0] label_file f{base_name}.txt with open(os.path.join(label_dir, label_file)) as f: classes {int(line.split()[0]) for line in f} for cls in classes: class_files[cls].append((img_file, label_file)) # 按比例划分 train_set, val_set, test_set [], [], [] for cls, files in class_files.items(): n len(files) train_end int(n * ratios[0]) val_end train_end int(n * ratios[1]) random.shuffle(files) train_set.extend(files[:train_end]) val_set.extend(files[train_end:val_end]) test_set.extend(files[val_end:]) # 保存划分结果 copy_files(train_set, os.path.join(output_dir, train)) copy_files(val_set, os.path.join(output_dir, val)) copy_files(test_set, os.path.join(output_dir, test))6. 配置文件深度解析6.1 完整的YAML配置原始文章的yaml比较基础这是一个更完整的模板# yolov8_obb_dataset.yaml path: /path/to/dataset train: images/train val: images/val test: images/test # 关键参数 obb_format: xyxyxyxy # 指定OBB格式 angle: 0 # 角度表示方式0表示不特别处理 # 类别信息 names: 0: ship 1: airplane 2: storage-tank 3: baseball-diamond 4: tennis-court # 数据增强配置 augmentations: rotation: 45 # 允许旋转增强 hsv_h: 0.015 # 色调增强幅度 hsv_s: 0.7 # 饱和度增强幅度 hsv_v: 0.4 # 明度增强幅度7. 训练技巧与参数调优7.1 关键训练参数yolo obb train \ datayour_dataset.yaml \ modelyolov8x-obb.pt \ epochs300 \ imgsz1024 \ batch16 \ patience50 \ lr00.01 \ lrf0.01 \ weight_decay0.0005 \ fliplr0.5 \ mosaic1.0 \ mixup0.27.2 解决常见问题问题1损失不收敛检查标注是否正确归一化尝试减小学习率lr00.001增加warmup_epochs如10问题2OBB预测框不稳定增加box loss权重box7.5使用更大的输入尺寸imgsz1024减少旋转增强幅度rotation158. 模型验证与部署8.1 评估指标解读YOLOv8 OBB新增了mAP0.5:0.95:OBB - 主要评估指标mAP0.5:OBB - 宽松评估mAP0.75:OBB - 严格评估8.2 模型导出导出为ONNX格式时需特别注意yolo export modelyolov8x-obb.pt formatonnx imgsz640 opset12在部署时需要确保推理代码能正确处理OBB输出格式。我通常使用后处理代码def process_obb_output(pred, conf_thres0.25): 处理OBB预测结果 boxes pred[..., :8] # 获取8个坐标点 scores pred[..., 8] # 置信度 classes pred[..., 9] # 类别 # 过滤低置信度预测 keep scores conf_thres boxes boxes[keep] scores scores[keep] classes classes[keep] # 转换到原图坐标 boxes boxes * np.array([img_w, img_h] * 4) return np.concatenate([ boxes, scores[:, None], classes[:, None] ], axis1)在实际项目中我发现YOLOv8 OBB对旋转目标的检测效果比传统方法提升明显特别是在遥感图像分析任务中mAP能提升15-20%。不过要注意OBB训练需要更精确的标注数据标注成本会比普通矩形框高一些。