一、引言

1、旋转目标检测检测

旋转目标检测检测就是将具有旋转方向的目标检测出来,也就是需要检测目标的中心点、长宽、角度。在俯视图的目标检测中比较常见,如遥感图像目标检测、航拍图像目标检测等。(见下图旋转目标检测,图源论文RoI Transformer )

目标检测数据集猫狗 目标检测 transformer_目标检测数据集猫狗

2、旋转目标检测算法

目前多阶段里面性能较好的是RoI Transformer这个算法,本篇博客将详细分析此算法。 论文《Learning RoI Transformer for Oriented Object Detection in Aerial Images》 开源代码基于mmdetection。

3、RoI Transformer

先简要看一下RoI Transformer的介绍吧,移步这里见第三部分旋转目标检测。下面将从数据处理、网络结构、RoI Align三个方面进行介绍。

二、数据处理

常见的目标检测算法都是做的水平目标检测,预测目标的中心点、长宽就好了,那么旋转目标多了一个角度。对于不同的算法对于角度的定义不同,处理方式略微不同。下面主要介绍两种旋转目标检测角度定义的方式。

1、opencv旋转矩形角度定义方式

opencv在旋转矩形的时候,以X轴逆时针旋转θ角度得到宽边,表示旋转的角度,如图红色角度。因此所有的角度范围为[-90,0)

目标检测数据集猫狗 目标检测 transformer_计算机视觉_02

下面说下在用opencv如何得到旋转矩形的坐标及其角度。

img = cv2.imread('test.png') #读入rgb图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转化为灰度图
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#获取二进制图像
#通过二进制图像获得二进制区域的边界框
#cv2.RETR_EXTERNAL表示只检测外轮廓
#cv2.CHAIN_APPROX_NONE存储所有的轮廓点
#返回值:img_是将轮廓部分画出来;contours所有轮廓坐标;hierarchy 表示轮廓属性,如个数等,具体可以查下opencv API
img_, contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
max_contour = max(contours, key=len)
# 返回一个最小外接矩形 (x,y) (h,w),angle [-90,0)
rect = cv2.minAreaRect(max_contour)
#获得旋转矩形的四个顶点坐标
poly = cv2.boxPoints(rect)

2、RoI Transformer中旋转目标角度定义

论文中角度的定位范围是[-π,π],针对bbox坐标[[x1,x2,x3,x4],[y1,y2,y3,y4]],角度计算为θ=np.arctan2(-(x2-x1),(y2-y1)),具体的角度见论文配图(如下)。

目标检测数据集猫狗 目标检测 transformer_目标检测数据集猫狗_03


现在我们知道了角度的定义方式了,需要由八个顶点坐标计算中心点、长宽、θ这几个参数值。

(1)中心点计算

目标检测数据集猫狗 目标检测 transformer_对应点_04

(2)长宽计算

长宽计算在此论文中先将旋转框经过角度旋转之后得到水平框,然后计算水平框的x、y坐标的左右、上下极值,得到[minx, miny, maxx, maxy]四个坐标,再计算矩形的长宽值。

目标检测数据集猫狗 目标检测 transformer_目标检测数据集猫狗_05


由图斜框与水平(x轴)的夹角是θ,那么将此斜框逆时针旋转β角度得到水平框。显然可得β=90-θ(长的好看的人需要推导一下)。那么现在就可以根据θ和A’点坐标来计算旋转之后点A的坐标了。

为了看起来简单,以斜框的中心点画坐标轴(因为四个坐标都可以以中心点作为参考)

目标检测数据集猫狗 目标检测 transformer_对应点_06


设A’坐标[x’,y’],求A的坐标[x,y],设红直线的长度为d(即A与A’到中心的距离)

目标检测数据集猫狗 目标检测 transformer_目标检测_07

目标检测数据集猫狗 目标检测 transformer_对应点_08

3、RoI Transformer中标签处理过程

旋转矩形框标注一般都是四个点的八个坐标(x,y),由于标注过程中存在很多误差,很多时候标注的并不是矩形,而是不规则四边形(比如图像边缘区域、密集小目标),那么这个时候直接利用四个坐标去计算长宽、偏转角度是不合适的。在RoI Transformer中处理过程如下:
(1)由四个标注点得到四边形封闭mask(二值矩阵);
(2)opencv通过mask找到最小外接矩形的四个点坐标(见1、opencv旋转矩形角度定义方式);
(3)找到旋转矩形的最小外接水平矩形,计算旋转矩形与水平矩形的对应点(这个计算直接计算各对应点的距离,找到最小值);比如最小外接水平矩形四个点为(A1、A2、A3、A4),旋转矩形的四个顶点为(A1’、A2’、A3’、A4’);
目标检测数据集猫狗 目标检测 transformer_算法_09
其中目标检测数据集猫狗 目标检测 transformer_算法_10表示两个点的距离。
(4)这样找到了最佳对应点之后,再通过(2、RoI Transformer中旋转目标角度定义)得到旋转矩形的中心点、长宽、角度,即[cx,cy,w,h,θ]。
为什么要经过第3步找到旋转矩形与水平矩形的对应点呢?这里有两个原因:
(1)找到对应的起始点之后,计算θ就是一个确定值(2中角度计算方式目标检测数据集猫狗 目标检测 transformer_目标检测_11);
(2)找到旋转矩形与水平矩形最小的旋转角度,便于后续通过水平Anchor预测旋转矩形。

