# 锚框

“我们以图像的每个像素为中心生成不同形状的锚框： 比例 为 s∈(0,1]， 宽高比 （宽高比）为 r>0。”

1 Like

multibox_prior函数的代码中，

w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),sizes[0] * torch.sqrt(ratio_tensor[1:]))) * in_height / in_width
h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]), sizes[0] / torch.sqrt(ratio_tensor[1:])))

w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]), sizes[0] * torch.sqrt(ratio_tensor[1:])))
* math.sqrt(in_height / in_width)
h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]), sizes[0] / torch.sqrt(ratio_tensor[1:])))
* math.sqrt(in_width / in_height)

1 Like

a_w = hs * sqrt(r)
a_h = hs / sqrt(r)
a_w / a_h = r
a_w * a_h = h^2 * s^2


boxes = Y.view(h, w, 5, 4)

a = boxes[250, 250, 0, :]

print(a)

top_left = a[:2]

down_right = a[2:]

print(top_left, down_right)

a_w = down_right[0] - top_left[0]

a_h = down_right[1] - top_left[1]

print(a_w, a_h)

# a_w / a_h == r

print((a_w * w) / (a_h * h))

# a_w * a_h == h^2 * s^2

print((a_w * w) * (a_h * h), h * h * 0.75 * 0.75)

sizes[0] * torch.sqrt(ratio_tensor[1:])))
* in_height / in_width # Handle rectangular inputs
。w,h在上边的代码里进行归一化了（steps_h = 1.0 / in_height）。所以公式里的w,h没有了。代码中的in_height / in_width是为了生成边界框的比例与输入图像比例保持一致，比如输入图像是1000100的话，生成的锚框也该是这个比例的。

s是对宽和高的单独放缩，总面积应该是放缩到s^2，r是对于原来的高宽比的放缩，例如原来的高宽比是h/w，添加r后变成了(h/w)*r，我觉得有问题的是这一段代码：

 w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),
sizes[0] * torch.sqrt(ratio_tensor[1:])))\
* in_height / in_width  # Handle rectangular inputs
h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]),
sizes[0] / torch.sqrt(ratio_tensor[1:])))


 左上：（center_x-w*s*sqrt(r)/2，center_y-h*s/sqrt(r)/2）
 右下：（center_x+w*s*sqrt(r)/2，center_y+h*s/sqrt(r)/2）

 左上：（center_x/w-s*sqrt(r)/2，center_y/h-s/sqrt(r)/2）
 右下：（center_x/w+s*sqrt(r)/2，center_y/h+s/sqrt(r)/2）

 w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),
sizes[0] * torch.sqrt(ratio_tensor[1:])))
h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]),
sizes[0] / torch.sqrt(ratio_tensor[1:])))


anchor_manipulations = torch.stack(
(-w, -h, w, h)).T.repeat(in_height * in_width, 1) / 2
anchor_manipulations 得到了真正的归一化的偏移量

11 Likes

w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),sizes[0] * torch.sqrt(ratio_tensor[1:])))* in_height / in_width到底为什么* in_height / in_width

2 Likes

center_h = (torch.arange(in_height, device=device) + offset_h) * steps_h 这里出来的是1，3，5，7…的1d tensor. 但不是每个pixel都是中心吗？为什么会跳一个pixel啊

S就是Size, 即锚框大小占输入图片大小的比率，比如size=0.5, 即输入图像的一半。
r的解释稍有不准，原文说是“宽高比”， 锚框的宽度和高度分别是 wsr√wsr 和 hs/r√hs/r

1 Like

1、matplotlib在生成图像的时候，X轴和Y轴坐标的刻度不是一致的，所以s值为X、Y两个轴的比例；
2、h_a * w_a = sshw
w_a/h_a = r

sqrt(rhw)

3、由于X，Y坐标轴刻度不一致，为了锚框宽高比和视觉一致， w_a = s * sqrt® * h / w

1 Like

r是指锚框的宽高比与图像的宽高比之比即w’/h’ = w/h*r，s是图像尺寸缩放因子即w’h’=whs^2，联立求解即可得文中的锚框宽高即w’=ws×sqrt( r ),h’=hs/sqrt( r )。

3 Likes

# 此函数中，ratio为锚框的真实宽高比
# data: (batch_size, num_channels, height, width)
def multibox_prior(data, sizes, ratios):
in_height, in_width = data.shape[-2:]
device, num_sizes, num_ratios = data.device, len(sizes), len(ratios)
boxes_per_pixel = (num_sizes + num_ratios - 1)
size_tensor = torch.tensor(sizes, device=device)
size_ratio = torch.tensor(ratio, device=device)
offset_h, offset_w = 0.5, 0.5
step_h = 1.0 / in_height
step_w = 1.0 / in_width
# (center_h, center_w): 每个锚框缩放后的中心点的坐标
center_h = (torch.arange(in_height, device=device) + offset_h) * step_h
center_w = (torch.arange(in_width, device=device) + offset_w) * steps_w
#     center_h = tensor([1, 2, 3, 4])
#     center_w = tensor([1, 2, 3])
#
#     shift_y = tensor([[1, 1, 1],    即在第0维叠加
#                       [2, 2, 2],
#                       [3, 3, 3],
#                       [4, 4, 4]])
#     shift_x = tensor([[1, 2, 3],    即在第1维叠加
#                       [1, 2, 3],
#                       [1, 2, 3],
#                       [1, 2, 3]])
#     shift_x = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3] ^ T
#     shift_y = [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4] ^ T
#     (shift_x, shift_y) 即是全部点的坐标
shift_y, shift_x = torch.meshgrid(center_h, center_w)
shift_y, shift_x = shift_y.reshape(-1), shift_x.reshape(-1)
# 由于ratio为真实比例，因此当 ratio=1 时，应满足 w=h，故要乘以 in_height / in_width
# 又由于上面的 shift_x 和 shift_y 已经缩放到 [0,1] 范围，
# 因此这里不用乘以 in_width 和 in_height
w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),
sizes[0] * torch.sqrt(ratio_tensor[1:])))\
* in_height / in_width
h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]),
sizes[0] / torch.sqrt(ratio_tensor[1:])))
# 每一行对应一个锚框的左上角偏差和右下角偏差
anchor_manipulations = torch.stack((-w, -h, w, h)).T.repeat(
in_height * in_width, 1) / 2
# 每一行对应锚框的中心点重复两次
out_grid = torch.stack([shift_x, shift_y, shift_x, shift_y],
dim=1).repeat_interleave(boxes_per_pixel, dim=0)
# 加起来之后，就是锚框左上和右下的真实坐标
output = out_grid + anchor_manipulations
# 第一维是批量大小，要生成这一维
return output.unsqueeze(0)

1 Like

wei为什么通过交并比判断锚框中的列别会有两个锚框都判断为猫啊，安照将真实边界框分配给锚框基于最大交并比的规则不应该只有一个锚框为猫嘛!

inter_upperlefts = torch.max(boxes1[:, None, :2], boxes2[:, :2])