(原)人體姿態識別alphapose


轉載請注明出處:

https://www.cnblogs.com/darkknightzh/p/12150171.html

論文

RMPE: Regional Multi-Person Pose Estimation

https://arxiv.org/abs/1612.00137

官方代碼:

https://github.com/MVIG-SJTU/AlphaPose

官方pytorch代碼:

https://github.com/MVIG-SJTU/AlphaPose/tree/pytorch

1. 簡介

該論文指出,定位和識別中不可避免的會出現錯誤,這些錯誤會引起單人姿態估計(single-person pose estimator,SPPE)的錯誤,特別是完全依賴人體檢測的姿態估計算法。因而該論文提出了區域姿態估計(Regional Multi-Person Pose Estimation,RMPE)框架。主要包括symmetric spatial transformer network (SSTN)、Parametric Pose Non- Maximum-Suppression (NMS), 和Pose-Guided Proposals Generator (PGPG)。並且使用symmetric spatial transformer network (SSTN)、deep proposals generator (DPG) 、parametric pose nonmaximum suppression (p-NMS) 三個技術來解決野外場景下多人姿態估計問題。

2. 之前算法的問題

2.1檢測框定位錯誤

如下圖所示。紅框為真實框,黃框為檢測到的框(IoU>0.5)。由於定位錯誤,黃框得到的熱圖無法檢測到關節點

解決方法:增大訓練時的框(框增大0.2-0.3倍)

2.2 檢測框冗余

如下圖所示。同一個人可能檢測到多個框。

解決方法:使用p-NMS來解決人體檢測框不准確時的姿態估計問題。

3. 網絡結構

3.1 總體結構

總體網絡結構如下圖:

Symmetric STN=STN+SPPE+SDTN

STN:空間變換網絡,對於不准確的輸入,得到准確的人的框。輸入候選區域,用於獲取高質量的候選區域。

SPPE:得到估計的姿態。

SDTN:空間逆變換網絡,將估計的姿態映射回原始的圖像坐標。

Pose-NMS:消除額外的估計到的姿態

Parallel SPPE:訓練階段作為額外的正則項,避免陷入局部最優,並進一步提升SSTN的效果。包含相同的STN及SPPE(所有參數均被凍結),無SDTN。測試階段無此模塊。

PGPG(Pose-guided Proposals Generator):通過PGPG網絡得到訓練圖像,用來訓練SSTN+SPPE模塊。

3.2 SSTN

SSTN如下圖所示。不准確的輸入(下圖左側input)經過STN+SPPE+SDTN,先姿態估計,把估計結果映射到原圖,以此來調整原本的框,使框變的精准。其中中間黑色虛線的框認為是准確的輸入(即中心化的輸入,將姿態對齊到圖像中心)。

3.3 STN和SDTN

STN為2D的仿射變換,定義如下:

SDTN定義如下:

其中為變換后坐標,為變換前坐標。${{\theta }_{1}}$,${{\theta }_{2}}$,${{\theta }_{3}}$,${{\gamma }_{1}}$,${{\gamma }_{2}}$,${{\gamma }_{3}}$為變換參數關系如下:

(使用SDTN進行反向傳播的公式請見論文)

3.4 Parallel SPPE(PSPPE)

PSPPE模塊和原始的SPPE共享相同的STN參數,但是無SDTN模塊。此分支的人體姿態已經中心化,和中心化后的真知標簽直接比較。訓練階段,PSPPE所有層的參數均被凍結,目的是反傳中心化的姿態誤差到STN模塊。因而若STN得到的姿態未中心化,會產生較大的誤差,使得STN集中於正確的區域。

可以講PSPPE作為訓練階段額外的正則項。

3.5 P-NMS

定義:令第i個姿態由m個關節點組成,定義為$\left\{ \left\langle k_{i}^{1},c_{i}^{1} \right\rangle ,\cdots ,\left\langle k_{i}^{m},c_{i}^{m} \right\rangle  \right\}$,其中k為location,c為socre。

消除過程:score最高的姿態作為基准,重復消除接近基准姿態的姿態,直到剩下單一的姿態。

消除准則:消除標准用於重復消除剩余姿態,為:

$f({{P}_{i}},{{P}_{j}}|\Lambda ,\eta )=\mathbf{1}(d({{P}_{i}},{{P}_{j}}|\Lambda ,\lambda )\le \eta )$

