该函数的作用是从预测的热力图中获取关键点,并将热力图中的关键点缩放为原图上的关键点,该函数位于eval.py中,完整代码如下
def getPrediction(hms, pt1, pt2, inpH, inpW, resH, resW):
'''
从热力图中获得关键点
'''
assert hms.dim() == 4, 'Score maps should be 4-dim'
maxval, idx = torch.max(hms.view(hms.size(0), hms.size(1), -1), 2)
maxval = maxval.view(hms.size(0), hms.size(1), 1)
idx = idx.view(hms.size(0), hms.size(1), 1) + 1
preds = idx.repeat(1, 1, 2).float()
preds[:, :, 0] = (preds[:, :, 0] - 1) % hms.size(3)#计算关键点的x坐标
preds[:, :, 1] = torch.floor((preds[:, :, 1] - 1) / hms.size(3))#计算关键点的y坐标
pred_mask = maxval.gt(0).repeat(1, 1, 2).float()
preds *= pred_mask
# Very simple post-processing step to improve performance at tight PCK thresholds
for i in range(preds.size(0)):
for j in range(preds.size(1)):
hm = hms[i][j]
pX, pY = int(round(float(preds[i][j][0]))), \
int(round(float(preds[i][j][1])))
if 0 < pX < opt.outputResW - 1 and 0 < pY < opt.outputResH - 1:
diff = torch.Tensor(
(hm[pY][pX + 1] - hm[pY][pX - 1],
hm[pY + 1][pX] - hm[pY - 1][pX]))
preds[i][j] += diff.sign() * 0.25
preds += 0.2
preds_tf = torch.zeros(preds.size())
preds_tf = transformBoxInvert_batch(preds, pt1, pt2, inpH, inpW, resH, resW)
return preds, preds_tf, maxval
该函数在dataloader.py中调用
为了方便代码的理解,依次输出了调试过程中各变量的值
调用该函数时,传入的各变量值为:
hms.shape=torch.Size([2, 17, 80, 64])
hms=tensor([ [ [ [ 7.1406e-06, -8.3787e-06, -4.2975e-06, ..., 6.0789e-06,
-1.1158e-05, 1.0070e-05],
...,
[-1.2371e-05, -9.3881e-06, 3.6857e-06, ..., -9.8551e-06,
-3.5456e-05, 9.0087e-06]],
...,
[ [ 2.2507e-04, 1.6495e-04, 1.8526e-04, ..., 2.1645e-04,
1.6137e-04, 2.3066e-04],
...,
[ 1.6770e-04, 1.9034e-04, 2.2977e-04, ..., 1.8730e-04,
9.3242e-05, 2.4771e-04]]],
[ [ [-1.4953e-04, -5.0633e-07, 9.2041e-09, ..., 1.0909e-05,
7.6110e-06, -6.9278e-05],
...,
[-1.4777e-05, -6.0838e-06, 6.0697e-06, ..., -7.9370e-06,
-3.8374e-05, 7.5062e-06]],
...,
[ [ 2.3423e-04, 1.9299e-04, 2.0025e-04, ..., 2.3365e-04,
2.3001e-04, 5.2406e-04],
...,
[ 1.5949e-04, 2.0223e-04, 4.0982e-04, ..., 1.9344e-04,
8.3786e-05, 2.4526e-04]]]])
pt1=tensor([ [344.1527, 172.4882], [577.4262, 198.1156] ])
pt2=tensor([ [566.1245, 650.4148], [719.0000, 654.6444] ])
inpH=320
inpW=256
resH=80
resW=64
assert hms.dim() == 4, 'Score maps should be 4-dim'
maxval, idx = torch.max(hms.view(hms.size(0), hms.size(1), -1), 2)
hms.size(0)=2
hms.size(1)=17
maxval为每张热力图中的最大值
maxval=tensor([ [0.6315, 0.6346, 0.4302, 0.7716, 0.8475, 0.7838, 0.8432, 0.7915, 0.7231,
0.8305, 0.8499, 0.6293, 0.5305, 0.4960, 0.6881, 0.7562, 0.5072],
[0.8412, 0.7632, 0.7683, 0.6953, 0.3785, 0.5764, 0.6929, 0.4772, 0.4548,
0.6735, 0.5426, 0.3364, 0.2682, 0.2762, 0.2131, 0.5713, 0.5388] ])
idx为每张热力图中最大值对应的索引
idx=tensor([ [ 603, 604, 540, 604, 610, 987, 996, 1881, 1704, 2325, 2219, 2396,
2402, 3356, 3294, 4255, 4191],
[ 615, 553, 551, 555, 617, 1129, 1128, 1959, 1893, 2143, 2207, 2793,
2727, 4077, 4066, 4445, 4445] ])
maxval = maxval.view(hms.size(0), hms.size(1), 1)
idx = idx.view(hms.size(0), hms.size(1), 1) + 1
maxval=tensor([ [ [0.6315], [0.6346], [0.4302], [0.7716], [0.8475], [0.7838], [0.8432], [0.7915],
[0.7231], [0.8305], [0.8499], [0.6293], [0.5305], [0.4960], [0.6881], [0.7562],
[0.5072] ],
[ [0.8412], [0.7632], [0.7683], [0.6953], [0.3785], [0.5764], [0.6929], [0.4772],
[0.4548], [0.6735], [0.5426], [0.3364], [0.2682], [0.2762], [0.2131], [0.5713],
[0.5388] ] ])
这里的idx为什么要+1呢
idx=tensor([ [ [ 604], [ 605], [ 541], [ 605], [ 611], [ 988], [ 997], [1882], [1705], [2326], [2220],
[2397], [2403], [3357], [3295], [4256], [4192] ],
[ [ 616], [ 554], [ 552], [ 556], [ 618], [1130], [1129], [1960], [1894], [2144], [2208],
[2794], [2728], [4078], [4067], [4446], [4446] ] ])
preds = idx.repeat(1, 1, 2).float()
preds = tensor([ [ [ 604., 604.], [ 605., 605.], [ 541., 541.], [ 605., 605.], [ 611., 611.],
[988.,988.], [ 997., 997.], [1882., 1882.], [1705., 1705.], [2326., 2326.],
[2220.,2220.], [2397., 2397.], [2403., 2403.], [3357., 3357.], [3295., 3295.],
[4256., 4256.], [4192., 4192.]],
[ [ 616., 616.], [ 554., 554.],[ 552., 552.], [556.,556.], [618.,618.], [1130.,1130.],
[1129., 1129.], [1960., 1960.], [1894., 1894.], [2144., 2144.], [2208.,2208.],
[2794., 2794.], [2728., 2728.], [4078., 4078.], [4067., 4067.], [4446.,4446.],
[4446., 4446.]]])
preds[:, :, 0] = (preds[:, :, 0] - 1) % hms.size(3)
hms.size(3)=64
获取热力图中最大值的x值坐标
preds=tensor([ [ [ 27., 604.], [ 28., 605.], [ 28., 541.], [ 28., 605.], [ 34., 611.], [ 27., 988.],
[ 36., 997.], [ 25., 1882.], [ 40., 1705.], [ 21., 2326.], [ 43., 2220.], [ 28.,2397.],
[ 34., 2403.], [ 28., 3357.], [ 30., 3295.], [ 31., 4256.], [ 31., 4192.]],
[ [ 39., 616.], [ 41., 554.], [ 39., 552.], [ 43., 556.], [ 41., 618.], [ 41., 1130.],
[40., 1129.], [ 39., 1960.], [ 37., 1894.], [ 31., 2144.], [ 31., 2208.], [ 41.,2794.],
[ 39., 2728.], [ 45., 4078.], [ 34., 4067.], [ 29., 4446.], [ 29., 4446.]]])
preds[:, :, 1] = torch.floor((preds[:, :, 1] - 1) / hms.size(3))#计算关键点的y坐标
获取热力图中最大值的y值坐标
preds=tensor([ [ [27., 9.], [28., 9.], [28., 8.], [28., 9.], [34., 9.], [27., 15.], [36., 15.], [25.,29.],
[40., 26.], [21., 36.], [43., 34.], [28., 37.], [34., 37.], [28., 52.], [30., 51.],
[31.,66.], [31., 65.]],
[ [39., 9.], [41., 8.], [39., 8.], [43., 8.], [41., 9.], [41., 17.], [40., 17.], [39.,30.],
[37., 29.], [31., 33.], [31., 34.], [41., 43.], [39., 42.], [45., 63.], [34., 63.],
[29.,69.], [29., 69.]]])
pred_mask = maxval.gt(0).repeat(1, 1, 2).float()
preds *= pred_mask
pred_mask =tensor([ [ [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.],
[1.,1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.] ],
[ [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.],
[1.,1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.] ] ])
preds = tensor([ [ [27., 9.], [28., 9.], [28., 8.], [28., 9.], [34., 9.], [27., 15.], [36., 15.], [25.,29.],
[40., 26.], [21., 36.], [43., 34.], [28., 37.], [34., 37.], [28., 52.], [30., 51.],
[31.,66.], [31., 65.]],
[ [39., 9.], [41., 8.], [39., 8.], [43., 8.], [41., 9.], [41., 17.], [40., 17.], [39., 30.],
[37., 29.], [31., 33.], [31., 34.], [41., 43.], [39., 42.], [45., 63.], [34., 63.],
[29.,69.], [29., 69.]]])
for i in range(preds.size(0)):
for j in range(preds.size(1)):
hm = hms[i][j]
pX, pY = int(round(float(preds[i][j][0]))), int(round(float(preds[i][j][1])))
if 0 < pX < opt.outputResW - 1 and 0 < pY < opt.outputResH - 1:
diff = torch.Tensor(
(hm[pY][pX + 1] - hm[pY][pX - 1],hm[pY + 1][pX] - hm[pY - 1][pX]))
preds[i][j] += diff.sign() * 0.25
进入for循环后,i=j=0时
hm = hms[i][j]=tensor([ [ 7.1406e-06, -8.3787e-06, -4.2975e-06, ..., 6.0789e-06,
-1.1158e-05, 1.0070e-05]
...,
[-1.2371e-05, -9.3881e-06, 3.6857e-06, ..., -9.8551e-06,
-3.5456e-05, 9.0087e-06]])
hm为一张热力图
round() 方法返回浮点数x的四舍五入值
preds[i][j][0]取关键点的x坐标,preds[i][j][1]取关键点的y坐标
pX=27, pY=9
diff=tensor([ 0.0744, -0.0159])
preds=tensor([ [ [27.2500, 8.7500], [28.0000, 9.0000], [28.0000,8.0000], [28.0000,9.0000],
[34.0000, 9.0000], [27.0000, 15.0000], [36.0000,15.0000], [25.0000,29.0000],
[40.0000,26.0000], [21.0000, 36.0000], [43.0000,34.0000], [28.0000,37.0000],
[34.0000, 37.0000], [28.0000, 52.0000], [30.0000, 51.0000], [31.0000, 66.0000],
[31.0000, 65.0000] ],
[ [39.0000, 9.0000], [41.0000, 8.0000], [39.0000, 8.0000], [43.0000,8.0000],
[41.0000,9.0000], [41.0000,17.0000], [40.0000,17.0000], [39.0000,30.0000],
[37.0000,29.0000], [31.0000, 33.0000], [31.0000, 34.0000], [41.0000,43.0000],
[39.0000, 42.0000], [45.0000, 63.0000], [34.0000, 63.0000], [29.0000, 69.0000],
[29.0000, 69.0000] ] ])
preds += 0.2
preds_tf = torch.zeros(preds.size())
preds_tf = transformBoxInvert_batch(preds, pt1, pt2, inpH, inpW, resH, resW)
preds加2之后
preds=tensor([ [ [27.4500, 8.9500],[27.9500, 8.9500],[27.9500, 7.9500],[28.4500, 9.4500],
[33.9500, 8.9500],[27.4500, 15.4500],[35.9500, 14.9500],[25.4500, 28.9500],
[39.9500, 25.9500],[21.4500, 35.9500],[42.9500, 33.9500],[27.9500, 36.9500],
[33.9500, 37.4500],[27.9500, 51.9500],[29.9500, 51.4500],[31.4500, 66.4500],
[30.9500, 65.4500]],
[ [39.4500, 9.4500],[40.9500, 7.9500],[39.4500, 7.9500],[42.9500, 7.9500],
[40.9500, 8.9500],[41.4500, 16.9500],[39.9500, 17.4500],[39.4500, 29.9500],
[37.4500, 28.9500],[31.4500, 33.4500],[31.4500, 33.9500], [41.4500, 42.9500],
[39.4500, 41.9500],[44.9500, 63.4500],[33.9500, 63.4500],[29.4500, 69.4500],
[29.4500, 69.4500]]])
这里调用了transformBoxInvert_batch()函数
def transformBoxInvert_batch(pt, ul, br, inpH, inpW, resH, resW):
pt的值为上面的preds
ul=tensor([ [344.1527, 172.4882],
[577.4262, 198.1156] ]) 为当前人员目标框在原图像中的左上角坐标
br=tensor([ [566.1245, 650.4148],
[719.0000, 654.6444] ]) 为当前人员目标框在原图像中的右下角坐标
inpH=320
inpW=256
resH=80
resW=64
center = (br - 1 - ul) / 2
size = br - ul #计算出原图像中人员目标框的宽高
size[:, 0] *= (inpH / inpW)
center = (br - 1 - ul) / 2=tensor([ [110.4859, 238.4633],
[ 70.2869, 227.7644] ])
size = br - ul=tensor([ [221.9717, 477.9266],
[141.5738, 456.5288]])
size[:, 0] *= (inpH / inpW)=tensor([ [277.4646, 477.9266],
[176.9672, 456.5288] ])
lenH, _ = torch.max(size, dim=1) # [n,]
lenW = lenH * (inpW / inpH)
_pt = (pt * lenH[:, np.newaxis, np.newaxis]) / resH #映射到原图中人员目标框图像上
将热力图上的坐标点映射到原图中的人员目标框图像上,注意该人员目标框是以目标框左上角为坐标原点,并不是将关键点坐标映射到原图上
lenH=tensor([477.9266, 456.5288]), _ = tensor([1, 1])
lenW = tensor([382.3413, 365.2231])
np.newaxis=None
_pt = tensor([ [ [163.9886, 53.4680],
...,
[184.8979, 391.0037]],
[ [225.1258, 53.9275],
...,
[168.0597, 396.3240]]])
_pt[:, :, 0] = _pt[:, :, 0] - ((lenW[:, np.newaxis].repeat(1, 17) - 1) /
2 - center[:, 0].unsqueeze(-1).repeat(1, 17)).clamp(min=0)
_pt[:, :, 1] = _pt[:, :, 1] - ((lenH[:, np.newaxis].repeat(1, 17) - 1) /
2 - center[:, 1].unsqueeze(-1).repeat(1, 17)).clamp(min=0)
对上面的lenW和这一步的代码作用不理解!
此时_pt=tensor([ [ [ 83.8038, 53.4680],
...,
[104.7131, 391.0037]],
[ [113.3011, 53.9275],
...,
[ 56.2350, 396.3240]]])
new_point = torch.zeros(pt.size())
new_point[:, :, 0] = _pt[:, :, 0] + ul[:, 0].unsqueeze(-1).repeat(1, 17)
new_point[:, :, 1] = _pt[:, :, 1] + ul[:, 1].unsqueeze(-1).repeat(1, 17)
将坐标点加上人员目标框左上角在原图中的x,y坐标,得到关键点在原图中的坐标
new_point.shape = torch.Size([2, 17, 2])
new_point = tensor([ [ [427.9565, 225.9562],
...,
[448.8658, 563.4919]],
[ [690.7274, 252.0431],
...,
[633.6613, 594.4396]]])
return new_point
最后将关键点返回
调用完transformBoxInvert_batch()函数之后
preds_tf=tensor([ [ [427.9565, 225.9562],[430.9435, 225.9562],[430.9435, 219.9821],
[433.9306,228.9433],[466.7881, 225.9562],[427.9565,264.7878],
[478.7362,261.8007], [416.0084, 345.4379],[502.6326, 327.5156],
[392.1120,387.2565], [520.5548, 375.3083], [430.9435, 393.2305],
[466.7881, 396.2176], [430.9435, 482.8418], [442.8917,479.8547],
[451.8528, 569.4659], [448.8658, 563.4919]],
[ [690.7274, 252.0431],[699.2873, 243.4832],[690.7274, 243.4832],
[710.7005,243.4832], [699.2873, 249.1898],[702.1406, 294.8427],
[693.5807,297.6960],[690.7274, 369.0286],[679.3141, 363.3220],
[645.0745,389.0017],[645.0745, 391.8550],[702.1406, 443.2145],
[690.7274,437.5079], [722.1137, 560.2000],[659.3410, 560.2000],
[633.6613, 594.4396], [633.6613, 594.4396] ] ])
return preds, preds_tf, maxval
最后将(预测骨架点在热力图中的位置,预测骨架点在原图中的位置,每张热力图的最大值)返回