关键点检测标注文件解析(姿态估计)——COCO数据集

发布于:2024-05-06 ⋅ 阅读:(21) ⋅ 点赞:(0)

本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!

🍊作者简介:,致力于用最通俗的语言描述问题

🍊专栏推荐:

🍊近期目标:写好专栏的每一篇文章

🍊支持小苏:点赞👍🏼、收藏⭐、留言📩

 

关键点检测标注文件解析(姿态估计)——COCO数据集

写在前面

Hello,大家好,我是小苏👦🏽👦🏽👦🏽

最近在学习关键点检测的知识,其中用到了COCO数据集中的关键点标注数据,自己对其不是特别熟悉,于是学习了一下,在此记录。🍋🍋🍋

我认为阅读一个代码或者看一个项目源码时,充分了解其数据集的结构是十分有必要的,如果你也对COCO关键点检测的标注信息不是很熟悉的话,这篇文章将会对你有帮助。🥂🥂🥂

话不多说,让我们一起来看看叭~~~🚖🚖🚖

关键点检测标注文件解析

我想来看这篇博客的对关键点检测的概念肯定是有所了解的,我就不介绍了,直接步入主题,不清楚的去网上找找资料。🌸🌸🌸

既然是COCO数据的关键点检测标注文件,那么第一步我们当然需要下载COCO数据集了,没下载的可以使用我的网盘连接下载:

百度云链接: 提取码: x3qk

下载解压之后,具有如下的目录结构:

image-20231119194246649

其中train2017val2017里面存储的是训练集和验证集的图片,annotations里面存储的是标注文件,我们进入标注文件中可以看到如下6个文件:

image-20231119194634850

其中,黄框中的两个json文件就是本节需要用到的关键点检测的标注文件(训练集和验证集)。


现在我们知道了本节的目标文件,任务就是对其进行分析。【注:训练集和验证集的格式是一样的,只是数据量存在差异,故后文我拿验证集的json文件进行分析】

那我们就打开这个文件来看看,如下:

是不是看麻了,莫慌,我来为大家解析一下这个文件。首先,整个文件由以下几个部分构成:【注意:这几个标签后面的数字6、8、3、3、1表示我选取的原文件的一部分数据,比如images有5000条数据,我只选择了3条】

image-20231119195716165

下面我分别来解释一下这几个字段:

  • info

    这个字段包括以下内容,主要就是一些描述信息,没什么好介绍的。🌱🌱🌱

    image-20231119200524695

  • licenses 这个字段包括以下内容,主要描述了8种不同的许可证,每种许可证都对数据或资源的使用施加了特定的限制,具体详情可点击对应url查看。

image-20231119200928136

  • image

    这个字段每个元素是一个特定图像的相关信息,其中包含了关于这张图像的一些相关数据,如图片名称,长度、宽度等。

    image-20231119201439919

    flicker是一个在线图片和视频的分享平台,提供用户存储、分享和组织他们的照片和视频的服务,flicker_url表示图像在Flickr上的URL链接。

  • annotations

    这个字段是最重要的了,提供了标注信息,如下:

    image-20231119202309531

    从这个标注信息中可以看到,这里也提供了分割(segmentation)和边界框(bbox)的标签,这里主要讨论关键点检测,故这两个就不过多介绍了 。

    • num_keypoints表示标注了多少个关键点信息;

    • area表示的是分割的面积,以像素为单位;

    • iscrowd表示是否是拥挤场景,0表示不是拥挤场景,1表示拥挤

      • keypoints表示目标实例的关键点坐标和可见性。这里给大家先说明一下,在COCO数据集中,人体关键点检测一个标注17个点,这里的keypoints共有17×3=51个数据,表示17个关键点的x,y坐标和可见性,如下图:

      怎么理解上文所述的可见性呢?其只会取{ 0 , 1 , 2 } 三个值。0表示该点在图像中无法标注,1表示虽然该点不可见但大概能猜测出位置(比如遮挡),2表示该点可见。如果第3个值为0,那么对应的x,y的值也都等于0。

    • image_id 图像的唯一标识

      image-20231119204132429

    • category_id 类别id,1在COCO数据集中表示person

    • id 目标实例分配的唯一标识符,用于在数据集中唯一标识这个目标实例。

  • categories

    这个字段描述了COCO数据集中用于标注人体关键点的类别信息,如下:

    image-20231119204613902

    • supercategory 类别的超级类别,即更大范畴中的类别。

    • id 类别的唯一标识符。在这个例子中,person的类别标识符是1。

    • name 类别的名称。在这里,类别名称为"person",表示这是用于标注人的类别。

    • keypoints 代表人体的一个关键点(一共17个),其对应关系如下:
      image-20231119205011788

    • skeleton

      表示各个关键点之间的连接关系,这里大家注意一下,上图的关键点索引是从0开始的,但是这里的连接关系是从从1开始的,所以要将上图的索引加1再进行连接,为了方便大家,给出下表:

      索引 关键点连接序号 关键点名称 中文名称
      0 1 nose 鼻子
      1 2 left_eye 左眼
      2 3 right_eye 右眼
      3 4 left_ear 左耳
      4 5 right_ear 右耳
      5 6 left_shoulder 左肩
      6 7 right_shoulder 右肩
      7 8 left_elbow 左手肘
      8 9 right_elbow 右手肘
      9 10 left_wrist 左手腕
      10 11 right_wrist 右手腕
      11 12 left_hip 左臀部
      12 13 right_hip 右臀部
      13 14 left_knee 左膝盖
      14 15 right_knee 右膝盖
      15 16 left_ankle 左脚踝
      16 17 right_ankle 右脚踝

      连接关系如下:

      image-20231203184622900

