详解经典旋转目标检测算法RoI Transformer
一、引言1、旋转目标检测检测就是将具有旋转方向的目标检测出来,也就是需要检测目标的中心点、长宽、角度。在俯视图的目标检测中比较常见,如遥感图像目标检测、航拍图像目标检测等。(见下图旋转目标检测,图源论文RoI Transformer )2、旋转目标检测算法,目前多阶段里面性能较好的是RoI Transformer这个算法,本篇博客将详细分析此算法。论文《Learning RoI Transform
一、引言
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/4i∑4xi,1/4i∑4yi)
(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β)=x′cosβ+y′sinβ
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γ)=y′cosβ−x′sinβ
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,4∑∣Ai−Ai′∣,i=2,3,4,1∑∣Ai−Ai′∣,i=3,4,1,2∑∣Ai−Ai′∣,i=4,1,2,3∑∣Ai−Ai′∣)
其中
∣
A
i
−
A
i
′
∣
|Ai-Ai'|
∣Ai−Ai′∣表示两个点的距离。
(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(−(x2−x1),(y2−y1)));
(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((x′−xr)cosθr+(y′−yr)sinθr)ty′=1/hr((y′−yr)cosθr−(x′−xr)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((x′−xr)cosθr+(y′−yr)sinθr),而不是直接计算偏差
t
x
′
=
1
/
w
r
(
(
x
′
−
x
r
)
t'_x=1/w_r((x'-x_r)
tx′=1/wr((x′−xr)。这里还是需要看第二章里面数据处理中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=yy∗sinθ+xx∗cosθ+centerwy=yy∗cosθ−xx∗sinθ+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的作者。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)