Faster RCNN 中的Anchor

Faster RCNN 中的Anchor

Anchor 计算

py-faster-rcnn/lib/rpn/generate_anchors.py文件中,定义了如何生成Anchor,代码如下:

import numpy as np
def generate_anchors(base_size=16, ratios=[0.5, 1, 2],
                     scales=2**np.arange(3, 6)):
    """
    生成原图像(0, 0, 15, 15) 区域的Anchor,ratio为[0.5, 1, 2],scale为[8, 16, 32]
    """
    # base_anchor = [0, 0, 15, 15]
    base_anchor = np.array([1, 1, base_size, base_size]) - 1
    # 生成ratios下的anchors
    ratio_anchors = _ratio_enum(base_anchor, ratios)
    # 对已进行过ratios的anchors进行scales
    anchors = np.vstack([_scale_enum(ratio_anchors[i, :], scales)
                         for i in xrange(ratio_anchors.shape[0])])
    return anchors

def _whctrs(anchor):
    """
    返回一个anchor的宽w,高h和中心点位置(x_ctr, y_ctr)
    """

    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

def _mkanchors(ws, hs, x_ctr, y_ctr):
    """
    给定中心点(x_ctr, y_ctr)的宽(ws)和高(hs)向量,输出一系列anchors的左上角和右下角坐标
    """

    ws = ws[:, np.newaxis]
    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)))
    return anchors

def _ratio_enum(anchor, ratios):
    """
    Enumerate a set of anchors for each aspect ratio wrt an anchor.
    """
    # 得到一个anchor的宽,高和中心点
    w, h, x_ctr, y_ctr = _whctrs(anchor)
    # anchor的面积
    size = w * h
    # 计算ratios下的宽和高
    size_ratios = size / ratios # [512, 256, 128]
    ws = np.round(np.sqrt(size_ratios)) # ws=[23, 16, 11]
    hs = np.round(ws * ratios) # hs = [12, 16, 22]
    # 计算在ratios下的各anchor的左上和右下坐标
    anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
    return anchors

def _scale_enum(anchor, scales):
    """
    Enumerate a set of anchors for each scale wrt an anchor.
    """
    # 得到一个anchor的宽,高和中心点
    w, h, x_ctr, y_ctr = _whctrs(anchor)
    # 计算scale下的宽和高
    ws = w * scales
    hs = h * scales
    # 计算在scales下的各anchor的左上和右下坐标
    anchors = _mkanchors(ws, hs, x_ctr, y_ctr)
    return anchors

if __name__ == '__main__':
    import time
    t = time.time()
    # 生成anchors
    a = generate_anchors()
    print time.time() - t
    print a
    from IPython import embed; embed()

下面展示base_anchor为[0, 0, 15, 15],ratios=[0.5, 1,2],scales=[8,16,32]时,生成的9个anchors的坐标信息。

ratios(ws,hs)scales坐标
0.5(23,12)8(184*96)-84, -40, 99, 55
16(368*192)-176,-88,191,103
32(736*384)-360,-184,375,191
1(16,16)8(128*128)-56, -56, 71, 71
16(256*256)-120,-120,135,135
32(512*512)-248,-248,263,263
2(11,22)8(88*176)-36, -80, 51, 95
16(176*352)-80,-168,95,183
32(352*704)-168,-344,183,359

根据上面代码,假设定义三种纵横比ratio=[0.5, 1, 2]和三种尺度scale=[8, 16,32],3*3可以组合9种Anchor boxes。其中ratio为高和宽的比率,表示boxes的形状,scale表示boxes的大小。

