🍊作者简介:秃头小苏,致力于用最通俗的语言描述问题
🍊专栏推荐:深度学习网络原理与实战
🍊近期目标:写好专栏的每一篇文章
🍊支持小苏:点赞👍🏼、收藏⭐、留言📩
关键点检测标注文件解析(姿态估计)——COCO数据集
写在前面
Hello,大家好,我是小苏👦🏽👦🏽👦🏽
最近在学习关键点检测的知识,其中用到了COCO数据集中的关键点标注数据,自己对其不是特别熟悉,于是学习了一下,在此记录。🍋🍋🍋
我认为阅读一个代码或者看一个项目源码时,充分了解其数据集的结构是十分有必要的,如果你也对COCO关键点检测的标注信息不是很熟悉的话,这篇文章将会对你有帮助。🥂🥂🥂
话不多说,让我们一起来看看叭~~~🚖🚖🚖
关键点检测标注文件解析
我想来看这篇博客的对关键点检测的概念肯定是有所了解的,我就不介绍了,直接步入主题,不清楚的去网上找找资料。🌸🌸🌸
既然是COCO数据的关键点检测标注文件,那么第一步我们当然需要下载COCO数据集了,没下载的可以使用我的网盘连接下载:
百度云链接: https://pan.baidu.com/s/1U3pPJ5nDluGdCtYi0njejg
提取码: x3qk
下载解压之后,具有如下的目录结构:
其中train2017
和val2017
里面存储的是训练集和验证集的图片,annotations
里面存储的是标注文件,我们进入标注文件中可以看到如下6个文件:
其中,黄框中的两个json文件就是本节需要用到的关键点检测的标注文件(训练集和验证集)。
现在我们知道了本节的目标文件,任务就是对其进行分析。【注:训练集和验证集的格式是一样的,只是数据量存在差异,故后文我拿验证集的json文件进行分析】
那我们就打开这个文件来看看,如下:
是不是看麻了,莫慌,我来为大家解析一下这个文件。首先,整个文件由以下几个部分构成:【注意:这几个标签后面的数字6、8、3、3、1表示我选取的原文件的一部分数据,比如images有5000条数据,我只选择了3条】
下面我分别来解释一下这几个字段:
-
info
这个字段包括以下内容,主要就是一些描述信息,没什么好介绍的。🌱🌱🌱
-
licenses
这个字段包括以下内容,主要描述了8种不同的许可证,每种许可证都对数据或资源的使用施加了特定的限制,具体详情可点击对应url查看。
-
image
这个字段每个元素是一个特定图像的相关信息,其中包含了关于这张图像的一些相关数据,如图片名称,长度、宽度等。
flicker是一个在线图片和视频的分享平台,提供用户存储、分享和组织他们的照片和视频的服务,flicker_url表示图像在Flickr上的URL链接。
-
annotations
这个字段是最重要的了,提供了标注信息,如下:
从这个标注信息中可以看到,这里也提供了分割(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。
- keypoints表示目标实例的关键点坐标和可见性。这里给大家先说明一下,在COCO数据集中,人体关键点检测一个标注17个点,这里的keypoints共有17×3=51个数据,表示17个关键点的x,y坐标和可见性,如下图:
-
image_id 图像的唯一标识
-
category_id 类别id,1在COCO数据集中表示person
-
id 目标实例分配的唯一标识符,用于在数据集中唯一标识这个目标实例。
-
-
categories
这个字段描述了COCO数据集中用于标注人体关键点的类别信息,如下:
-
supercategory 类别的超级类别,即更大范畴中的类别。
-
id 类别的唯一标识符。在这个例子中,person的类别标识符是1。
-
name 类别的名称。在这里,类别名称为"person",表示这是用于标注人的类别。
-
keypoints
代表人体的一个关键点(一共17个),其对应关系如下:
-
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 右脚踝 连接关系如下:
-
为了让大家更直观的感受,根据连接关系和关键点的大致位置,我在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_id
后,对刚刚的标注文件进行读取:
# 读取 COCO 标注文件
with open(annotations_file_path, 'r') as f:
coco_data = json.load(f)
我们可以来看看coco_data
的信息,如下:
你会发现其就是我们上一小节所介绍的几个部分。有了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_info
和annotations
的结果:
有了这些信息之后,后面就很好办了,其实主要就是一些绘图的工作了,如下:
# 显示图像
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()
我们来看一下,运行的结果叭:
接着考虑利用标注信息中的关键点的连接规则,将这些关键点进行连接,如下:
# 绘制关键点之间的连接线段
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的坐标。🍉🍉🍉
我们再来看看连接这些关键点之后的效果叭,如下:
最后的最后,再贴一下这部分完整的代码:
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()
小结
这部分就到这里结束啦,希望大家能够有所收获喔🌴🌴🌴如果代码有看不懂的地方,强烈建议大家先调试看看结果,如果实在不会,评论区留下你的问题,我们共同探讨。🍻🍻🍻
如若文章对你有所帮助,那就🛴🛴🛴