其中,距離函數$d(\centerdot )$包括姿態距離和空間距離,若$d(\centerdot )$不大於$\eta $,則上面$f(\centerdot )$的輸出為1,表明由於${{P}_{i}}$和基准姿態${{P}_{j}}$過於相似,因而${{P}_{i}}$需要被消除。其定義如下:

$d({{P}_{i}},{{P}_{j}}|\Lambda )\text{=}{{K}_{Sim}}({{P}_{i}},{{P}_{j}}|{{\sigma }_{1}})+\lambda {{H}_{sim}}({{P}_{i}},{{P}_{j}}|{{\sigma }_{2}})$

其中,$\Lambda =\{{{\sigma }_{1}},{{\sigma }_{2}},\lambda \}$。

姿態距離用於消除和其他姿態太近且太相似的姿態,假定${{P}_{i}}$的bbox是${{B}_{i}}$,其定義為如下的soft matching公式(不同特征之間score的相似度):

其中$B(k_{i}^{n})$為中心在$k_{i}^{n}$的box,並且每個坐標$B(k_{i}^{n})$為原始坐標${{B}_{i}}$的1/10。

如下圖所示。其中藍框為關節點${{P}_{i}}$的框,各黑點為藍框${{P}_{i}}$各個關節點位置$k_{i}^{n}$(為了方便,只顯示了4個),各紅框為寬高為藍框1/10的子框,其中心為相應的關節點$k_{i}^{n}$,三角為姿態${{P}_{j}}$在紅框內的關節點$k_{j}^{n}$,五星為姿態${{P}_{j}}$在紅框外關節點$k_{j}^{n}$。進行消除時,對三角使用上式的if進行消除,因該點在子框內;對五星使用otherwise,因該點在子框外(左上角既有三角,又有五星。實際上對於一個檢測到的姿態${{P}_{j}}$,是不會出現這種情況的,因為一個姿態的某個特定關節點只有一個,不會出現三角和五星兩個關節點。此處只是顯示使用)。

空間距離用於衡量不同特征之間空間距離的相似度,令$k_{i}^{n}$和$k_{j}^{n}$為不同特征中心,其定義如下:

${{H}_{sim}}({{P}_{i}},{{P}_{j}}|{{\sigma }_{2}})=\sum\limits_{n}{\exp [-\frac{{{(k_{i}^{n}-k_{j}^{n})}^{2}}}{{{\sigma }_{2}}}]}$

$\lambda $為平衡姿態距離和空間距離的權重。$\eta $為閾值。上式共四個參數${{\sigma }_{1}}$,${{\sigma }_{2}}$,$\lambda $,$\eta $,論文中說交替固定2個,訓練另外兩個。但是pytorch代碼中全部固定了。

3.6 PGPG

步驟:

1 歸一化姿態,使得所有軀干有歸一化長度。

2 使用kmeans聚類對齊的姿態,並且聚類得到的中心形成atomic poses。

3 對有相同atomic poses的人,計算gt bbox和detected bbox的偏移。

4 偏移使用gt bbox進行歸一化。

5 此時,偏移作為頻率的分布,且固定數據為高斯混合分布。對於不同的atomic poses,有不同的高斯混合分布的參數。

注:沒看此部分對應的代碼

4. 代碼

4.1 前向推斷

網絡前向推斷使用InferenNet_fast函數,其中輸入圖像x為通過yolo V3檢測到的單張人體。

輸出為熱圖。out.narrow原因是,訓練時使用了COCO和MPII,因而特征維數維33,前17層為COCO特征。代碼中只測試COCO上性能,因而只取前17層熱圖。

 1 class InferenNet_fast(nn.Module):
 2     def __init__(self, kernel_size, dataset):
 3         super(InferenNet_fast, self).__init__()
 4 
 5         model = createModel().cuda()
 6         print('Loading pose model from {}'.format('./models/sppe/duc_se.pth'))
 7         model.load_state_dict(torch.load('./models/sppe/duc_se.pth'))
 8         model.eval()
 9         self.pyranet = model   # 圖像得到33維熱圖