​ 为了让大家更直观的感受,根据连接关系和关键点的大致位置,我在drawio上绘制了人体关键点的大致图像,如下:

关键点.drawio

关键点检测标注文件读取及可视化

呼呼呼~~~终于把关键点检测的标注文件介绍完了,大家是否都理解了呢?如果还没理解的话,就在多看看或者评论区留言。🥗🥗🥗

下面我将来介绍一下关键点检测标注文件读取及可视化,这里我不打算使用COCO的API进去读取,而是只使用图像处理库和 matplotlib 进行绘制,这样应该更好理解一些。

首先,我们需要导入一些必要的库,如下:

import json
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, ConnectionPatch
from PIL import Image

接着,我们来设置标注图像的文件路径和图像文件夹路径,如下:

# COCO 标注文件路径
annotations_file_path = r'D://数据集//coco2017//annotations//person_keypoints_val2017.json'

# 图像文件夹路径
images_folder_path = r'D://数据集//coco2017//val2017//'

# 指定数据集中的图像 ID
image_id = 481386  # 替换为你想要的图像 ID

其中,图像文件夹路径就是我们下载COCO数据集时验证集图片文件路径。【注意这里我用的是验证集的标注信息,所以图像文件路径是验证集的,如果你使用的是训练集的标注信息,则需换成训练集图像路径】image_id可以在标注信息中找到,或者是图像名称的非0数字,比如下图文件名是000000481386,则其image_id则是481386。

image-20231119212224293

制定好这些路径和image_id后,对刚刚的标注文件进行读取:

# 读取 COCO 标注文件
with open(annotations_file_path, 'r') as f:
    coco_data = json.load(f)

我们可以来看看coco_data的信息,如下:

image-20231119212613157

你会发现其就是我们上一小节所介绍的几个部分。有了coco_data数据,我们就根据image_id来找到对应的图像信息和标注信息,如下:

# 找到对应图像的信息
image_info = next(item for item in coco_data['images'] if item['id'] == image_id)

# 找到对应图像的标注信息
annotations = [ann for ann in coco_data['annotations'] if ann['image_id'] == image_id]

关于这段代码不理解的可以看看我的,这里不在过多叙述。

我们也来看看image_infoannotations的结果:

image-20231119213147977

image-20231119213220324

有了这些信息之后,后面就很好办了,其实主要就是一些绘图的工作了,如下:

# 显示图像
image_path = images_folder_path + image_info['file_name']
image = Image.open(image_path)
plt.imshow(image)
plt.axis('off')

# 绘制关键点
for ann in annotations:
    keypoints = ann['keypoints']
    for i in range(0, len(keypoints), 3):
        x, y, v = keypoints[i], keypoints[i + 1], keypoints[i + 2]
        if v > 0:  # 仅绘制可见的关键点
            plt.scatter(x, y, color='r', s=10)  
            
