看不懂anchor生成方法,就看不懂参数。
faster_rcnn的anchors生成
在这里我就不看faster_rcnn的anchors生成源代码了,我们用numpy自己去实现,在128*128大小的图片中生成anchors.
开始上代码
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
# %matplotlib inline
feature_map的大小是16,在faster_rcnn中feature_map是一张图片经过卷积后生成的。如这里输入128*128的图片卷积后16*16大小,也就等于在128*128的图片里平均找16*16个像素点,每个像素点都生成3*3个锚框,scales和ratios决定框的大小。
size_Y = 16
size_X = 16
rpn_stride = 8
scales = [8, 16, 32]
ratios = [0.5, 1, 2]
scales, ratios = np.meshgrid(scales, ratios)
scales, ratios = scales.flatten(), ratios.flatten()
scalesY = scales * np.sqrt(ratios)
scalesX = scales / np.sqrt(ratios)
shiftX = np.arange(0, size_X) * rpn_stride
shiftY = np.arange(0, size_Y) * rpn_stride
shiftX, shiftY = np.meshgrid(shiftX, shiftY)
centerX, anchorX = np.meshgrid(shiftX, scalesX)
centerY, anchorY = np.meshgrid(shiftY, scalesY)
anchor_center = np.stack([centerY, centerX], axis=2).reshape(-1, 2)
anchor_size = np.stack([anchorY, anchorX], axis=2).reshape(-1, 2)
boxes = np.concatenate([anchor_center - 0.5*anchor_size, anchor_center + 0.5*anchor_size], axis=1)
建一个空白图片在上面显示anchors
plt.figure(figsize=(15, 15))
img = np.ones((150,150, 3))
plt.imshow(img)
Axs = plt.gca()
for i in range(anchors.shape[0]):
box = anchors[i]
rec = patches.Rectangle((box[0], box[1]), box[2]-box[0], box[3]-box[1], edgecolor='r', facecolor='none')
Axs.add_patch(rec)
这个输出是经过修改scales=(1,2,4)后的结果,每个点3*3个框,修改后显示得更明显,scales影响着锚框的平均大小。
可以看到锚框最大的正方形也就是4*4的。当我们把scales调到(8, 16, 32)最大的正方形锚框是32*32,最小的是8*8。
这样当出现占满50%图片的物体时根本没办法框住,在mask_rcnn中对anchors的生成就有改进。
mask_rcnn的anchors生成
我们先看一下生成anchors的一点代码,参数输入:
t = generate_pyramid_anchors(
(32, 64, 128, 256, 512),
[0.5, 1, 2],
[ [32,32],[16,16],[8,8],[4,4],[2,2]],
# [[256, 256], [128, 128], [64, 64], [32, 32], [16, 16]],
[4, 8, 16, 32, 64],
1)
这里面还有一部分跳转,和前面faster_rcnn的生成方法一样的。
我们先看一下feature_shapes这个参数,是根据输入图片大小决定的,每个feature_map是固定的,因为这是网络结构卷积后每一层输出的feature_map大小,输入图片128*128得到[ [32,32],[16,16],[8,8],[4,4],[2,2]],输入1024*1024得到[[256, 256], [128, 128], [64, 64], [32, 32], [16, 16]],也就是分出5个feature_map的大小,对逐个feature_map进行anchors的生成。
可以看到对参数进行了5次循环。
def generate_pyramid_anchors(scales, ratios, feature_shapes, feature_strides,
anchor_stride):
anchors = []
for i in range(len(scales)): # (32, 64, 128, 256, 512)
anchors.append(generate_anchors(scales[i], ratios, feature_shapes[i],
feature_strides[i], anchor_stride))
return np.concatenate(anchors, axis=0)
我们来看一下每次代入的参数和生成的anchors数量。
这里还是以128*128来进行。
整个运行生成4092个anchors。
把参数分解出来。
第一次循环参数:
生成anchors是(3072, 4) , 这里每个点只生成3个框,这个生成的最大正方形anchors是32*32。
scales = [32]
ratios = [0.25, 0.5, 1]
size_Y = size_X = 32
rpn_stride = 4
这里用了前面的代码,复制就可以运行(加上上面的参数)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
%matplotlib inline
scales, ratios = np.meshgrid(scales, ratios)
scales, ratios = scales.flatten(), ratios.flatten()
scalesY = scales * np.sqrt(ratios)
scalesX = scales / np.sqrt(ratios)
shiftX = np.arange(0, size_X) * rpn_stride
shiftY = np.arange(0, size_Y) * rpn_stride
shiftX, shiftY = np.meshgrid(shiftX, shiftY)
centerX, anchorX = np.meshgrid(shiftX, scalesX)
centerY, anchorY = np.meshgrid(shiftY, scalesY)
anchor_center = np.stack([centerY, centerX], axis=2).reshape(-1, 2)
anchor_size = np.stack([anchorY, anchorX], axis=2).reshape(-1, 2)
boxes = np.concatenate([anchor_center - 0.5*anchor_size, anchor_center + 0.5*anchor_size], axis=1)
plt.figure(figsize=(15, 15))
img = np.ones((150,150, 3))
plt.imshow(img)
Axs = plt.gca()
for i in range(anchors.shape[0]):
box = anchors[i]
rec = patches.Rectangle((box[0], box[1]), box[2]-box[0], box[3]-box[1], edgecolor='r', facecolor='none')
print((box[0], box[1]), box[2]-box[0], box[3]-box[1])
Axs.add_patch(rec)
改了scalse生成的,可以看到每个点只生成3个anchors
第二次循环参数:
生成anchors是(768, 4), 这个生成的最大正方形anchors是64*64
scales = [64]
ratios = [0.25, 0.5, 1]
size_Y = size_X = 16
rpn_stride = 8
第三次循环参数:
生成anchors是(192, 4), 这个生成的最大正方形anchors是128*128
scales = [128]
ratios = [0.25, 0.5, 1]
size_Y = size_X = 8
rpn_stride = 16
第四次循环参数:
生成anchors是(48, 4), 这个生成的最大正方形anchors是256*256
scales = [256]
ratios = [0.25, 0.5, 1]
size_Y = size_X = 4
rpn_stride = 32
第五次循环参数:
生成anchors是(12, 4), 这个生成的最大正方形anchors是512*512
scales = [512]
ratios = [0.25, 0.5, 1]
size_Y = size_X = 2
rpn_stride = 64
我们可以看到3072+768+192+48+12=4092,前面faster_rcnn中生成anchors个数是2304个,这里明显多了,但我们发现第四次循环和第五次循环,生成的anchors大小都到256、512,可是图片大小也就128,我暂时的见解是后面这些框没必要生成,太大了。
rpn生成anchors粗劣看了生成结果:
当ratios = [0.5, 1, 2]固定
scales = [128, 256, 512]
生成最小的框128*0.66=84
生成最大的框512/0.66=775
那么就可以得出:
图片大小128*128时 scales = [16, 32, 64] 合适
图片大小1024*1024时 scales = [128, 256, 512] 合适
图片大小512*512时 scales = [64, 128, 256] 合适