目标检测之YoloV5+旋转目标
写在前面
2023年的某一天,记录过一个有关于活虾检测的数据预处理文章:利用虾检测模型检测图像生成的txt转成roLabelImg需要的xml,有兴趣的可以去看看那些密密麻麻的虾子。当时拿到这些图片的第一想法是这视角不就是无人机视角吗,那么该用什么样的方法去实现这种视角下的虾子的检测?刚好看了这个系列的文章:自己改建YOLOv5旋转目标的踩坑记录,才知道可以用旋转目标的方法来解决这样的问题,对此对大佬感激不尽,因此也借用了大佬的开源代码:Yolov5_obb,做了一个虾子检测。
当然,效果并没有很好,原因有很多,不一一描述,在这篇文章里面,主要是简单介绍一下我在实现过程中的一些理解,如有问题,请多多指教。
1. YoloV5
YoloV5作为单阶段目标检测算法的代表,以其高效和精度著称。其核心思想是将目标检测视为回归问题,通过单个神经网络直接从完整图像预测边界框和类别概率。现在的yolo版本已经到了11了,在这个系列里面,v5并不是最好的,但是业内很多人都觉得这个版本是比较经典的一个版本,后续的很多个版本迭代都是在这个基础上进行修改,因此选择用V5来描述。原理就不说了,可以研读一下yolo论文和其他详解。
1.1 主要亮点
(1)输入端:Mosaic数据增强:提升小目标检测能力(通过密集目标场景模拟),增强模型对目标遮挡的鲁棒性,减少GPU显存消耗(4图合1训练)、自适应锚框计算:自动适配不同数据集的物体尺度分布,相比手动设定提升3-5% mAP,支持动态调整(训练中可二次优化)、自适应图片缩放:减少无效像素计算(相比直接拉伸),保持目标几何特征不变形,推理速度提升约15%。
(2)Backbone:Focus结构:下采样无信息丢失(传统卷积有信息损失),计算量减少约30%,保持高分辨率特征。CSP结构: 梯度分流解决梯度重复问题,内存占用降低20%,增强特征融合能力。
(3)Neck:FPN+PAN结构:多尺度特征融合(3-5个不同尺度),小目标检测精度提升8-12%,双向特征传播路径。
(4)Prediction network:GIOU Loss:解决非重叠框梯度消失问题, 收敛速度提升约2倍, 框回归精度提高5-8%。
看到这些亮点,从密集小目标,尺度,显存内存上的优化,推理性能的优化,似乎很符合做虾子检测的需求。
2. 旋转目标检测改进点
2.1 主要区别
特性 | 原始YoloV5 | YoloV5-OBB |
---|---|---|
框表示 | 水平矩形(x,y,w,h) | 旋转矩形(x,y,w,h,θ) |
标签格式 | 类别+4点坐标 | 类别+8点坐标或5参数 |
数据增强 | 水平翻转为主 | 支持旋转增强 |
损失函数 | GIoU/CIoU | 旋转IoU |
输出维度 | 4+1+nc | 5+1+nc+角度分类数 |
2.2 关键代码改动
数据加载部分
标注格式 :
- 支持多边形标注(8个点)或旋转框标注(5个参数)
- 标签文件格式: class_id x1 y1 x2 y2 x3 y3 x4 y4(事实上我提供的是 x1 y1 x2 y2 x3 y3 x4 y4 class_id )
详细代码还是见开源的源码中yolov5_obb/utils/datasets.py和yolov5_obb\utils\rboxs_utils.py
# 多边形转旋转框的核心函数
def poly2rbox(polys, num_cls_thata=180, radius=6.0, use_pi=True, use_gaussian=True):
# 将多边形转换为旋转框[cx, cy, w, h, angle]
# 并生成角度的高斯分布标签
...
角度损失计算部分
在YOLOv5-OBB旋转目标检测代码中,损失函数主要在ComputeLoss
类中实现,在这里,只关注角度损失函数。具体来说:
- 角度损失初始化:
# 在__init__中初始化角度损失函数
BCEtheta = nn.BCEWithLogitsLoss(pos_weight=torch.tensor([h['theta_pw']], device=device))
if g > 0: # 如果启用了Focal Loss
BCEtheta = FocalLoss(BCEtheta, g) # 使用Focal Loss包装
self.BCEtheta = BCEtheta # 保存为成员变量
- 角度损失计算:
# 在__call__方法中计算角度损失
class_index = 5 + self.nc # 分类分支结束位置
t_theta = tgaussian_theta[i].type(ps.dtype) # 获取目标角度的高斯分布标签
ltheta += self.BCEtheta(ps[:, class_index:], t_theta) # 计算角度损失
- 角度损失特点:
- 使用**Circular Smooth Label (CSL)**方法将角度预测转化为分类问题
- 采用BCEWithLogitsLoss作为基础损失函数
- 支持Focal Loss处理类别不平衡
- 角度值通过高斯分布编码,预测的是角度分布而非直接回归角度值
- 损失整合:
# 最终将角度损失与其他损失加权求和
ltheta *= self.hyp['theta'] # 应用角度损失权重
total_loss = (lbox + lobj + lcls + ltheta) * bs # 总损失
角度损失的特点:
- 使用BCEWithLogitsLoss作为基础损失函数
- 支持Focal Loss处理类别不平衡
- 角度值通过高斯分布编码,预测的是角度分布而非直接回归角度值
- 最终损失是各损失项的加权和:
total_loss = (lbox + lobj + lcls + ltheta) * bs
3. 旋转目标
3.1 旋转框表示方法
采用五参数表示法:[cx, cy, w, h, θ]
,其中:
cx, cy
:旋转框中心坐标w, h
:框的宽度和高度θ
:旋转角度(弧度制),范围[-π/2, π/2)
# 五参数表示法 [cx, cy, w, h, θ]
def poly2rbox(polys, num_cls_thata=180, radius=6.0, use_pi=False, use_gaussian=False):
# θ∈[-pi/2, pi/2) 或 [0,180) 两种模式
(x,y), (w,h), angle = cv2.minAreaRect(poly)
theta = angle / 180 * pi # 弧度制转换
return [x, y, w, h, theta] if use_pi else [x, y, w, h, angle]
3.2 角度编码方式
- CSL编码(Circular Smooth Label):
- 将连续角度离散化为分类问题
- 使用圆形平滑标签缓解类别不平衡
- 每个角度类别用高斯分布表示相邻角度关系
def gaussian_label_cpu(label, num_class, u=0, sig=4.0):
"""
转换成CSL Labels:
用高斯窗口函数根据角度θ的周期性赋予gt labels同样的周期性,使得损失函数在计算边界处时可以做到“差值很大但loss很小”;
并且使得其labels具有环形特征,能够反映各个θ之间的角度距离
Args:
label (float32):[1], theta class
num_theta_class (int): [1], theta class num
u (float32):[1], μ in gaussian function
sig (float32):[1], σ in gaussian function, which is window radius for Circular Smooth Label
Returns:
csl_label (array): [num_theta_class], gaussian function smooth label
"""
x = np.arange(-num_class/2, num_class/2)
y_sig = np.exp(-(x - u) ** 2 / (2 * sig ** 2))
index = int(num_class/2 - label)
return np.concatenate([y_sig[index:],
y_sig[:index]], axis=0)
- 高斯编码:
- 使用高斯分布表示角度不确定性
- 更精细的角度表示能力
4. 旋转目标检测的优点
-
更精确的定位:
- 旋转框能更紧密地贴合倾斜目标
- 减少背景区域的误检
- 对于长宽比较大的目标(如车辆、船舶)效果尤为明显
-
更高的IoU:
- 对于密集排列的倾斜目标(如遥感图像中的车辆)
- 旋转框IoU比水平框平均提高15-30%
- 减少同一目标被多次检测的情况
-
更广的应用场景:
- 遥感图像分析:飞机、船舶检测、无人机
- 文档分析:文字检测与识别
- 自动驾驶:道路标志检测
- 工业检测:零件定位与缺陷检测
5. 总结
YoloV5-OBB通过引入旋转框检测能力,显著提升了模型在倾斜目标场景下的检测性能。其核心改进包括旋转框表示、角度编码策略和旋转IoU计算等。虽然带来了一定的计算开销,但在需要精确检测旋转目标的场景下,这种改进是非常有价值的。未来,随着硬件加速和算法优化的进步,旋转目标检测技术将在更多领域得到广泛应用。