根据COCO dataset 官网:COCO - Common Objects in Context, 关键点归一化因子的计算方法应该是:
下面的公式是根据网上大部分博客写的,是有问题的。于2021/12/11更正。
---------------------------------------------分割线,下面内容有些问题------------------------------------------------
人体姿态估计的评估指标为AP,其类似于目标检测领域的AP,只不过将iou替换为oks。oks(object keypoint similarity),是目前常用的人体骨骼关键点检测算法的评价指标,目的就是为了计算真值和预测人体关键点的相似度。
其中:表示关键点归一化因子,这个因子是通过对所有的样本集中的关键点由人工标注与真实值存在的标准差,越大表示此类型的关键点越难标注。
的计算方法:
下面是根据上述公式写的代码,背景:自己创建的关键点数据集(包含多个类别,不同类别下的关键点定义的数量不同)。两个path下分别为人工标注与真实值的annotation的json文件(labelme生成),num列表存储的是不同类别的关键点数量。标注标准差最后存储在sigma列表中。
import os
import numpy as np
import json
import codecs
import math
class MyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
else:
return super(MyEncoder, self).default(obj)
path = '../已核'
path_matched = '../ori'
num = [27, 5, 10, 6, 4, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1]
a = 0
all = []
all_avg = []
a = [0,1,2,3,5,6,7,9,11,12,13,14,15,17,19,22]
for r,t in enumerate(a):
path1 = path + '/' + str(t + 1)
path2 = path_matched + '/' + str(t + 1)
list_ori = os.listdir(path1)
list_matched = os.listdir(path2)
class_list = []
for item1 in list_ori:
# 如果该文件以json结尾
if(item1.split('.')[1] == 'json'):
path_ori = path1 + '/' + item1
data1 = codecs.open(path_ori, 'r', 'gbk')
data1 = json.load(data1)
anno1 = data1["shapes"]
w = data1["imageWidth"]
h = data1["imageHeight"]
if(item1 in list_matched):
path_matched_json = path2 + '/' + item1
data2 = codecs.open(path_matched_json, 'r', 'gbk')
data2 = json.load(data2)
anno2 = data2["shapes"]
# 将本json文件(对应一张图片)下的所有点保存在一个list中
l1 = [[]] * num[r]
for shape in anno1:
i = int(shape["label"])
if(i != 90):
l1[i] = shape["points"][0]
else:
w = abs(shape["points"][0][0] - shape["points"][1][0])
h = abs(shape["points"][0][1] - shape["points"][1][1])
l2 = [[]] * num[r]
for shape in anno2:
i = int(shape["label"])
if(i != 90):
l2[i] = shape["points"][0]
# 单张图片在本类下(一共23类)所有点的d/S的值
ds = [[]] * num[r]
for i,j in enumerate(l1):
j_matched = l2[i]
d = math.pow(j[0] - j_matched[0], 2) + math.pow(j[1] - j_matched[1], 2)
ds[i] = math.sqrt(d / (w * h))
class_list.append(ds)
all.append(class_list)
sum = [0] * int(num[r])
for l in class_list:
for i,j in enumerate(l):
sum[i] = sum[i] + j
avg = []
l = len(class_list)
avg = [i / l for i in sum]
all_avg.append(avg)
sigma = []
for i in range(len(all)):
# 每一类的统计的E(d/s)
temp_avg = all_avg[i]
# 每一类的所有人的数据,双层列表
temp_people = all[i]
# 每一类的人数
lens = len(temp_people)
temp_ds_e = []
for k in temp_people:
temp_ds_e_per_person = []
for m,n in enumerate(k):
# (d/s - E(d/s))^2
oo = math.pow(n - temp_avg[m], 2)
temp_ds_e_per_person.append(oo)
temp_ds_e.append(temp_ds_e_per_person)
sum_1 = [0] * len(temp_avg)
for l in temp_ds_e:
for o,p in enumerate(l):
sum_1[o] = sum_1[o] + p
avg_1 = []
avg_1 = [math.sqrt(v / lens) for v in sum_1]
for sigma_i in avg_1:
sigma.append(sigma_i)
print(len(sigma))
print(sigma)