Faster R-CNN/RPN/generate_anchors详解

注: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

anchors定义

Faster R-CNN各部分之前在R-CNN发展史笔记中已解释过,目标检测初读者可在文首提供的各个平台查阅。

这里一句话概括即假设conv5_3上的3×3卷积核对应原图上9种框。(为什么是9种?是实验人为总结的,在YOLO中有进行anchor聚类而得到anchor预设值的操作)

代码

rpn/generate_anchors.py

先看主函数,然后再从generate_anchors开始看

main

主函数,单独运行的入口

generate_anchors

相当于次主函数,它调用了其他一些函数

_ratio_enum

给定一正方形x1y1x2y2,然后根据这个正方形变成同面积scale的、三种长宽比ratio的框。相当于输入1个正方形,输出1个正方形+2个长方形

_whctrs(anchor)

把anchor的x1y1x2y2换算成了wh和中心坐标

_mkanchors

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.]

你可能感兴趣的:(深度学习)