三、网络结构

网络结构部分整体类似一个cascade rcnn,过程是BackBone->RPN->rbbox1->rbbox2。

目标检测数据集猫狗 目标检测 transformer_目标检测数据集猫狗_12

1、Backbone特征提取(FPN略去)

这里用的ResNet系列网络,可以替换成ResNeXt、ResNeSt等Backbone。

2、经过RPN网络得到水平proposal

# RPN网络结构,rpn_conv表示共享层,然后分别进行cls和reg预测
rpn_conv = nn.Conv2d(in_channels, feat_channels, 3, padding=1) #共享层
rpn_cls = nn.Conv2d(feat_channels,num_anchors * cls_out_channels, 1) #cls,num_anchor表示同一层特征中同一个位置有几个Anchorc尺寸比例,一般是3(0.5,1,2)
rpn_reg = nn.Conv2d(feat_channels, num_anchors * 4, 1) # *4表示[delta_x,delta_y,delta_w,delya_h]

这个过程就是普通的RPN网络,将RPN网络中cls分支按照得分进行排序,取最高的前K个;然后得到这K个得分对应的bbox偏差预测(检测头输出结果),与对应的K个Anchor进行偏差回归得到K个预测框,然后再进行NMS。

3、由水平proposal经过RoI Align得到水平proposal的特征

就是普通的RoI Align,RoI Align详细讲解请看这个博客里面的Mask RCNN部分。

4、对proposal特征进行分类和回归得到旋转矩形框(rbbox1)

(1)回归输出五个值,包括中心点位置、长宽、角度,其中这里的角度是相对于水平proposal的旋转的角度(其实也就是ground truth的角度,因为proposal也是水平的,所以角度是一样的);
(2)回归的偏差计算如下:
目标检测数据集猫狗 目标检测 transformer_目标检测数据集猫狗_13
注意这里为什么中心坐标要乘以角度:目标检测数据集猫狗 目标检测 transformer_计算机视觉_14,而不是直接计算偏差目标检测数据集猫狗 目标检测 transformer_目标检测_15。这里还是需要看第二章里面数据处理中RoI Transformer中数据处理的方式,因为旋转目标的参考系并不是以图像为参考系,而是以预测目标为参考系的。因此,旋转目标下的x、y的偏移需要经过角度的偏差计算变换回到原图中x、y的大小。

5、由rbbox1经过RRoI Align得到旋转矩形框的特征;

这一过程看第四章节。

6、由rbbox1的特征,再次经过分类和回归头得到最终的旋转矩形rbbox2

这里的中心点、长宽、角度偏移都是相对于rbbox1的偏移,过程与RPN相对于rbbox1的过程一致。

四、RRoI Align(旋转RoI Align)

RRoI Align其实流程和RoI Align的流程是一样的,区别在于RoI Align的采样点是水平的和竖直方向的,而RRoI Align是对坐标进行角度偏移进行采样。

1、RoI Align

我们知道RoI Pooling通过取整在feature map上进行池化操作提取固定尺度的特征(比如7×7×C),但是这里有两次取整操作会导致误差较大。

(1)第一次取整是RPN的Proposal在映射到feature map进行取整;

(2)第二次取整是feature map映射到原图上时由于图像下采样导致坐标的偏差;

(3)这两次取整会导致像素点在特征图上的偏移很大,假如特征下采样32次,那么RoI Pooling就会导致32像素的偏差,对于小目标的检测极其不友好

因此RoI Align通过两种方式解决这个问题;

(1)保留proposal映射到feature map位置的小数部分;

(2)采用双线性插值的方式对proposal所在的feature map进行处理,避免边界导致的特征不准确(RoI Pooling会进行重复采样);

(3)每个proposal到feature map映射的bin中,由4个(如2×2、3×3)周围的值进行加权得到。

如图所示,虚线表示特征图,实线表示采样的proposal,利用双线性插值的方法计算每个黑点的值,然后每个bin(2×2)内的四个值(四个黑点)再求最大值或者均值,实现RoI Align。

目标检测数据集猫狗 目标检测 transformer_目标检测_16

因此在目标检测时使用RoI Align效果要比RoI Pooling好,尤其是对于小目标的精度影响。

2、RRoI Align

RRoI Align本质和RoI Align是一样的,区别在于双线性插值时采样点是经过偏移(与前文中的坐标偏移一致)。偏移计算为:

目标检测数据集猫狗 目标检测 transformer_目标检测_17

其中目标检测数据集猫狗 目标检测 transformer_目标检测数据集猫狗_18目标检测数据集猫狗 目标检测 transformer_算法_19分别表示中心点的x、y坐标(红点),目标检测数据集猫狗 目标检测 transformer_计算机视觉_20目标检测数据集猫狗 目标检测 transformer_对应点_21表示采样点所在特征图的x、y坐标。

目标检测数据集猫狗 目标检测 transformer_对应点_22


完结撒花!感谢RoI Transformer的作者。