faster rcnn代码解读(二)anchor的生成

faster rcnn代码解读参考

https://github.com/adityaarun1/pytorch_fast-er_rcnn

    https://github.com/jwyang/faster-rcnn.pytorch

单独说一下anchor生成。

一、首先是为一个像素点生成anchor


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 
   ratio_anchors = _ratio_enum(base_anchor, ratios)
    anchors = np.vstack([
        _scale_enum(ratio_anchors[i, :], scales)
        for i in range(ratio_anchors.shape[0])
    ])
    return anchors

这里可以看到有几个参数:

base_size:其实也就是一开始变换的基础,resize的基础吧。

ratios:主要就是改变base_size,其实也就是关联长宽比

scales:就是在ratios基础上做一些放缩。

这里生成的anchor基本上是左上、右下角座标表示。

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的宽高和中心点座标
    size = w * h                        #计算size
    size_ratios = size / ratios         #将size进行ratios放缩
    ws = np.round(np.sqrt(size_ratios)) #计算放缩有的w,多个w
    hs = np.round(ws * ratios)          #计算放缩后的h,多个h
    anchors = _mkanchors(ws, hs, x_ctr, y_ctr)#根据计算的ws、hs生成多个anchor,左下角和右上角座标
    return anchors

上面的是根据ratios将base anchor长宽进行等比例放缩。_whctrs没什么特别的,就是将top left、bottom right座标转成 center+w+h,center是为了定位,w、h是为了变换

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)
    y_ctr = anchor[1] + 0.5 * (h - 1)
    return w, h, x_ctr, y_ctr

 _mkanchors就是把之前的center+w+h方式再变换anchors形式,其实也就是左上、右下角的表示形式。


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).
  # 在ctr为中心点生成多个以ws、hs为宽高的anchor
  """
    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

 _scale_enum做了一个类似的尺度变换

def _scale_enum(anchor, scales):
    """
  Enumerate a set of anchors for each scale wrt an anchor.
  """
    w, h, x_ctr, y_ctr = _whctrs(anchor)#计算anchor的宽高和中心点座标
    ws = w * scales #将w进行scales放缩,多个ws
    hs = h * scales #将h进行scales放缩,多个hs
    anchors = _mkanchors(ws, hs, x_ctr, y_ctr)#根据计算的ws、hs生成多个anchor,左下角和右上角座标
    return anchors

 二、在feature上将相隔stride的pixel生成的len(scale)*len(ratios)组合起来。

def generate_anchors_pre(height,
                         width,
                         feat_stride,
                         anchor_scales=(8, 16, 32),
                         anchor_ratios=(0.5, 1, 2)):
    """ A wrapper function to generate anchors given different scales
    Also return the number of anchors in variable 'length'
  """
    # 生成标准的len(anchor_ratios)*len(anchor_scales)为一组的anchors
    anchors = generate_anchors( ratios=np.array(anchor_ratios), scales=np.array(anchor_scales))
    A = anchors.shape[0]
    shift_x = np.arange(0, width) * feat_stride #计算x座标移动长度
    shift_y = np.arange(0, height) * feat_stride#计算y座标移动长度
    shift_x, shift_y = np.meshgrid(shift_x, shift_y)#生成采样网格,即映射到原height、width上的anchor中心点座标
    shifts = np.vstack((shift_x.ravel(), shift_y.ravel(), shift_x.ravel(),
                        shift_y.ravel())).transpose()
    K = shifts.shape[0]
    # width changes faster, so here it is H, W, C
    anchors = anchors.reshape((1, A, 4)) + shifts.reshape((1, K, 4)).transpose((1, 0, 2))
    anchors = anchors.reshape(( K * A, 4)).astype(np.float32, copy=False)
    length = np.int32(anchors.shape[0])

    return anchors, length

 这里有几个参数:

height、width:这是之前从vgg16生成的feature  map大小,这里不需要传入feature map的,只是生成anchor。

feat_stride:和卷积的stride一个意思。

meshgrid这个函数很有意思,能看得懂它做了什么,但是要理解从输入到输出就有点匪夷所思了,类似于枚举了采样网格点,对采样网格座标进行操作,具体是从谁采样到谁,可以仔细的研究一下,简单的理解就是以全排列的方式枚举pixel座标,其中x、y座标是分开的,ravel的作用是将x、y座标flatten。为什么是vstack两个shift_x,是因为左上角右下角连个都需要移动。

A = len(anchor_ratios)*len(anchor_scales) = anchor_num

K = (feat_width *feat_height)

要注意的一点是,python中的数据是按行存取的,因此会经常看到reshape操作,因为按行存。

最后一个feature map输出的大小是K*A*4 =  (feat_width *feat_height) *  anchor_num

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章