Faster RCNN 中 anchor 的计算

Faster RCNN Python 版源码文件 generate_anchors.py

一些基本设定

  1. 输出的 anchor 格式: 对应在原图上的位置, 四个坐标值, 为左上角和右下角的坐标: x1,y1, x2, y2
  2. ctr: center 的意思, 如 (x_ctr, y_ctr) 表示 anchor 中心点的坐标
  3. base_size: 用来初始化一个 anchor 的边长, 后续乘以 ratioscale 即可得到实际使用的 anchor 的长宽, 通常设为进行 RPN 的特征图的 stride, 如 Faster RCNN 中是在 conv4 上进行 RPN 的, 那么 base_size 通常设置为 16, 这样就会初始化一个 anchor, 其坐标为 [0, 0, 15, 15], 如果 scale 设为 [8, 16, 32], ratio 设为 [0.5, 1, 2], 就会得到 9 种不同大小的 anchor 。注意, 这里计算 ratio 的时候易出错, 如 ratio=2, 那么长宽应为 scale * base_size * sqrt(2) , scale * base_size / sqrt(2) , 而不是 scale * base_size * 2 或者 scale * base_size / 2, 因为后者计算如果使用 长/宽=4 而不是 2;
  4. 代码主要分为 3 步:
    • 根据 base_size 生成初始的 anchor;
    • 保持 anchor 的面积不变, 改变 ratio (代码中的 _ratio_enums 函数);
    • 对上一步的结果, 分别进行 scale 缩放, 得到最终的 anchor (代码中的 _scale_enums 函数).
  5. _whctrs(anchors) 的作用是找出一个 anchor 的宽高和中心坐标
  6. _mkanchors 是根据宽高和中心坐标, 生成一个新的 anchor
  7. generate_anchors 是生成 anchor 的总函数

源码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#功能描述: 生成多尺度、多宽高比的anchors。  
# 尺度为: 128,256,512; 宽高比为: 1:2,1:1,2:1

import numpy as np #提供矩阵运算功能的库

#生成anchors总函数: ratios为一个列表, 表示宽高比为: 1:2,1:1,2:1
#2**x表示:2^x, scales:[2^3 2^4 2^5],即:[8 16 32]
def generate_anchors(base_size=16, ratios=[0.5, 1, 2],
scales=2**np.arange(3, 6)):
"""
Generate anchor (reference) windows by enumerating aspect ratios X
scales wrt a reference (0, 0, 15, 15) window.
"""
base_anchor = np.array([1, 1, base_size, base_size]) - 1 #新建一个数组: base_anchor:[0 0 15 15]
ratio_anchors = _ratio_enum(base_anchor, ratios) #枚举各种宽高比
anchors = np.vstack([_scale_enum(ratio_anchors[i, :], scales) #枚举各种尺度, vstack:竖向合并数组
for i in xrange(ratio_anchors.shape[0])]) #shape[0]:读取矩阵第一维长度, 其值为3
return anchors

#用于返回width,height,(x,y)中心坐标(对于一个anchor窗口)
def _whctrs(anchor):
"""
Return width, height, x center, and y center for an anchor (window).
"""
#anchor:存储了窗口左上角, 右下角的坐标
w = anchor[2] - anchor[0] + 1
h = anchor[3] - anchor[1] + 1
x_ctr = anchor[0] + 0.5 * (w - 1) #anchor中心点坐标
y_ctr = anchor[1] + 0.5 * (h - 1)
return w, h, x_ctr, y_ctr

#给定一组宽高向量, 输出各个anchor, 即预测窗口, **输出anchor的面积相等, 只是宽高比不同**
def _mkanchors(ws, hs, x_ctr, y_ctr):
#ws:[23 16 11], hs:[12 16 22],ws和hs一一对应。
"""
Given a vector of widths (ws) and heights (hs) around a center
(x_ctr, y_ctr), output a set of anchors (windows).
"""
ws = ws[:, np.newaxis] #newaxis:将数组转置
hs = hs[:, np.newaxis]
anchors = np.hstack((x_ctr - 0.5 * (ws - 1), #hstack、vstack:合并数组
y_ctr - 0.5 * (hs - 1), #anchor: [[-3.5 2 18.5 13]
x_ctr + 0.5 * (ws - 1), # [0 0 15 15]
y_ctr + 0.5 * (hs - 1))) # [2.5 -3 12.5 18]]
return anchors

#枚举一个anchor的各种宽高比, anchor[0 0 15 15],ratios[0.5,1,2]
def _ratio_enum(anchor, ratios):
""" 列举关于一个anchor的三种宽高比 1:2,1:1,2:1
Enumerate a set of anchors for each aspect ratio wrt an anchor.
"""

w, h, x_ctr, y_ctr = _whctrs(anchor) #返回宽高和中心坐标, w:16,h:16,x_ctr:7.5,y_ctr:7.5
size = w * h #size:16*16=256
size_ratios = size / ratios #256/ratios[0.5,1,2]=[512,256,128]
#round()方法返回x的四舍五入的数字, sqrt()方法返回数字x的平方根
ws = np.round(np.sqrt(size_ratios)) #ws:[23 16 11]
hs = np.round(ws * ratios) #hs:[12 16 22],ws和hs一一对应。as:23&12
anchors = _mkanchors(ws, hs, x_ctr, y_ctr) #给定一组宽高向量, 输出各个预测窗口
return anchors

#枚举一个anchor的各种尺度, 以anchor[0 0 15 15]为例,scales[8 16 32]
def _scale_enum(anchor, scales):
""" 列举关于一个anchor的三种尺度 128*128,256*256,512*512
Enumerate a set of anchors for each scale wrt an anchor.
"""
w, h, x_ctr, y_ctr = _whctrs(anchor) #返回宽高和中心坐标, w:16,h:16,x_ctr:7.5,y_ctr:7.5
ws = w * scales #[128 256 512]
hs = h * scales #[128 256 512]
anchors = _mkanchors(ws, hs, x_ctr, y_ctr) #[[-56 -56 71 71] [-120 -120 135 135] [-248 -248 263 263]]
return anchors

if __name__ == '__main__': #主函数
import time
t = time.time()
a = generate_anchors() #生成anchor(窗口)
print time.time() - t #显示时间
print a
from IPython import embed; embed()

其中, _ratio_enum() 部分生成三种宽高比 1:2, 1:1, 2:1anchor 如下图所示:
ratio enum

其中, _scale_enum() 部分, 生成三种尺寸的 anchor, 以_ratio_enum() 部分生成的 anchor [0 0 15 15] 为例, 扩展了三种尺度 128*128 , 256*256 , 512*512, 如下图所示:
scale enum

参考资料

  1. Faster RCNN 源码中 anchor 的计算
  2. faster rcnn RPN 之 anchor (generate_anchors) 源码解析
0%