一、引言

1、旋转目标检测检测

旋转目标检测检测就是将具有旋转方向的目标检测出来,也就是需要检测目标的中心点、长宽、角度。在俯视图的目标检测中比较常见,如遥感图像目标检测、航拍图像目标检测等。(见下图旋转目标检测,图源论文RoI 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)
在这里插入图片描述

下面说下在用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)),具体的角度见论文配图(如下)。
在这里插入图片描述
现在我们知道了角度的定义方式了,需要由八个顶点坐标计算中心点、长宽、θ这几个参数值。
(1)中心点计算
( x , y ) = ( 1 / 4 ∑ i 4 x i , 1 / 4 ∑ i 4 y i ) (x,y)=(1/4∑_i^{4}x_i,1/4∑_i^{4}y_i) (x,y)=(1/4i4xi1/4i4yi)
(2)长宽计算
长宽计算在此论文中先将旋转框经过角度旋转之后得到水平框,然后计算水平框的x、y坐标的左右、上下极值,得到[minx, miny, maxx, maxy]四个坐标,再计算矩形的长宽值。
在这里插入图片描述
由图斜框与水平(x轴)的夹角是θ,那么将此斜框逆时针旋转β角度得到水平框。显然可得β=90-θ(长的好看的人需要推导一下)。那么现在就可以根据θ和A’点坐标来计算旋转之后点A的坐标了。
为了看起来简单,以斜框的中心点画坐标轴(因为四个坐标都可以以中心点作为参考)
在这里插入图片描述
设A’坐标[x’,y’],求A的坐标[x,y],设红直线的长度为d(即A与A’到中心的距离)
x = d × s i n ( β + γ ) = d × ( s i n β c o s γ + s i n γ c o s β ) = x ′ c o s β + y ′ s i n β x=d×sin(β+γ)=d×(sinβcosγ+sinγcosβ)=x'cosβ+y'sinβ x=d×sin(β+γ)=d×(sinβcosγ+sinγcosβ)=xcosβ+ysinβ
y = d × c o s ( β + γ ) = d × ( c o s β c o s γ − s i n β s i n γ ) = y ′ c o s β − x ′ s i n β y=d×cos(β+γ)=d×(cosβcosγ-sinβsinγ)=y'cosβ-x'sinβ y=d×cos(β+γ)=d×(cosβcosγsinβsinγ)=ycosβxsinβ

3、RoI Transformer中标签处理过程

旋转矩形框标注一般都是四个点的八个坐标(x,y),由于标注过程中存在很多误差,很多时候标注的并不是矩形,而是不规则四边形(比如图像边缘区域、密集小目标),那么这个时候直接利用四个坐标去计算长宽、偏转角度是不合适的。在RoI Transformer中处理过程如下:
(1)由四个标注点得到四边形封闭mask(二值矩阵);
(2)opencv通过mask找到最小外接矩形的四个点坐标(见1、opencv旋转矩形角度定义方式);
(3)找到旋转矩形的最小外接水平矩形,计算旋转矩形与水平矩形的对应点(这个计算直接计算各对应点的距离,找到最小值);比如最小外接水平矩形四个点为(A1、A2、A3、A4),旋转矩形的四个顶点为(A1’、A2’、A3’、A4’);
m i n d = m i n ( ∑ i = 1 , 2 , 3 , 4 ∣ A i − A i ′ ∣ , ∑ i = 2 , 3 , 4 , 1 ∣ A i − A i ′ ∣ , ∑ i = 3 , 4 , 1 , 2 ∣ A i − A i ′ ∣ , ∑ i = 4 , 1 , 2 , 3 ∣ A i − A i ′ ∣ ) min_d=min(∑_{i=1,2,3,4}|Ai-Ai'|,∑_{i=2,3,4,1}|Ai-Ai'|,∑_{i=3,4,1,2}|Ai-Ai'|,∑_{i=4,1,2,3}|Ai-Ai'|) mind=min(i=1,2,3,4AiAi,i=2,3,4,1AiAi,i=3,4,1,2AiAi,i=4,1,2,3AiAi)
其中 ∣ A i − A i ′ ∣ |Ai-Ai'| AiAi表示两个点的距离。
(4)这样找到了最佳对应点之后,再通过(2、RoI Transformer中旋转目标角度定义)得到旋转矩形的中心点、长宽、角度,即[cx,cy,w,h,θ]。
为什么要经过第3步找到旋转矩形与水平矩形的对应点呢?这里有两个原因:
(1)找到对应的起始点之后,计算θ就是一个确定值(2中角度计算方式 θ = n p . a r c t a n 2 ( − ( x 2 − x 1 ) , ( y 2 − y 1 ) ) θ=np.arctan2(-(x2-x1),(y2-y1)) θ=np.arctan2((x2x1)(y2y1)));
(2)找到旋转矩形与水平矩形最小的旋转角度,便于后续通过水平Anchor预测旋转矩形。

三、网络结构

网络结构部分整体类似一个cascade rcnn,过程是BackBone->RPN->rbbox1->rbbox2。
在这里插入图片描述

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)回归的偏差计算如下:
t x ′ = 1 / w r ( ( x ′ − x r ) c o s θ r + ( y ′ − y r ) s i n θ r ) t y ′ = 1 / h r ( ( y ′ − y r ) c o s θ r − ( x ′ − x r ) s i n θ r ) t w ′ = l o g ( w ′ / w r ) ; t h ′ = l o g ( h ′ / h r ) t θ ′ = ( ( θ ′ − θ r ) m o d 2 π ) / 2 π t'_x=1/w_r((x'-x_r)cosθ_r+(y'-y_r)sinθ_r)\\ t'_y=1/h_r((y'-y_r)cosθ_r-(x'-x_r)sinθ_r)\\ t'_w=log(w'/w_r);t'_h=log(h'/h_r)\\ t'_θ=((θ'-θ_r)mod2π)/2π tx=1/wr((xxr)cosθr+(yyr)sinθr)ty=1/hr((yyr)cosθr(xxr)sinθr)tw=log(w/wr);th=log(h/hr)tθ=((θθr)mod2π)/2π
注意这里为什么中心坐标要乘以角度: t x ′ = 1 / w r ( ( x ′ − x r ) c o s θ r + ( y ′ − y r ) s i n θ r ) t'_x=1/w_r((x'-x_r)cosθ_r+(y'-y_r)sinθ_r) tx=1/wr((xxr)cosθr+(yyr)sinθr),而不是直接计算偏差 t x ′ = 1 / w r ( ( x ′ − x r ) t'_x=1/w_r((x'-x_r) tx=1/wr((xxr)。这里还是需要看第二章里面数据处理中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。
在这里插入图片描述

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

2、RRoI Align

RRoI Align本质和RoI Align是一样的,区别在于双线性插值时采样点是经过偏移(与前文中的坐标偏移一致)。偏移计算为:
x = y y ∗ s i n θ + x x ∗ c o s θ + c e n t e r w y = y y ∗ c o s θ − x x ∗ s i n θ + c e n t e r h x=yy*sinθ+xx*cosθ+center_w\\ y=yy*cosθ-xx*sinθ+center_h x=yysinθ+xxcosθ+centerwy=yycosθxxsinθ+centerh
其中 c e n t e r w center_w centerw c e n t e r h center_h centerh分别表示中心点的x、y坐标(红点), x x xx xx y y yy yy表示采样点所在特征图的x、y坐标。
在这里插入图片描述
完结撒花!感谢RoI Transformer的作者。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