如何使用Python分析姿态估计数据集COCO?
# 遍历所有图像
for img_id, img_fname, w, h, meta in get_meta(coco):
images_data.append({
'image_id': int(img_id),
'path': img_fname,
'width': int(w),
'height': int(h)
})
# 遍历所有元数据
for m in meta:
persons_data.append({
'image_id': m['image_id'],
'is_crowd': m['iscrowd'],
'bbox': m['bbox'],
'area': m['area'],
'num_keypoints': m['num_keypoints'],
'keypoints': m['keypoints'],
})
# 创建带有图像路径的数据帧
images_df = pd.DataFrame(images_data)
images_df.set_index('image_id', inplace=True)
# 创建与人相关的数据帧
persons_df = pd.DataFrame(persons_data)
persons_df.set_index('image_id', inplace=True)
return images_df, persons_df
我们使用get_meta函数构造两个数据帧—一个用于图像路径,另一个用于人的元数据。在一个图像中可能有多个人,因此是一对多的关系。在下一步中,我们合并两个表(left join操作)并将训练集和验证集组合,另外,我们添加了一个新列source,值为0表示训练集,值为1表示验证集。这样的信息是必要的,因为我们需要知道应该在哪个文件夹中搜索图像。如你所知,这些图像位于两个文件夹中:train2017/和val2017/images_df, persons_df = convert_to_df(train_coco)
train_coco_df = pd.merge(images_df, persons_df, right_index=True, left_index=True)
train_coco_df['source'] = 0
images_df, persons_df = convert_to_df(val_coco)
val_coco_df = pd.merge(images_df, persons_df, right_index=True, left_index=True)
val_coco_df['source'] = 1
coco_df = pd.concat([train_coco_df, val_coco_df], ignore_index=True)
最后,我们有一个表示整个COCO数据集的数据帧。图像中有多少人现在我们可以执行第一个分析。COCO数据集包含多个人的图像,我们想知道有多少图像只包含一个人。代码如下:# 计数
annotated_persons_df = coco_df[coco_df['is_crowd'] == 0]
crowd_df = coco_df[coco_df['is_crowd'] == 1]
print("Number of people in total: " + str(len(annotated_persons_df)))
print("Number of crowd annotations: " + str(len(crowd_df)))
persons_in_img_df = pd.DataFrame({
'cnt': annotated_persons_df['path'].value_counts()
})
persons_in_img_df.reset_index(level=0, inplace=True)
persons_in_img_df.rename(columns = {'index':'path'}, inplace = True)
# 按cnt分组,这样我们就可以在一张图片中得到带有注释人数的数据帧
persons_in_img_df = persons_in_img_df.groupby(['cnt']).count()
# 提取数组
x_occurences = persons_in_img_df.index.values
y_images = persons_in_img_df['path'].values
# 绘图
plt.bar(x_occurences, y_images)
plt.title('People on a single image ')
plt.xticks(x_occurences, x_occurences)
plt.xlabel('Number of people in a single image')
plt.ylabel('Number of images')
plt.show()
结果图表:
如你所见,大多数COCO图片都包含一个人。但也有相当多的13个人的照片,让我们举几个例子:
好吧,甚至有一张图片有19个注解(非人群):
这个图像的顶部区域不应该标记为一个人群吗?是的,应该,但是,我们有多个没有关键点的边界框!这样的注释应该像对待人群一样对待,这意味着它们应该被屏蔽。在这张图片中,只有中间的3个方框有一些关键点。让我们来优化查询,以获取包含有/没有关键点的人图像的统计信息,以及有/没有关键点的人的总数:annotated_persons_nokp_df = coco_df[(coco_df['is_crowd'] == 0) & (coco_df['num_keypoints'] == 0)]
annotated_persons_kp_df = coco_df[(coco_df['is_crowd'] == 0) & (coco_df['num_keypoints'] > 0)]
print("Number of people (with keypoints) in total: " +
str(len(annotated_persons_kp_df)))
print("Number of people without any keypoints in total: " +
str(len(annotated_persons_nokp_df)))
persons_in_img_kp_df = pd.DataFrame({
'cnt': annotated_persons_kp_df[['path','source']].value_counts()
})
persons_in_img_kp_df.reset_index(level=[0,1], inplace=True)
persons_in_img_cnt_df = persons_in_img_kp_df.groupby(['cnt']).count()
x_occurences_kp = persons_in_img_cnt_df.index.values
y_images_kp = persons_in_img_cnt_df['path'].values
f = plt.figure(figsize=(14, 8))
width = 0.4
plt.bar(x_occurences_kp, y_images_kp, width=width, label='with keypoints')
plt.bar(x_occurences + width, y_images, width=width, label='no keypoints')
plt.title('People on a single image ')
plt.xticks(x_occurences + width/2, x_occurences)
plt.xlabel('Number of people in a single image')
plt.ylabel('Number of images')
plt.legend(loc = 'best')
plt.show()
现在我们可以看到区别是明显的。
虽然COCO官方页面上描述有25万人拥有关键点,而我们只有156165个这样的例子。他们可能应该删除了“带关键点”这几个字。添加额外列一旦我们将COCO转换成pandas数据帧,我们就可以很容易地添加额外的列,从现有的列中计算出来。我认为最好将所有的关键点坐标提取到单独的列中,此外,我们可以添加一个具有比例因子的列。特别是,关于一个人的边界框的规模信息是非常有用的,例如,我们可能希望丢弃所有太小规模的人,或者执行放大操作。为了实现这个目标,我们使用Python库sklearn中的transformer对象。一般来说,sklearn transformers是用于清理、减少、扩展和生成数据科学模型中的特征表示的强大工具。我们只会用一小部分的api。代码如下:from sklearn.base import BaseEstimator, TransformerMixin
class AttributesAdder(BaseEstimator, TransformerMixin):
def __init__(self, num_keypoints, w_ix, h_ix, bbox_ix, kp_ix):
"""
:param num_keypoints: 关键点的数量
:param w_ix: 包含图像宽度的列索引
:param h_ix: 包含图像高度的列索引
:param bbox_ix: 包含边框数据的列索引
:param kp_ix: 包含关键点数据的列索引
"""
self.num_keypoints = num_keypoints
self.w_ix = w_ix
self.h_ix = h_ix
self.bbox_ix = bbox_ix
self.kp_ix = kp_ix
def fit(self, X, y=None):
return self
def transform(self, X):
# 检索特定列
w = X[:, self.w_ix]
h = X[:, self.h_ix]
bbox = np.array(X[:, self.bbox_ix].tolist()) # to matrix
keypoints = np.array(X[:, self.kp_ix].tolist()) # to matrix
最新活动更多
-
11月28日立即报名>>> 2024工程师系列—工业电子技术在线会议
-
12月19日立即报名>> 【线下会议】OFweek 2024(第九届)物联网产业大会
-
即日-12.26火热报名中>> OFweek2024中国智造CIO在线峰会
-
即日-2025.8.1立即下载>> 《2024智能制造产业高端化、智能化、绿色化发展蓝皮书》
-
精彩回顾立即查看>> 2024 智能家居出海论坛
-
精彩回顾立即查看>> 【在线会议】多物理场仿真助跑新能源汽车
推荐专题
发表评论
请输入评论内容...
请输入评论/评论长度6~500个字
暂无评论
暂无评论