Pose Estimation Evaluation.

人体姿态估计中常用的评估指标包括:

  1. PCKPercentage of Correct Keypoints
  2. OKSObject Keypoint Similarity
  3. APAverage Precision
  4. mAPmean Average Precision

1. Percentage of Correct Keypoints

PCK指标衡量正确估计出的关键点比例。这是比较老的人体姿态估计指标,在$2017$年比较广泛使用,现在基本不再使用。但是在工程项目中,使用该指标评价训练模型的好坏还是蛮方便的。

第$i$个关键点的PCK指标计算如下:

\[PCK_{i}^{k} = \frac{\sum_{p}^{} {\delta (\frac{d_{pi}}{d_{p}^{def}} ≤ T_k)}}{\sum_{p}^{} {1}}\]

其中:

算法的PCK指标是对所有关键点计算取平均:

\[PCK_{mean}^{k} = \frac{\sum_{p}^{} {\sum_{i}^{} {\delta (\frac{d_{pi}}{d_{p}^{def}}} ≤ T_k)}}{\sum_{p}^{} {\sum_{i}^{} {1}}}\]

PCK指标计算参考代码:

def compute_pck_pckh(dt_kpts,gt_kpts,refer_kpts):
    """
    pck指标计算
    :param dt_kpts:算法检测输出的估计结果,shape=[n,h,k]=[行人数,2,关键点个数]
    :param gt_kpts: groundtruth人工标记结果,shape=[n,h,k]
    :param refer_kpts: 尺度因子,用于预测点与groundtruth的欧式距离的scale。
               pck指标:躯干直径,左肩点-右臀点的欧式距离;
               pckh指标:头部长度,头部对角线的欧式距离;
    :return: 相关指标
    """
    
    dt=np.array(dt_kpts)
    gt=np.array(gt_kpts)
    assert(len(refer_kpts)==2)
    assert(dt.shape[0]==gt.shape[0])
    ranges=np.arange(0.0,0.1,0.01)
    kpts_num=gt.shape[2]
    ped_num=gt.shape[0]
	
    # compute dist
    scale=np.sqrt(np.sum(np.square(gt[:,:,refer_kpts[0]]-gt[:,:,refer_kpts[1]]),1))
    dist=np.sqrt(np.sum(np.square(dt-gt),1))/np.tile(scale,(gt.shape[2],1)).T
	
    # compute pck
    pck = np.zeros([ranges.shape[0], gt.shape[2]+1])
    for idh,trh in enumerate(list(ranges)):
        for kpt_idx in range(kpts_num):
            pck[idh,kpt_idx] = 100*np.mean(dist[:,kpt_idx] <= trh)
        # compute average pck
        pck[idh,-1] = 100*np.mean(dist <= trh)
    return pck

2. Object Keypoint Similarity

OKS是目前常用的人体骨骼关键点检测算法的评估指标,该指标受目标检测中的IoU指标启发,目的是计算关键点预测值和标注真值的相似度。

第$p$个人的OKS指标计算如下:

\[OKS_p = \frac{\sum_{i}^{} {exp\{-d_{pi}^{2}/2S_{p}^{2} \sigma_{i}^{2}\} \delta (v_{pi} > 0)}}{\sum_{i}^{} {\delta (v_{pi} > 0)}}\]

其中:

OKS指标计算参考代码:

sigmas = np.array([.26, .25, .25, .35, .35, .79, .79, .72, .72, .62,.62, 1.07, 1.07, .87, .87, .89, .89])/10.0
variances = (sigmas * 2)**2
def compute_kpts_oks(dt_kpts, gt_kpts, area):
    """
    this function only works for computing oks with keypoints,
    :param dt_kpts: 关键点检测结果 dt_kpts.shape=[3,k],dt_kpts[0]表示横坐标值,dt_kpts[1]表示纵坐标值,dt_kpts[2]表示可见性,
    :param gt_kpts: 关键点标记结果 gt_kpts.shape=[3,k],gt_kpts[0]表示横坐标值,gt_kpts[1]表示纵坐标值,gt_kpts[2]表示可见性,
    :param area: groundtruth中当前一组关键点所在人检测框的面积
    :return: 两组关键点的相似度oks
    """
	
    g = np.array(gt_kpts)
    xg = g[0::3]
    yg = g[1::3]
    vg = g[2::3]
    assert(np.count_nonzero(vg > 0) > 0)
    d = np.array(dt_kpts)
    xd = d[0::3]
    yd = d[1::3]
    dx = xd - xg
    dy = yd - yg
    e = (dx**2 + dy**2) /variances/ (area+np.spacing(1)) / 2 #加入np.spacing()防止面积为零
    e=e[vg > 0]
    return np.sum(np.exp(-e)) / e.shape[0]

3. Average Precision

对于单人姿态估计,首先计算OKS指标,然后人为给定一个阈值$T$,通过所有图像计算AP指标:

\[AP = \frac{\sum_{p}^{} {\delta (oks_p) > T}}{\sum_{p}^{} {1}}\]

对于多人姿态估计,如果采用的检测方法是自顶向下,先把所有的人找出来再检测关键点,那么其AP计算方法同上;

如果采用的检测方法是自底向上,先把所有的关键点找出来再组成人,假设一张图片中共有$M$个人,预测出$N$个人,由于不知道预测出的$N$个人与标记的$M$个人之间的对应关系,因此需要计算标记的每个人与预测的$N$个人的OKS指标,得到一个大小为${M}\times{N}$的矩阵,矩阵的每一行为标记的一个人与预测结果的$N$个人的OKS指标,然后找出每一行中OKS指标最大的值作为当前标记人的OKS指标。最后每一个标记人都有一个OKS指标,然后人为给定一个阈值$T$,通过所有图像计算AP指标:

\[AP = \frac{\sum_{m}^{} \sum_{p}^{} {\delta (oks_p) > T}}{\sum_{m}^{} \sum_{p}^{} {1}}\]

4. mean Average Precision

mAP是给AP指标中的人工阈值$T$设定不同的值,对这些阈值下得到的AP求平均得到的结果。

\[T \in [0.5:0.05:0.95]\]