注:md文件,Typora软件书写,md兼容程度github=CSDN>知乎,若有不兼容处麻烦移步其他平台,github文档供下载。
上传在github:https://github.com/FermHan/Learning-Notes
发表在CSDN:https://blog.csdn.net/hancoder/article/
发表在知乎专栏:https://zhuanlan.zhihu.com/c_1088438808227254272
anchors最初是由Faster R-CNN中首次提出的,后来目标检测中的FPN、SSD、Mask R-CNN中都有类似于anchors的用法,由于其对目标检测的重要程度,特此拿出来进行代码解读。
代码原来:github上搜faster R-CNN有很多,个人参考https://github.com/jwyang/faster-rcnn.pytorch
Faster R-CNN各部分之前在R-CNN发展史笔记中已解释过,目标检测初读者可在文首提供的各个平台查阅。
这里一句话概括即假设conv5_3上的3×3卷积核对应原图上9种框。(为什么是9种?是实验人为总结的,在YOLO中有进行anchor聚类而得到anchor预设值的操作)
先看主函数,然后再从generate_anchors开始看
主函数,单独运行的入口
相当于次主函数,它调用了其他一些函数
给定一正方形x1y1x2y2,然后根据这个正方形变成同面积scale的、三种长宽比ratio的框。相当于输入1个正方形,输出1个正方形+2个长方形
把anchor的x1y1x2y2换算成了wh和中心坐标
from __future__ import print_function
import numpy as np
try:
xrange # Python 2
except NameError:
xrange = range # Python 3
# 注:anchors在这个.py中,表示形式都是x1y1x2y2。wh只是过渡
# 第1个调用
def generate_anchors(base_size=16, ratios=[0.5, 1, 2],
scales=2**np.arange(3, 6)):
# base_size=16 代表feature map上一个点对应原图16×16的区域
# ratios=[0.5,1,2] 代表的是anchors框的长宽比1:2,1:1,2:1
# base_size/根号ratios 即可得出base_size有3种框23:12,16:16,11:22
# scales 代表在base_size的anchor框基础上需要放大的倍数[8,16,32]
# base_size×scales 即(16*8)*(16*8)=128*128,(16*16)*(16*16)=256*256,(16*32)*(16*32)=512*512,这是原图上框的尺寸
"""
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
# [0,0,15,15],代表这个区域左上角和右下角坐标
ratio_anchors = _ratio_enum(base_anchor, ratios) #参数16,[0.5, 1, 2]
# 返回一个scale下三种ratio的anchor
# ratio_anchors=
#[[ -3.5 2. 18.5 13. ]
# [ 0. 0. 15. 15. ]
# [ 2.5 -3. 12.5 18. ]]
# ratio_anchors.shape[0]=3
anchors = np.vstack(
[ _scale_enum(ratio_anchors[i, :], scales) for i in xrange(ratio_anchors.shape[0])]
) # 竖直方向上叠加
# [[ -84. -40. 99. 55.]
# [-176. -88. 191. 103.]
# [-360. -184. 375. 199.]
# [ -56. -56. 71. 71.]
# [-120. -120. 135. 135.]
# [-248. -248. 263. 263.]
# [ -36. -80. 51. 95.]
# [ -80. -168. 95. 183.]
# [-168. -344. 183. 359.]]
return anchors
# 第2个调用
def _ratio_enum(anchor, ratios): # [0,0,15,15],[0.5, 1, 2]
"""
Enumerate a set of anchors for each aspect ratio wrt an anchor.
"""
w, h, x_ctr, y_ctr = _whctrs(anchor)
# _whctrs函数把anchor的x1y1x2y2换算成了wh和中心坐标
size = w * h #size:16*16=256
size_ratios = size / ratios #256/ratios[0.5,1,2]=[512,256,128]
# 相当于w/根号ratios
ws = np.round(np.sqrt(size_ratios)) #np.round()四舍五入,np.sqrt()开方ws:[23 16 11]
hs = np.round(ws * ratios) #hs:[12 16 22],ws和hs一一对应。23&12
#给定一组宽高向量,输出各个预测窗口,也就是将(宽,高,中心点横坐标,中心点纵坐标)的形式,转成
#四个坐标值的形式
anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
# 将whx_cy_c变量坐标变成一组x1y1x2y2,这一组的w×h是相同的
return anchors #返回到generate_anchors函数
# 第3个调用
def _whctrs(anchor): # 把anchor的x1y1x2y2换算成了wh和中心坐标
"""
Return width, height, x center, and y center for an anchor (window).
"""
w = anchor[2] - anchor[0] + 1
h = anchor[3] - anchor[1] + 1
x_ctr = anchor[0] + 0.5 * (w - 1)
y_ctr = anchor[1] + 0.5 * (h - 1)
return w, h, x_ctr, y_ctr
# 第4个调用
def _mkanchors(ws, hs, x_ctr, y_ctr):
# ws=[23 16 11] hs=[12 16 22]
"""
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] # np.newaxis相当于None,相当于增加了一维
# ws=[23 16 11] ws=[[23], [16], [11]]
hs = hs[:, np.newaxis]
anchors = np.hstack((x_ctr - 0.5 * (ws - 1), # 水平方向平铺,注意括号层数,括起来相当于一个参数
y_ctr - 0.5 * (hs - 1),
x_ctr + 0.5 * (ws - 1),
y_ctr + 0.5 * (hs - 1) ))
# anchors= [[-3.5,2,18.5,13]
# [0,0,15,15]
# [2.5,-3,12.5,18]]
return anchors #x1y1x2y2
# 第5个调用,调用重复3次,3次后generate也完成了工作
def _scale_enum(anchor, scales):
"""
Enumerate a set of anchors for each scale wrt an anchor.
"""
# anchor=[ -3.5 2. 18.5 13. ] scales=[8,16,32]
# 每次_scale_enum函数完成的是:给定框宽高比ratio,返回这种比例所有scale的框
w, h, x_ctr, y_ctr = _whctrs(anchor)
ws = w * scales # [ 184. 368. 736.]
hs = h * scales # [ 96. 192. 384.]
anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
# [[ -84. -40. 99. 55.]
# [-176. -88. 191. 103.]
# [-360. -184. 375. 199.]]
return anchors
if __name__ == '__main__':
import time
t = time.time()
a = generate_anchors() # 入口
print(time.time() - t)
print(a)
from IPython import embed; embed()
附generate_anchors.py运行结果
base_anchor | ratios | (宽,高,xc,yc) | 坐标 |
---|---|---|---|
[184,96,7.5,7.5] scale=8 | [ -84. -40. 99. 55.] | ||
23×12(2:1) | [368,192,7.5,7.5] scale=16 | [-176. -88. 191. 103.] | |
[736,384,7.5,7.5] scale=32 | [-360. -184. 375. 199.] | ||
[128,128,7.5,7.5] scale=8 | [ -56. -56. 71. 71.] | ||
16×16 | 16×16(1:1) | [256,256,7.5,7.5] scale=16 | [-120. -120. 135. 135.] |
[512,512,7.5,7.5] scale=32 | [-248. -248. 263. 263.] | ||
[88,176,7.5,7.5] scale=8 | [ -36. -80. 51. 95.] | ||
11×22(1:2) | [176,352,7.5,7.5] scale=16 | [ -80. -168. 95. 183.] | |
[352,704,7.5,7.5] scale=32 | [-168. -344. 183. 359.] |