1 vs 16真实区域
设一个矩形框的面积 s s s,矩形框的宽为 w w w,高为h,面积 s = h × w s = h \times w s=h×w,比率定义 r a t i o = h w ratio=\frac{h}{w} ratio=wh,经过简单变换之后,就可以得到不同比率下矩形框的宽 w w w和高 h h h。假设backbone网络为VGG,经过backbone网络后得到的feature map上的一点对应原图像大小的 16 × 16 16 \times 16 16×16区域。面积 128 × 128 128 \times 128 128×128 256 × 256 256 \times 256 256×256 512 × 512 512 \times 512 512×512 16 × 16 16 \times 16 16×16 8 2 8^{2} 82 1 6 2 16^{2} 162 3 2 2 32^{2} 322倍,scale大小为 [ 8 , 16 , 32 ] [8, 16,32] [8,16,32]。宽和高推导计算步骤如下公式所示。
h = w × r a t i o r a t i o × w 2 = s ⇒ w = s / r a t i o      h = w × r a t i o = s × r a t i o ⇒ s c a l e w = s a c l e × s / r a t i o      h = s c a l e × s × r a t i o \begin{matrix} h = w \times ratio \\ ratio \times w^{2}=s \end{matrix} \Rightarrow \begin{matrix} w = \sqrt{s / ratio} \; \; \\ h = w \times ratio = \sqrt{s \times ratio} \end{matrix} \overset{scale}{\Rightarrow} \begin{matrix} w = sacle \times \sqrt{s / ratio} \; \; \\ h = scale \times \sqrt{s \times ratio} \end{matrix} h=w×ratioratio×w2=sw=s/ratio h=w×ratio=s×ratio scalew=sacle×s/ratio h=scale×s×ratio

Anchor 数目计算

对于一个大小为 W × H W \times H W×H的卷积特征图,每一个滑动窗口的最大可能候选框的个数记为 k k k,那么总共会有 W H k WHk WHk个anchors。

通过一个 3 × 3 3 \times 3 3×3大小的滑动窗口在 W × H W \times H W×H大小的特征图中滑动,stride=1且padding为"same",那么就可以得到W*H个 3 × 3 3 \times 3 3×3的滑动窗口,那也就是说特征图中的每一点将会作为滑动窗口的中心点。如下图的红色滑动窗口,VGG网络下采样16倍,那么其中心点对应原图中的 16 × 16 16 \times 16 16×16区域。设置ratios和scales参数,特征图中的每一点就可以得到k个不同长宽比例和不同面积的anchors。

RPN
假设输入图像大小为800*600,经过VGG网络下采样16倍,得到的特征图的大小为 c e i l ( 800 / 16 ) c e i l ( 800 / 16 ) = 50 ∗ 38 ceil \left( 800 / 16 \right) ceil \left( 800 / 16 \right) = 50 * 38 ceil(800/16)ceil(800/16)=5038,在Faster RCNN 中,特征图上每一点的anchors数量为9,那么总共会有 50 × 38 × 9 = 17100 50 \times 38 \times 9 = 17100 50×38×9=17100个anchors。图像化解释见下图。

anchor生成

生成目标anchors

对于大小为800*600的原图,按照上述的计算,将会生成17100个anchors,如果全部用于训练,任务量巨大。而且生成的某些anchor不会起作用,为此,对于每一个anchor,分配一个二值化的标签,包含物体(正)/不包含物体(负)。生成目标anchors就是为了区分哪些anchors是正样本,哪些anchors是负样本。

具体计算方法是计算anchor和ground-truth boxes的IoU大小。正样本选择有两种标准,对于每一个ground-truth box,选取与其IoU最大的anchor作为正样本,或者如果一个anchor至少与任意一个ground-truth box的IoU大于0.7,则认为这个anchor为正样本。如果IoU小于0.3,则认为这个anchor为负样本。那些IoU值位于(0.3,0.7)区间的anchor,则认为对训练无益。

正样本的第一条标准保证了每一个ground-truth box都有一个anchor与之相对应,第二条标准保证有一定数量的anchor可以被筛选作为正样本。

在训练RPN的时候,一张图片随机选取256个anchors计算loss,正样本anchor和负样本anchor的比例是1:1,如果正样本的个数小于128,那么就用负样本来填充。

参考

  1. 目标检测1:目标检测中的Anchor详解
  2. faster R-CNN中anchors 的生成过程(generate_anchors源码解析)
  3. py-faster-rcnn
  4. 一文读懂Faster RCNN
  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马鹤宁

谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值