一、写在开头
这次主要记录关于Retinaface的默认框生成
部分。
下面是代码地址:
Retinaface代码地址
主要包括的脚本为:
prior_box.py
也欢迎阅读其上一篇博客Retinaface代码记录(一)。可以帮助读者对本片博客可以有一个整体上的把握和理解。
二、主要内容
这个主要包含一个PriorBox类,首先在__init__
中传入一系列后续要用到的参数,然后在forward()中,来获取一系列默认框。具体获取方式:先遍历三个特征图,(特征图大小为[80,40,20]论文中提到的是5个,但代码实现只有3个,如下图。)获取默认框大小,即min_sizes[k],然后遍历特征图的每个像素点(itertools.product()即返回相应的笛卡尔坐标,各个坐标值相应配对),s_kx,s_ky代表的是默认框的宽w和高h;dense_cx,dense_cy包含的是默认框的中心点,即遍历获取的特征图的像素点。这里我们可以看到,x,y乘以的是steps/image_size,因为feature_map和steps的乘积正好是image的大小,这样处理刚好等分遍历完整个图像。最后变化下anchors的形状([x,y,w,h]这个样子),并将其归一化于0-1之间(clamp()即将输入压缩与min和max之间,小于min的记为min,大于max的记为max),因为论文中 the aspect ratio at 1:1,所以直接返回即可。
prior_box.py
:
import torch
from itertools import product as product
import numpy as np
from math import ceil
class PriorBox(object):
def __init__(self, cfg, image_size=None, phase='train'):
super(PriorBox, self).__init__()
self.min_sizes = cfg['min_sizes'] # 'min_sizes': [[16, 32], [64, 128], [256, 512]]
self.steps = cfg['steps'] # 'steps': [8, 16, 32]
self.clip = cfg['clip'] # 'clip': False
self.image_size = image_size # cfg_mnet中'image_size': 640, cfg_re50中'image_size': 840
self.feature_maps = [[ceil(self.image_size[0]/step), ceil(self.image_size[1]/step)] for step in self.steps] #feature_maps : [80,40,20]
self.name = "s"
def forward(self):
anchors = []
for k, f in enumerate(self.feature_maps):
min_sizes = self.min_sizes[k]
for i, j in product(range(f[0]), range(f[1])):
for min_size in min_sizes:
s_kx = min_size / self.image_size[1]
s_ky = min_size / self.image_size[0]
dense_cx = [x * self.steps[k] / self.image_size[1] for x in [j + 0.5]]
dense_cy = [y * self.steps[k] / self.image_size[0] for y in [i + 0.5]]
for cy, cx in product(dense_cy, dense_cx):
anchors += [cx, cy, s_kx, s_ky]
# back to torch land
output = torch.Tensor(anchors).view(-1, 4)
if self.clip:
output.clamp_(max=1, min=0)
return output
三、结尾
默认框生成
的介绍到这里就结束了。有什么疑问的,可以看下我的这篇博客,里面是一个综述。