10         self.dataset = dataset
11 
12     def forward(self, x):
13         out = self.pyranet(x)   # 得到b*33*h*w的矩陣
14         # https://github.com/MVIG-SJTU/AlphaPose/issues/187#issuecomment-441416429 指出,代碼聯合訓練COCO和MPII,前17個為COCO,后16個為MPII,故此處取前17層
15         out = out.narrow(1, 0, 17)  # data = tensor:narrow(dim, index, size)取出tensor中第dim維上索引從index開始到index+size-1的所有元素存放在data中
16 
17         return out   # 圖像得到33維熱圖,取出channel上0—16維特征
18 
19 
20 def createModel():
21     return FastPose()
22 
23 
24 class FastPose(nn.Module):
25     DIM = 128
26 
27     def __init__(self):
28         super(FastPose, self).__init__()
29         self.preact = SEResnet('resnet101')   # 101層SE_ResNet
30         self.suffle1 = nn.PixelShuffle(2) #將Input: (N, C∗upscale_factor * upscale_factor2, H, W)轉換成輸出Output: (N, C, H∗upscale_factor, W∗upscale_factor),此處upscale_factor=2
31         self.duc1 = DUC(512, 1024, upscale_factor=2)   # conv+BN+ReLU+PixelShuffle, PixelShuffle將1024維降低到256維
32         self.duc2 = DUC(256, 512, upscale_factor=2)    # conv+BN+ReLU+PixelShuffle, PixelShuffle將512維降低到128維
33         self.conv_out = nn.Conv2d(self.DIM, opt.nClasses, kernel_size=3, stride=1, padding=1) # 128維降低到33維
34 
35     def forward(self, x: Variable):
36         out = self.preact(x)
37         out = self.suffle1(out)
38         out = self.duc1(out)
39         out = self.duc2(out)
40 
41         out = self.conv_out(out)
42         return out
43 
44 
45 class DUC(nn.Module):
46     '''
47     INPUT: inplanes, planes, upscale_factor
48     OUTPUT: (planes // 4)* ht * wd
49     '''
50     def __init__(self, inplanes, planes, upscale_factor=2):
51         super(DUC, self).__init__()
52         self.conv = nn.Conv2d(inplanes, planes, kernel_size=3, padding=1, bias=False)
53         self.bn = nn.BatchNorm2d(planes)
54         self.relu = nn.ReLU()
55 
56         self.pixel_shuffle = nn.PixelShuffle(upscale_factor)  #將Input: (N, C∗upscale_factor * upscale_factor2, H, W)轉換成輸出Output: (N, C, H∗upscale_factor, W∗upscale_factor)
57 
58     def forward(self, x):
59         x = self.conv(x)
60         x = self.bn(x)
61         x = self.relu(x)
62         x = self.pixel_shuffle(x)
63         return x
View Code

4.2 預測

預測代碼如下:

 1 def getPrediction(hms, pt1, pt2, inpH, inpW, resH, resW):  # 由於對人體檢測后裁剪的圖像進行預測,后6個參數為裁剪圖像的相關信息
 2     '''Get keypoint location from heatmaps'''
 3     assert hms.dim() == 4, 'Score maps should be 4-dim'
 4     # 每個通道最大值作為關節點,因為是自頂向下,前提就是每張圖只有一個人,因而每個通道只有一個關節點
 5     maxval, idx = torch.max(hms.view(hms.size(0), hms.size(1), -1), 2)  # hms.size(0)為batchsize,hms.size(1)為channels,熱圖中h*w變成一維后的最大值及索引
 6 
 7     maxval = maxval.view(hms.size(0), hms.size(1), 1)  # b*c*1的矩陣
 8     idx = idx.view(hms.size(0), hms.size(1), 1) + 1    # b*c*1的矩陣,+1是用於防止計算xy坐標時錯誤
 9 
