faster rcnn如何生成anchors

      本文就faster rcnn中anchors的函数generate_anchors.py为例,介绍anchors的生成过程。

      首先看下主函数入口。论文中提到anchor两个参数:ratios和scales,长宽比和尺度变换都需要有个基础anchor的大小,也就是base_size的由来,至于16的由来,则等于网络的输入大小 / 特征图大小(生成anchor的feature map层)

def generate_anchors(base_size=16, ratios=[0.5, 1, 2],
                     scales=2**np.arange(3, 6))

      这样," base_anchor = np.array([1, 1, base_size, base_size]) - 1 "就表示基础anchor的大小了。

      其次,看下如何生成长宽比不同的anchors。这里是对anchor的宽高都进行了改变,具体是将宽变为round({sqrt(w*h/ratios))},高变为ws*ratio,这样长宽比就变为ratios了。此时生成3个长宽比不同的anchors。

def _ratio_enum(anchor, ratios):
    """
    Enumerate a set of anchors for each aspect ratio wrt an anchor.
    """

    w, h, x_ctr, y_ctr = _whctrs(anchor) #基础anchor(0, 0, 15, 15)的宽高中心点坐标
    size = w * h   #anchor面积
    size_ratios = size / ratios #面积比例w**2/ratios
    ws = np.round(np.sqrt(size_ratios)) #对宽度进行变换,得到w/sqrt(ratios)
    hs = np.round(ws * ratios) #由于ws=w/sqrt(ratios), 所以hs=w*sqrt(ratios)
    anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
    return anchors

      再者,看下如何生成尺度不同的anchors,将anchor的宽和高分别进行尺度变换即可。

def _scale_enum(anchor, scales):
    """
    Enumerate a set of anchors for each scale wrt an anchor.
    """

    w, h, x_ctr, y_ctr = _whctrs(anchor)
    ws = w * scales #对anchor的宽进行尺度变换
    hs = h * scales #对anchor的高进行尺度变换
    anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
    return anchors

      最后就是两个函数的理解了,np.hstacknp.vstack,可以通过_mkanchors函数理解前者,得到3行4列的anchors,然后利用np.vstack函数再得到9行4列的元素。

def _mkanchors(ws, hs, x_ctr, y_ctr):
    """
    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] #增加新的维度,由(3, )变为(3, 1)
    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))) #依次堆叠ws和hs水平方向上对应元素生成的值
    return anchors

这样最终得到一个点上生成的anchor,对应论文图3中的k anchor boxes.

整个计算流程如下:

>>> base_size=16
>>> ratios=[0.5, 1, 2]
>>> scales=2**np.arange(3, 6)
>>> base_anchor = np.array([1, 1, base_size, base_size]) - 1
>>> ratio_anchors = _ratio_enum(base_anchor, ratios)
>>> scale_anchors_0 =_scale_enum(ratio_anchors[0, :], scales)
>>> ratio_anchors.shape
(3, 4)
>>> scale_anchors_0.shape
(3, 4)
>>> ratio_anchors
array([[-3.5,  2. , 18.5, 13. ],
       [ 0. ,  0. , 15. , 15. ],
       [ 2.5, -3. , 12.5, 18. ]])
>>> scale_anchors_0
array([[ -84.,  -40.,   99.,   55.],
       [-176.,  -88.,  191.,  103.],
       [-360., -184.,  375.,  199.]])
>>> anchors = np.vstack([_scale_enum(ratio_anchors[i, :], scales) for i in xrange(ratio_anchors.shape[0])])
>>> anchors.shape
(9, 4)
>>> anchors
array([[ -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.]])

参考文献:

  1.  https://github.com/smallcorgi/Faster-RCNN_TF/blob/master/lib/rpn_msr/generate_anchors.py

版权声明:本文为hzhj2007原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。