YOLOv8 OBB 旋转目标检测模型详解与实践

引言

在计算机视觉领域,目标检测是至关重要的任务之一。YOLO(You Only Look Once)系列算法因其高效性和准确性而广受欢迎。YOLOv8 作为稳定版本,在目标检测领域取得了显著成果,依旧能打。本文将深入探讨 YOLOv8 OBB(Oriented Bounding Box,定向边界框) 模型的结构、损失函数、关键代码以及如何进行自定义 OBB 对象检测的完整流程。


在开始之前,弥补上节YOLOV8不同精度模型解析:

旋转对象模型 OBB

1. 旋转对象检测模型结构拆解

YOLOv8 OBB 模型的结构主要分为两个部分:BackboneHead。其中:

以YOLOV8n为例

Backbone 部分
  • 使用 C2f(Cross Convolutional Layer)SPPF(Spatial Pyramid Pooling - Fast) 等模块来增强特征提取能力。
  • 通过多次卷积和下采样操作,逐步提取图像的高级特征。
Head 部分
  • 包含了上采样、Concat 操作以及 C2f 模块,用于融合不同层级的特征。
  • 最终通过 OBB 模块生成定向边界框的预测。

2. 旋转对象损失函数

YOLO OBB 模型使用了三种主要的损失函数:cls(分类)、box(边界框)和 df1(分布焦点损失)

Cls - BCE(Binary Cross Entropy)
  • 用于分类任务,衡量预测类别与真实类别之间的差异。
Box - ProbIOU
  • 衡量预测边界框与真实边界框之间的 IOU(Intersection over Union),并结合概率进行损失计算。

论文地址:https://arxiv.org/pdf/2106.06072v1.pdf

1. 数据准备

进行自定义 OBB 目标检测的第一步是准备数据集,数据集应包含图像文件和对应的标签文件。

OBB 数据集格式
  • YOLO OBB 格式通过 四个角点 指定边界框,其坐标在 0 和 1 之间归一化。
  • 标签文件格式如下:
class_index, x1, y1, x2, y2, x3, y3, x4, y4

2. 模型训练与测试

使用准备好的数据集,可以开始模型的训练过程。

训练命令
yolo obb train data=pen_dataset.yaml model=yolov8s-obbb.pt epochs=25 imgsz=640
测试命令
yolo obb predict model=yolov8n-obbb.pt source=plane_03.jpg

3. 模型导出与推理

训练完成后,可以将模型导出为 ONNX 格式,以便在其他平台进行部署。

导出命令
yolo export model=yolov8s-obbb.pt format=onnx
推理格式
  • 输入格式NCHW=1x3x640x640
  • 输出格式1x6x8400,包含 xywhcr(中心坐标、宽度、高度、旋转角度和置信度)信息。

数据标注与说明

1. 标注工具

为了生成符合 YOLO OBB 格式的标签文件,需要使用专门的标注工具,例如:

  • LabelImg
  • Roboflow
  • CVAT

2. 数据集生成

通过编写代码,可以将标注好的数据转换为 YOLO OBB 格式,包括:

  • 统一不同格式的标注数据。
  • 进行数据增强,如旋转、缩放、裁剪等。

3. 旋转矩阵

在处理旋转目标时,旋转矩阵 是必不可少的。通过旋转矩阵,可以将原始坐标转换为旋转后的坐标,从而准确表示目标的位置和方向。

不同旋转的标注格式:


模型推理与部署

1. 输入输出格式

进行模型推理时,需要明确输入和输出格式:

  • 输入格式1x3x640x640 的张量,NCHW=1x3x640x640
  • 输出格式:包含检测到目标的 边界框信息,1x6x8400。 
  • xywhcr 只有一个类别

2. 部署实践

模型部署到实际应用时,需要考虑性能优化兼容性,可以采用:

  • 量化(Quantization):减少计算量,提高推理速度。
  • 剪枝(Pruning):去除冗余权重,优化模型大小。

3.旋转中心-角度正负

•选择中心,角度R旋转旋转矩阵

•得到四个点坐标

旋转检测pen的demo代码如下:

import cv2 as cv
import time
import numpy as np
from openvino.runtime import Core


def get_rotate_point(curr_pts, M, d1, box):
    rpts = []
    M[:, :] = 0
    alpha = np.cos(d1)
    beta = np.sin(d1)
    M[0, 0] = alpha
    M[1, 1] = alpha
    M[0, 1] = beta
    M[1, 0] = -beta
    cx = box[0] + box[2] / 2
    cy = box[1] + box[3] / 2
    tx = (1 - alpha) * cx - beta * cy
    ty = beta * cx + (1 - alpha) * cy
    M[0, 2] = tx
    M[1, 2] = ty
    for pt in curr_pts:
        x0 = pt[0];
        y0 = pt[1];
        x = M[0, 0] * x0 + M[0, 1] * y0 + M[0, 2];
        y = M[1, 0] * x0 + M[1, 1] * y0 + M[1, 2];
        rpts.append((x, y))
    return rpts


def format_yolov8(frame):
    row, col, _ = frame.shape
    _max = max(col, row)
    result = np.zeros((_max, _max, 3), np.uint8)
    result[0:row, 0:col] = frame
    return result