plt.show()

我们来看一下,运行的结果叭:

image-20231119213516230

接着考虑利用标注信息中的关键点的连接规则,将这些关键点进行连接,如下:

# 绘制关键点之间的连接线段
skeleton = [[16, 14], [14, 12], [17, 15], [15, 13], [12, 13], [6, 12], [7, 13], [6, 7], [6, 8], [7, 9], [8, 10], [9, 11], [2, 3], [1, 2], [1, 3], [2, 4], [3, 5], [4, 6], [5, 7]]

for connection in skeleton:
    start_point = (annotations[0]['keypoints'][3 * (connection[0] - 1)], annotations[0]['keypoints'][3 * (connection[0] - 1) + 1])
    end_point = (annotations[0]['keypoints'][3 * (connection[1] - 1)], annotations[0]['keypoints'][3 * (connection[1] - 1) + 1])
    line = ConnectionPatch(start_point, end_point, "data", "data", color='r', linewidth=2)
    plt.gca().add_patch(line)

大家注意一下这段代码:start_point = (annotations[0]['keypoints'][3 * (connection[0] - 1)], annotations[0]['keypoints'][3 * (connection[0] - 1) + 1])(connection[0] - 1)是因为连接线段是从1开始计算的,而关键点索引是从0开始计算的,这点在前文也有介绍,annotations[0]['keypoints'][3 * (connection[0] - 1)]这部分计算的是起始点x的坐标,annotations[0]['keypoints'][3 * (connection[0] - 1) + 1]这部分计算的是起始点y的坐标。🍉🍉🍉

我们再来看看连接这些关键点之后的效果叭,如下:

image-20231119214124303


最后的最后,再贴一下这部分完整的代码:

import json
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, ConnectionPatch
from PIL import Image

# COCO 标注文件路径
annotations_file_path = r'D://数据集//coco2017//annotations//person_keypoints_val2017.json'

# 图像文件夹路径
images_folder_path = r'D://数据集//coco2017//val2017//'

# 指定数据集中的图像 ID
image_id = 481386  # 替换为你想要的图像 ID

# 读取 COCO 标注文件
with open(annotations_file_path, 'r') as f:
    coco_data = json.load(f)

# 找到对应图像的信息
image_info = next(item for item in coco_data['images'] if item['id'] == image_id)

# 找到对应图像的标注信息
annotations = [ann for ann in coco_data['annotations'] if ann['image_id'] == image_id]

# 显示图像
image_path = images_folder_path + image_info['file_name']
image = Image.open(image_path)
plt.imshow(image)
plt.axis('off')

# 绘制关键点
for ann in annotations:
    keypoints = ann['keypoints']
    for i in range(0, len(keypoints), 3):
        x, y, v = keypoints[i], keypoints[i + 1], keypoints[i + 2]
        if v > 0:  # 仅绘制可见的关键点
            plt.scatter(x, y, color='r', s=10) 

# 绘制关键点之间的连接线段
skeleton = [[16, 14], [14, 12], [17, 15], [15, 13], [12, 13], [6, 12], [7, 13], [6, 7], [6, 8], [7, 9], [8, 10], [9, 11], [2, 3], [1, 2], [1, 3], [2, 4], [3, 5], [4, 6], [5, 7]]

for connection in skeleton:
    start_point = (annotations[0]['keypoints'][3 * (connection[0] - 1)], annotations[0]['keypoints'][3 * (connection[0] - 1) + 1])
    end_point = (annotations[0]['keypoints'][3 * (connection[1] - 1)], annotations[0]['keypoints'][3 * (connection[1] - 1) + 1])
    line = ConnectionPatch(start_point, end_point, "data", "data", color='r', linewidth=2)
    plt.gca().add_patch(line)

# 显示带有关键点的图像
plt.show()

小结

这部分就到这里结束啦,希望大家能够有所收获喔🌴🌴🌴如果代码有看不懂的地方,强烈建议大家先调试看看结果,如果实在不会,评论区留下你的问题,我们共同探讨。🍻🍻🍻

   

如若文章对你有所帮助,那就🛴🛴🛴

         一键三连 (1).gif