10     preds = idx.repeat(1, 1, 2).float()  # b*c*2的矩陣,將第2維重復一遍
11 
12     preds[:, :, 0] = (preds[:, :, 0] - 1) % hms.size(3)                 # 得到x坐標
13     preds[:, :, 1] = torch.floor((preds[:, :, 1] - 1) / hms.size(3))    # 得到y坐標
14 
15     pred_mask = maxval.gt(0).repeat(1, 1, 2).float()   # 最大值中大於0的第2維重復一遍
16     preds *= pred_mask   # 去掉maxval小於0對應的坐標
17 
18     # Very simple post-processing step to improve performance at tight PCK thresholds
19     for i in range(preds.size(0)):        # 遍歷batchsize中每個輸入的預測
20         for j in range(preds.size(1)):    # 遍歷每個channels
21             hm = hms[i][j]                # 當前熱圖
22             pX, pY = int(round(float(preds[i][j][0]))), int(round(float(preds[i][j][1])))    # 當前坐標
23             # 得到熱圖每個關節點的坐標后,進一步結合上下左右四個點,優化坐標(論文中沒有提到)
24             if 0 < pX < opt.outputResW - 1 and 0 < pY < opt.outputResH - 1:                  # 當前坐標在特征圖內
25                 diff = torch.Tensor((hm[pY][pX + 1] - hm[pY][pX - 1], hm[pY + 1][pX] - hm[pY - 1][pX]))  # 當前熱圖點右側減左側值,當前點熱圖下邊減上邊值
26                 preds[i][j] += diff.sign() * 0.25  # diff.sign()得到diff每個元素的正負;此處將preds進行偏移
27     preds += 0.2   # preds進一步偏移??
28 
29     preds_tf = torch.zeros(preds.size())
30     preds_tf = transformBoxInvert_batch(preds, pt1, pt2, inpH, inpW, resH, resW)  # 熱圖中關節點坐標映射回原始圖像上的坐標
31 
32     return preds, preds_tf, maxval   # 返回關節點在原始圖像裁剪后圖像上的坐標,在原始圖像上的坐標,熱圖最大值
View Code

4.3 P-NMS

