订阅
纠错
加入自媒体

如何使用Python分析姿态估计数据集COCO?

2021-01-16 09:50
磐创AI
关注

       # 计算边框的比例因子
       scale_x = bbox[:,2] / w
       scale_y = bbox[:,3] / h
       aspect_ratio = w / h
       
       # 计算规模类别
       
       scale_cat = pd.cut(scale_y,
           bins=[0., 0.4, 0.6, 0.8, np.inf],
           labels=['S', 'M', 'L', 'XL'])
       
       return np.c_[X, scale_x, scale_y, scale_cat, aspect_ratio, keypoints]
     
     
# 用于添加新列的transformer对象
attr_adder = AttributesAdder(num_keypoints=17, ...)
coco_extra_attribs = attr_adder.transform(coco_df.values)
# 创建列发新列表
keypoints_cols = [['x'+str(idx), 'y'+str(idx), 'v'+str(idx)]
                       for idx, k in enumerate(range(num_keypoints))]
keypoints_cols = np.concatenate(keypoints_cols).tolist()
# 创建新的更丰富的数据z帧
coco_extra_attribs_df = pd.DataFrame(
   coco_extra_attribs,
   columns=list(coco_df.columns) +
       ["scale_x", "scale_y", "scale_cat", "aspect_ratio"] +
       keypoints_cols,
   index=coco_df.index)
38行代码,我们为每一行指定规模类别(S、M、L或XL)。计算方法如下:如果scale_y在[0–0.4)范围内,则类别为S如果scale_y在[0.4–0.6)范围内,则类别为M如果scale_y在[0.6–0.8)范围内,则类别为L如果scale_y在[0.8–1.0)范围内,则类别为XL在第42行中,我们将原始列与新列进行合并。第28行我们将关键点扩展到单独的列中。COCO数据集中的关键点数据由一个一维列表表示:[x0,y0,v0,x1,y1,…],我们可以把这个列转换成一个矩阵:[num of rows]x[num of keypoints*3],然后,我们可以不需要任何额外的努力就可以返回它(第42行)。最后,我们创建一个新的数据帧(第58-63行)鼻子在哪里?我们通过检查图像中头部位置的分布来找到鼻子的坐标,然后在标准化的二维图表中画一个点。

呈现此图表的代码如下:# 对水平图像进行关键点坐标标准化
horiz_imgs_df = coco_extra_attribs_df[coco_extra_attribs_df['aspect_ratio'] >= 1.]
# 获取平均宽度和高度-用于缩放关键点坐标
avg_w = int(horiz_imgs_df['width'].mean())
avg_h = int(horiz_imgs_df['height'].mean())
class NoseAttributesAdder(BaseEstimator, TransformerMixin):
   def __init__(self, avg_w, avg_h, w_ix, h_ix, x1_ix, y1_ix, v1_ix):
       self.avg_w = avg_w
       self.avg_h = avg_h
       self.w_ix = w_ix
       self.h_ix = h_ix
       self.x1_ix = x1_ix
       self.y1_ix = y1_ix
       self.v1_ix = v1_ix
       def fit(self, X, y=None):
       return self
     def transform(self, X):
       w = X[:, self.w_ix]
       h = X[:, self.h_ix]
       x1 = X[:, self.x1_ix]
       y1 = X[:, self.y1_ix]
       # 标准化鼻子坐标,提供平均宽度和高度
       scale_x = self.avg_w / w
       scale_y = self.avg_h / h
       nose_x = x1 * scale_x
       nose_y = y1 * scale_y
       
       return np.c_[X, nose_x, nose_y]
     # 用于标准化鼻子坐标列的transformer对象
w_ix = horiz_imgs_df.columns.get_loc('width')
h_ix = horiz_imgs_df.columns.get_loc('height')
x1_ix = horiz_imgs_df.columns.get_loc('x0')  # 鼻子的x坐标在'x0'列中
y1_ix = horiz_imgs_df.columns.get_loc('y0')  # 鼻子的y坐标在'y0'列中
v1_ix = horiz_imgs_df.columns.get_loc('v0')  # 鼻头的可见性
attr_adder = NoseAttributesAdder(avg_w, avg_h, w_ix, h_ix, x1_ix, y1_ix, v1_ix)
coco_noses = attr_adder.transform(horiz_imgs_df.values)
# 使用标准化的数据创建新数据帧
coco_noses_df = pd.DataFrame(
   coco_noses,
   columns=list(horiz_imgs_df.columns) + ["normalized_nose_x", "normalized_nose_y"],
   index=horiz_imgs_df.index)
# 过滤-只有可见的鼻子
coco_noses_df = coco_noses_df[coco_noses_df["v0"] == 2]
coco_noses_df.plot(kind="scatter", x="normalized_nose_x",
                  y="normalized_nose_y", alpha=0.3).invert_yaxis()
与前面一样,我们使用一个转换器来添加新列。COCO数据集包含不同宽度和高度的图像,我们必须标准化每个图像中鼻子的x,y坐标,这样我们就能在输出图表中画出代表鼻子的点。我们首先确定所有图像的平均宽度和高度(第7-8行)这里我们可以使用任何值,因为它只用于确定比例因子。在第40-44行,我们从dataframe中找到所需列的索引。随后,我们执行转换(第46-47行)并创建一个新的数据帧,其中包含新的列normalized_nose_x和normalized_nose_y(第51-55行)最后一行绘制二维图表。现在我们可以检查一些图像,例如,我们想检查一些头部位置非常接近图像底边的图像,为了实现这一点,我们通过列normalized_nose_y来过滤数据帧low_noses_df = coco_noses_df[coco_noses_df['normalized_nose_y'] > 430 ]
low_noses_df
以下是满足此条件的示例图像:

关键点数量具有特定数量关键点的边界框的数量是附加的有用信息。

为什么要边界框?边界框有一个特殊的标志iscrowd,用来确定内容是应该作为一个群组(没有关键点)还是一个人(应该有关键点)。一般来说,iscrowd是为包含许多人的小实例(例如网球比赛中的观众)的边界框设置的。y_images = coco_extra_attribs_df['num_keypoints'].value_counts()
x_keypoints = y_images.index.values
# 绘图
plt.figsize=(10,5)
plt.bar(x_keypoints, y_images)
plt.title('Histogram of keypoints')
plt.xticks(x_keypoints)
plt.xlabel('Number of keypoints')
plt.ylabel('Number of bboxes')
plt.show()
# 带有若干关键点(行)的bboxes(列)百分比
kp_df = pd.DataFrame({
   "Num keypoints %": coco_extra_attribs_df[
                          "num_keypoints"].value_counts() / len(coco_extra_attribs_df)
}).sort_index()
如你所见,在表中显示相同的信息非常容易:

规模这是迄今为止最有价值的指标。训练姿态估计深度神经网络模型对样本中人的规模变化非常敏感,提供一个平衡的数据集是非常关键的,否则,模型可能会偏向于一个更具优势的规模。你还记得一个额外的属性scale_cat吗?现在我们要好好利用它。代码:persons_df = coco_extra_attribs_df[coco_extra_attribs_df['num_keypoints'] > 0]

persons_df['scale_cat'].hist()

可以呈现以下图表:

我们清楚地看到,COCO数据集包含了很多小人物——不到图像总高度的40%。我们把它放到表格中:scales_props_df = pd.DataFrame({
   "Scales": persons_df["scale_cat"].value_counts() / len(persons_df)
})
scales_props_df

COCO数据集的分层抽样首先,分层抽样定义为当我们将整个数据集划分为训练集/验证集等时,我们希望确保每个子集包含相同比例的特定数据组。假设我们有1000人,男性占57%,女性占43%。我们不能只为训练集和验证集选取随机数据,因为在这些数据子集中,一个组可能会被低估。,我们必须从57%的男性和43%的女性中按比例选择。换句话说,分层抽样在训练集和验证集中保持了57%的男性/43%的女性的比率。同样,我们可以检查COCO训练集和验证集中是否保持了不同规模的比率。persons_df = coco_extra_attribs_df[coco_extra_attribs_df['num_keypoints'] > 0]
train_df = persons_df[persons_df['source'] == 0]
val_df = persons_df[persons_df['source'] == 1]
scales_props_df = pd.DataFrame({
   "Scales in train set %": train_df["scale_cat"].value_counts() / len(train_df),
   "Scales in val set %": val_df["scale_cat"].value_counts() / len(val_df)
})
scales_props_df["Diff 100%"] = 100 *
   np.absolute(scales_props_df["Scales in train set %"] -
               scales_props_df["Scales in val set %"])
在第2-3行,我们将数据帧拆分为训练集和验证集的单独数据帧,这与我们分别从person_keypoints_train2017.json和person_keypoints_val2017.json加载数据帧相同。接下来,我们用训练集和验证集中每个规模组的基数创建一个新的数据帧,此外,我们添加了一个列,其中包含两个数据集之间差异的百分比。结果如下:

如我们所见,COCO数据集的分层非常好,训练集和验证集中的规模组之间只有很小的差异(1-2%)。现在,让我们检查不同的组-边界框中关键点的数量。train_df = coco_extra_attribs_df[coco_extra_attribs_df['source'] == 0]
val_df = coco_extra_attribs_df[coco_extra_attribs_df['source'] == 1]
kp_props_df = pd.DataFrame({
   "Num keypoints in train set %": train_df["num_keypoints"].value_counts() /
   len(train_df),
   "Num keypoints in val set %": val_df["num_keypoints"].value_counts() /
   len(val_df)
}).sort_index()
kp_props_df["Diff 100%"] = 100 *
   np.absolute(kp_props_df["Num keypoints in train set %"] -
               kp_props_df["Num keypoints in val set %"])

类似地,我们看到关键点的数量在COCO训练和验证集中是相等的,这很好!现在,你可以将所有数据集(MPII、COCO)合并到一个包中,然后自己进行拆分,有一个很好的sklearn类:StratifiedShuffleSplit可用做这个事情。总结在本文中,分析了COCO数据集的结构,了解其中的内容可以帮助你更好地决定增加或丢弃一些不相关的样本。分析可以在Jupyter notebook上进行。从COCO数据集中展示了一些或多或少有用的指标,比如图像中人的分布、人的边界框的规模、某些特定身体部位的位置。最后,描述了验证集分层的过程。github仓库链接:https://github.com/michalfaber/dataset_toolkit


☆ END ☆如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 mthler」,每日朋友圈更新一篇高质量博文。↓扫描二维码添加小编↓


<上一页  1  2  3  
声明: 本文由入驻维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。

发表评论

0条评论,0人参与

请输入评论内容...

请输入评论/评论长度6~500个字

您提交的评论过于频繁,请输入验证码继续

暂无评论

暂无评论

    人工智能 猎头职位 更多
    扫码关注公众号
    OFweek人工智能网
    获取更多精彩内容
    文章纠错
    x
    *文字标题:
    *纠错内容:
    联系邮箱:
    *验 证 码:

    粤公网安备 44030502002758号