def post_process(rows):
    class_ids = []
    confidences = []
    boxes = []
    angles = []
    x_factor = img_w / 640
    y_factor = img_h / 640

    for r in range(rows.shape[0]):
        row = rows[r]
        classes_scores = row[4:5]
        _, _, _, max_indx = cv.minMaxLoc(classes_scores)
        class_id = max_indx[1]
        if (classes_scores[class_id] > .25):
            angles.append(row[5])
            confidences.append(classes_scores[class_id])
            class_ids.append(class_id)
            x, y, w, h = row[0].item(), row[1].item(), row[2].item(), row[3].item()
            left = int((x - 0.5 * w) * x_factor)
            top = int((y - 0.5 * h) * y_factor)
            width = int(w * x_factor)
            height = int(h * y_factor)
            box = np.array([left, top, width, height])
            boxes.append(box)
    return boxes, confidences, angles, class_ids


class_list = ["pen"]
colors = [(255, 255, 0), (0, 255, 0), (0, 255, 255), (255, 0, 0)]

ie = Core()
for device in ie.available_devices:
    print(device)

# Read IR
model = ie.read_model(model=pen_obb_best.onnx)
compiled_model = ie.compile_model(model=model, device_name="CPU")
output_layer = compiled_model.output(0)

## xywhr
frame = cv.imread(code/four_pen.jpg)
bgr = format_yolov8(frame)
img_h, img_w, img_c = bgr.shape

start = time.time()
image = cv.dnn.blobFromImage(bgr, 1 / 255.0, (640, 640), swapRB=True, crop=False)

res = compiled_model([image])[output_layer] # 1x25x8400
rows = np.squeeze(res, 0).T
boxes, confidences, angles, class_ids = post_process(rows)

indexes = cv.dnn.NMSBoxes(boxes, confidences, 0.25, 0.45)
M = np.zeros((2, 3), dtype=np.float32)
for index in indexes:
    box = boxes[index]
    d1 = -angles[index]
    color = colors[int(class_ids[index]) % len(colors)]
    pts = [(box[0], box[1]), (box[0]+box[2], box[1]), (box[0]+box[2], box[1]+box[3]), (box[0], box[1]+box[3])]
    rrt_pts = get_rotate_point(pts, M, d1, box)
    cv.drawContours(frame, [np.asarray(rrt_pts).astype(np.int32)], 0, (255, 0, 255), 2)
    cv.putText(frame, class_list[class_ids[index]], (int(box[0]+box[2]/2), int(box[1]+box[3]/2)), cv.FONT_HERSHEY_SIMPLEX, 1.0, (0, 0, 255), 2)

end = time.time()
inf_end = end - start
fps = 1 / inf_end
fps_label = "FPS: %.2f" % fps
cv.putText(frame, fps_label, (20, 45), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

cv.imshow("YOLOv8-OBB Rotate Object Detection", frame)
cv.imwrite("D:/pen_result.jpg", frame)

# 新增自动退出逻辑
while True:
    # 检查窗口是否关闭
    if cv.getWindowProperty("YOLOv8-OBB Rotate Object Detection", cv.WND_PROP_VISIBLE) < 1:
        break
    # 检查是否按下q键
    if cv.waitKey(1) & 0xFF == ord('q'):
        break

cv.destroyAllWindows()

测试结果如图所示:


总结

本文详细介绍了 YOLOv8 OBB 模型的结构、损失函数、关键代码以及 自定义 OBB 目标检测 的完整流程。旨在深入理解 YOLOv8 OBB 的工作原理,并应用到实际旋转目标检测任务中。


未来展望

随着计算机视觉技术的发展,旋转目标检测在 无人机监测、遥感图像分析 等领域有广阔的应用前景。YOLOv8 OBB 作为高效检测工具,将在这些领域发挥重要作用。欢迎继续交流!😊🚀


### 使用YOLOv8进行带有旋转框(OBB)的目标检测训练 #### 修改配置文件 为了适应特定的数据集,在`ultralytics\ultralytics\cfg\models\v8`路径下的`yolov8-obb.yaml`需要被调整。主要改动在于设置类别的数量(`nc`)以及对应的名称映射,这一步骤对于确保模型能够识别自定义数据集中不同类型的对象至关重要[^3]。 ```yaml # yolov8-obb.yaml snippet nc: 4 # 类别数目 names: 0: ture 1: ban 2: man 3: di ``` 此外,还需编辑位于`yolov8/ultralytics/data/converter.py`中的代码片段来适配个人项目的标签体系,比如更新`class_mapping`字段以反映新的分类标准。 #### 加载预训练权重构建模型实例 当准备就绪后,可以通过Python脚本加载YOLOv8 OBB版本的预训练权重或基于YAML描述新建一个未经过预先学习过程的新模型: ```python from ultralytics import YOLO model = YOLO('yolov8n-obb.pt') # 载入已有的预训练模型(推荐用于继续训练) # 或者 model = YOLO('yolov8n-obb.yaml').load('yolov8n.pt') # 根据模板创建并迁移旧版参数 ``` 上述两种方式均可实现模型初始化;其中一种方法是从官方提供的基础架构出发建立全新的网络结构而后赋予初始权值,另一种则是直接利用现有的高质量预训练成果作为起点[^2]。 #### 启动训练进程 最后,通过调用`.train()`函数指定必要的超参数如迭代轮次(`epochs`)、输入图像尺寸(`imgsz`)等,并提供指向数据集元信息(.yaml)的具体位置即可启动整个训练流程: ```python results = model.train( data='/home/user/path/to/dataset/config.yaml', epochs=100, imgsz=640 ) ``` 此命令会依据给定条件自动完成从读取样本到优化直至保存最终结果的一系列操作,期间产生的日志记录有助于监控进度和性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值