p _poseNMS.py配置參數如下(固定的參數,並未體現出通過訓練得到):

  1 delta1 = 1
  2 mu = 1.7
  3 delta2 = 2.65
  4 gamma = 22.48
  5 scoreThreds = 0.3
  6 matchThreds = 5
  7 areaThres = 0#40 * 40.5
  8 alpha = 0.1
  9 
 10 pose_nms如下:
 11 def pose_nms(bboxes, bbox_scores, pose_preds, pose_scores):
 12     '''
 13     Parametric Pose NMS algorithm
 14     bboxes:         bbox locations list (n, 4)
 15     bbox_scores:    bbox scores list (n,)    #       各個框為人的score
 16     pose_preds:     pose locations list (n, 17, 2)   各關節點的坐標
 17     pose_scores:    pose scores list    (n, 17, 1)   各個關節點的score
 18     '''
 19     #global ori_pose_preds, ori_pose_scores, ref_dists
 20 
 21     pose_scores[pose_scores == 0] = 1e-5
 22     final_result = []
 23 
 24     ori_bbox_scores = bbox_scores.clone()   # 各個框為人的score,下面要刪除,此處先備份
 25     ori_pose_preds = pose_preds.clone()     # 各關節點的坐標,下面要刪除,此處先備份
 26     ori_pose_scores = pose_scores.clone()   # 各個關節點的score,下面要刪除,此處先備份 [n, 17, 1]
 27 
 28     xmax = bboxes[:, 2]   # 檢測到的人在原始圖像上的坐標
 29     xmin = bboxes[:, 0]
 30     ymax = bboxes[:, 3]
 31     ymin = bboxes[:, 1]
 32 
 33     widths = xmax - xmin   # 檢測到的人的寬高
 34     heights = ymax - ymin
 35     ref_dists = alpha * np.maximum(widths, heights)   # alpha=0.1,為論文中的1/10,此處為NMS中當前batch各個人子框的閾值[n,]
 36 
 37     nsamples = bboxes.shape[0]
 38     human_scores = pose_scores.mean(dim=1)  # 當前batch各個人姿態的均值 [n, 1]
 39     human_ids = np.arange(nsamples)
 40     pick = []            # Do pPose-NMS
 41     merge_ids = []
 42     while(human_scores.shape[0] != 0):
 43         pick_id = torch.argmax(human_scores)     # Pick the one with highest score   找出分值最高的姿態的索引
 44         pick.append(human_ids[pick_id])          # 由於后面要delete array的部分值,因而此處保存索引
 45         # num_visPart = torch.sum(pose_scores[pick_id] > 0.2)
 46 
 47         ref_dist = ref_dists[human_ids[pick_id]]  # Get numbers of match keypoints by calling PCK_match  當前人NMS子框的閾值
 48         simi = get_parametric_distance(pick_id, pose_preds, pose_scores, ref_dist)   # 公式(10)的距離,[n],由於每次均會刪除id,因而n遞減
 49         num_match_keypoints = PCK_match(pose_preds[pick_id], pose_preds, ref_dist)   # 返回滿足條件的點的數量,[n],由於每次均會刪除id,因而n遞減
 50 
 51         # Delete humans who have more than matchThreds keypoints overlap and high similarity   # gamma = 22.48,matchThreds = 5,
 52         delete_ids = torch.from_numpy(np.arange(human_scores.shape[0]))[(simi > gamma) | (num_match_keypoints >= matchThreds)]  # 迭代刪除的索引
 53 
 54         if delete_ids.shape[0] == 0:
 55             delete_ids = pick_id
 56         #else:
 57         #    delete_ids = torch.from_numpy(delete_ids)
 58 
 59         merge_ids.append(human_ids[delete_ids])    # 每次篩選出來的人的索引,如果沒有近距離的人,merge_ids==pick
 60         pose_preds = np.delete(pose_preds, delete_ids, axis=0)
 61         pose_scores = np.delete(pose_scores, delete_ids, axis=0)
 62         human_ids = np.delete(human_ids, delete_ids)
 63         human_scores = np.delete(human_scores, delete_ids, axis=0)
 64         bbox_scores = np.delete(bbox_scores, delete_ids, axis=0)
 65 
 66     assert len(merge_ids) == len(pick)
 67     preds_pick = ori_pose_preds[pick]            # 根據pick重新映射后的不同人各關節點的坐標
 68     scores_pick = ori_pose_scores[pick]
 69     bbox_scores_pick = ori_bbox_scores[pick]
 70     #final_result = pool.map(filter_result, zip(scores_pick, merge_ids, preds_pick, pick, bbox_scores_pick))
 71     #final_result = [item for item in final_result if item is not None]
 72 
 73     for j in range(len(pick)):   # 人的數量。此處是當人體檢測器檢測的不好,同一個人檢測到了2個以上的框,這些框比較接近的情況
 74         ids = np.arange(17)
 75         max_score = torch.max(scores_pick[j, ids, 0])
 76 
 77         if max_score < scoreThreds:
 78             continue
 79 
 80         merge_id = merge_ids[j]  # Merge poses
 81         # 返回冗余關節點位置和這些關節點對應的score。無冗余姿態的情況下,merge_pose==preds_pick[j]==ori_pose_preds[merge_id],merge_score==ori_pose_scores[merge_id]
 82         merge_pose, merge_score = p_merge_fast(preds_pick[j], ori_pose_preds[merge_id], ori_pose_scores[merge_id], ref_dists[pick[j]])
 83 
 84         max_score = torch.max(merge_score[ids])
 85         if max_score < scoreThreds:
 86             continue
 87 
 88         xmax = max(merge_pose[:, 0])
 89         xmin = min(merge_pose[:, 0])
 90         ymax = max(merge_pose[:, 1])
 91         ymin = min(merge_pose[:, 1])
 92 
 93         if (1.5 ** 2 * (xmax - xmin) * (ymax - ymin) < areaThres):
 94             continue
 95 
 96         final_result.append({
 97             'keypoints': merge_pose - 0.3,
 98             'kp_score': merge_score,
 99             'proposal_score': torch.mean(merge_score) + bbox_scores_pick[j] + 1.25 * max(merge_score)
100         })
101 
102     return final_result
103 
104 
105 
106 def PCK_match(pick_pred, all_preds, ref_dist):
107     dist = torch.sqrt(torch.sum(torch.pow(pick_pred[np.newaxis, :] - all_preds, 2), dim=2 ))   # 當前點和其他所有點的距離 [n, 17]
108     ref_dist = min(ref_dist, 7)
109     num_match_keypoints = torch.sum(dist / ref_dist <= 1, dim=1)   # 得到滿足條件的點的數量   [n]
110     return num_match_keypoints    # 返回滿足條件的點的數量
111 
112 
113 
114 def get_parametric_distance(i, all_preds, keypoint_scores, ref_dist):
115     pick_preds = all_preds[i]   # 當前預測關節點的坐標
116     pred_scores = keypoint_scores[i]    # 當前預測關節點的分值
117     dist = torch.sqrt(torch.sum(torch.pow(pick_preds[np.newaxis, :] - all_preds, 2), dim=2))  # 當前人關節點和所有人關節點的距離 [n, 17]
118     mask = (dist <= 1)    # 當前人關節點和所有人關節點的mask,此處指如果兩套關節點距離太小(因是二維矩陣,不會出現某人部分關節點mask=1),則mask=1,一般來說,只是本人關節點mask=1 [n, 17]
119 
120     score_dists = torch.zeros(all_preds.shape[0], 17)  # Define a keypoints distance
121     keypoint_scores.squeeze_()
122     if keypoint_scores.dim() == 1:
123         keypoint_scores.unsqueeze_(0)  # 增加維度
124     if pred_scores.dim() == 1:
125         pred_scores.unsqueeze_(1)      # 增加維度
126     pred_scores = pred_scores.repeat(1, all_preds.shape[0]).transpose(0, 1)  # The predicted scores are repeated up to do broadcast。 [n, 1]
127 
128     # 由於broadcast,pred_scores!=keypoint_scores,但是pred_scores[mask] == keypoint_scores[mask]
129     score_dists[mask] = torch.tanh(pred_scores[mask] / delta1) * torch.tanh(keypoint_scores[mask] / delta1)   # delta1 = 1,當前點和近距離點的score的相似度,公式(8)
130 
131     point_dist = torch.exp((-1) * dist / delta2)    # delta2 = 2.65,當前點和近距離點的距離的相似度,公式(9)
132     final_dist = torch.sum(score_dists, dim=1) + mu * torch.sum(point_dist, dim=1)  # mu = 1.7,最終的距離  [n]
133 
134     return final_dist   # 返回最終的距離
135 
136 
137 # 如果人體檢測器效果很好,無冗余檢測,則此函數無效
138 def p_merge_fast(ref_pose, cluster_preds, cluster_scores, ref_dist):
139     '''
140     Score-weighted pose merging
141     INPUT:
142         ref_pose:       reference pose          -- [17, 2]       ref_pose  # 根據pick重新映射后的當前人各關節點的坐標
143         cluster_preds:  redundant poses         -- [n, 17, 2]    cluster_preds  # 篩選出來的當前人各關節點的坐標
144         cluster_scores: redundant poses score   -- [n, 17, 1]    cluster_scores  # 篩選出來的當前人各個關節點的score
145         ref_dist:       reference scale         -- Constant      ref_dist  # 根據pick重新映射后當前人NMS子框的閾值
146     OUTPUT:
147         final_pose:     merged pose             -- [17, 2]
148         final_score:    merged score            -- [17]
149     '''
150     # 無冗余姿態的情況下,ref_pose==cluster_preds==final_pose,dist=[[0....0]]  17個
151     dist = torch.sqrt(torch.sum(torch.pow(ref_pose[np.newaxis, :] - cluster_preds, 2), dim=2))
152 
153     kp_num = 17
154     ref_dist = min(ref_dist, 15)
155 
156     mask = (dist <= ref_dist)
157     final_pose = torch.zeros(kp_num, 2)
158     final_score = torch.zeros(kp_num)
159 
160     if cluster_preds.dim() == 2:
161         cluster_preds.unsqueeze_(0)    # [17,2] ==> [1, 17, 2]
162         cluster_scores.unsqueeze_(0)   # [17,1] ==> [1, 17, 1]
163     if mask.dim() == 1:
164         mask.unsqueeze_(0)             # [1,17] ==> [1, 17]  不變
165 
166     # Weighted Merge
167     masked_scores = cluster_scores.mul(mask.float().unsqueeze(-1))    # [1, 17, 1]   冗余score乘以mask,並進行歸一化
168     normed_scores = masked_scores / torch.sum(masked_scores, dim=0)    # [1, 17, 1]  的全1矩陣
169 
170     # 冗余關節點位置乘歸一化分數,得到冗余關節點位置。無冗余姿態的情況下,無冗余姿態的情況下,ref_pose==cluster_preds==final_pose
171     final_pose = torch.mul(cluster_preds, normed_scores.repeat(1, 1, 2)).sum(dim=0)
172     # 歸一化之前的冗余關節點分數  final_score==cluster_scores==masked_scores
173     final_score = torch.mul(masked_scores, normed_scores).sum(dim=0)
174 
175     return final_pose, final_score   # 返回冗余關節點位置和這些關節點對應的score
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM