参数化公式如下: 预测偏移转预测框时(decode解码)(均以中心表示)
a n c h o r 框 ( a n c h o r s ) : ( x a , y a , h a , w a ) 预测框与 a n c h o r 框的差值 ( p r e d _ b b o x _ d e l t a s ) : ( t x , t y , t h , t w ) 预测框 ( 解码结果 ) : ( x , y , h , w ) x = t x w a + x a y = t y y a + y a w = w a ∗ e t w h = h a ∗ e t h \begin{align} anchor框(anchors)&:(x_a,y_a,h_a,w_a)\\ 预测框与anchor框的差值(pred\_bbox\_deltas)&:(t_x,t_y,t_h,t_w) \\ 预测框(解码结果)&:(x,y,h,w) \\ x&=t_xw_a + x_a\\ y&=t_yy_a + y_a\\ w&=w_a*e^{t_w}\\ h&=h_a*e^{t_h}\\ \end{align}\\ anchor框(anchors)预测框与anchor框的差值(pred_bbox_deltas)预测框(解码结果)xywh:(xa,ya,ha,wa):(tx,ty,th,tw):(x,y,h,w)=txwa+xa=tyya+ya=wa∗etw=ha∗eth
注意指数运算会可能会爆炸 需要对 t w , t h 执行 c l a m p 到 l n ( 62.5 ) , 即缩放后限制到 62.5 注意指数运算会可能会爆炸\\ 需要对t_w,t_h执行clamp到ln(62.5),即缩放后限制到62.5\\ 注意指数运算会可能会爆炸需要对tw,th执行clamp到ln(62.5),即缩放后限制到62.5
代码逻辑
处理输入
1.基础 anchors,形如:
[torch.Size([787464, 4]),
torch.Size([787464, 4]),
torch.Size([787464, 4]),
torch.Size([787464, 4])]
一共4个图像,每个图像有787464个候选框,每个候选框含4个坐标
2.rpnhead的pred_bbox_deltas,形如:
[torch.Size([4, 36, 198, 334]),
torch.Size([4, 36, 98, 166]),
torch.Size([4, 36, 48, 82]),
torch.Size([4, 36, 23, 40]),
torch.Size([4, 36, 12, 20])]
list每一行是一个FPN层级,每个层级:[batch_size,4*9,h,w] 第一维度是4个图像,每个图像有9个候选框,每个候选框含4个坐标,故而为36,后面是h和w
对于每一张图候选框数量为: 787464 = (198x334+98x166+48x82+23x40+12x20)x9
对于所有的图候选框数量为: 787646 x 4 = 3149856
整理一下数据,将 anchors和pred_bbox_deltas格式转为一致 Tensor(3149856,4)得:
anchors-> boxes; pred_bbox_deltas->rel_codes
代码参见: torchvision.models.detection.rpn.concat_box_prediction_layers
实际计算
- 先将boxes的x1,y1.x2,y2转为 w,h,cx.cy(2点表示转中心宽高)
- 从rel_codes获取xywh偏移dx,dy,dw,dh.即0,1,2,3位置,(可能存在权重,如果存在就要除权重)
- 限制dw,dh再范围内math.log(1000.0 / 16)
- 计算偏移后坐标
p c x = d x ∗ w + c x p c y = d y ∗ h + c y p w = e x p ( d w ) ∗ w p h = e x p ( d h ) ∗ h pcx = dx*w + cx\\ pcy = dy*h + cy\\ pw = exp(dw) * w\\ ph = exp(dh) * h\\ pcx=dx∗w+cxpcy=dy∗h+cypw=exp(dw)∗wph=exp(dh)∗h - 再将p转为2点表示
- 合并tensor
示意代码如下
@staticmethod
def decode(anchors, rel_codes):
"""
对RpnHead的pred_bbox_deltas进行解码操作,得到真的预测框
"""
concat_boxes = torch.cat(anchors, dim=0)
max_clip = math.log(62.5)
# 2点表示转中心宽高
w = concat_boxes[:, 2] - concat_boxes[:, 0]
h = concat_boxes[:, 3] - concat_boxes[:, 1]
cx = concat_boxes[:, 0] + 0.5 * w
cy = concat_boxes[:, 1] + 0.5 * h
# 获取偏移dx,dy,dw,dh.即0,1,2,3位置,(可能存在权重,如果存在就要除权重)
dx = rel_codes[:, 0]
dy = rel_codes[:, 1]
dw = rel_codes[:, 2]
dh = rel_codes[:, 3]
# 限制偏移再范围内
dw = torch.clamp(dw, max=max_clip)
dh = torch.clamp(dh, max=max_clip)
# 计算中心宽高表示的预测框,p表示predict
pcx = dx * w + cx
pcy = dy * h + cy
pw = torch.exp(dw) * w
ph = torch.exp(dh) * h
# 中心宽高换2点表示
pw2 = pw/2
ph2 = ph/2
px1 = pcx - pw2
py1 = pcy - ph2
px2 = pcx + pw2
py2 = pcy + ph2
# 合并tensor
pred_boxes = torch.stack((px1, py1, px2, py2), dim=1)
return pred_boxes