2D人体姿态关键点数据通常包含人体多个关节的坐标位置、对应置信度等信息,JSON格式因结构清晰、易扩展的特点,成为这类数据存储的主流选择。不同数据集的JSON结构存在差异,处理时需要先明确数据结构再开展解析工作。

常见2D人体姿态关键点JSON结构
主流数据集的JSON结构通常分为两类,一类是单张图片对应一个JSON文件,另一类是多个图片的关键点信息存储在一个JSON文件中。单文件结构示例如下:
{
"image_path": "test_001.jpg",
"image_width": 1920,
"image_height": 1080,
"keypoints": [
{"name": "nose", "x": 960, "y": 300, "confidence": 0.98},
{"name": "left_eye", "x": 920, "y": 280, "confidence": 0.95},
{"name": "right_eye", "x": 1000, "y": 280, "confidence": 0.96}
]
}
多文件合并存储的结构通常会在外层增加图片列表字段,每个元素对应单张图片的所有关键点信息,解析时需要通过循环遍历外层列表获取单张图片的数据。
JSON格式解析方法
Python的json模块是解析JSON数据的常用工具,无需额外安装依赖,解析流程分为读取文件、加载数据、提取目标字段三个步骤。
基础解析代码示例
以下代码实现了单JSON文件的解析,提取所有关键点的坐标和置信度:
import json
def parse_single_json(json_path):
# 读取JSON文件
with open(json_path, 'r', encoding='utf-8') as f:
data = json.load(f)
# 提取基础信息
image_path = data.get('image_path')
img_width = data.get('image_width')
img_height = data.get('image_height')
# 提取关键点信息
keypoints_list = []
for kp in data.get('keypoints', []):
kp_info = {
'name': kp.get('name'),
'x': kp.get('x'),
'y': kp.get('y'),
'confidence': kp.get('confidence')
}
keypoints_list.append(kp_info)
return {
'image_path': image_path,
'img_size': (img_width, img_height),
'keypoints': keypoints_list
}
# 调用示例
result = parse_single_json('pose_data.json')
print(f"图片路径: {result['image_path']}")
print(f"关键点数量: {len(result['keypoints'])}")
批量解析多文件JSON
如果多个图片的JSON数据存储在一个文件中,只需要增加外层循环即可:
import json
def parse_batch_json(json_path):
with open(json_path, 'r', encoding='utf-8') as f:
batch_data = json.load(f)
all_results = []
# 假设外层是图片数据列表
for item in batch_data:
single_result = {
'image_path': item.get('image_path'),
'img_size': (item.get('image_width'), item.get('image_height')),
'keypoints': item.get('keypoints', [])
}
all_results.append(single_result)
return all_results
模型适配策略
解析后的原始数据通常无法直接输入模型,需要根据模型要求做格式转换,常见的适配策略包含以下几个方向。
坐标归一化处理
模型训练时通常需要将坐标归一化到0-1区间或者-1到1区间,避免不同图片尺寸带来的数值差异。归一化公式为:
x_norm = x / image_width,y_norm = y / image_height
实现代码如下:
def normalize_keypoints(keypoints, img_width, img_height):
normalized = []
for kp in keypoints:
norm_x = kp['x'] / img_width
norm_y = kp['y'] / img_height
normalized.append({
'name': kp['name'],
'x': norm_x,
'y': norm_y,
'confidence': kp['confidence']
})
return normalized
数据格式转换
多数姿态估计模型要求输入的关键点数据为固定维度的数组,比如17个关键点就需要生成形状为(17, 3)的数组,包含x、y坐标和置信度。转换代码如下:
import numpy as np
def convert_to_model_input(keypoints, target_num=17):
# 初始化全零数组
kp_array = np.zeros((target_num, 3), dtype=np.float32)
# 建立关键点名称到索引的映射
kp_name_map = {
'nose': 0, 'left_eye': 1, 'right_eye': 2,
'left_ear': 3, 'right_ear': 4, 'left_shoulder': 5,
'right_shoulder': 6, 'left_elbow': 7, 'right_elbow': 8,
'left_wrist': 9, 'right_wrist': 10, 'left_hip': 11,
'right_hip': 12, 'left_knee': 13, 'right_knee': 14,
'left_ankle': 15, 'right_ankle': 16
}
for kp in keypoints:
name = kp['name']
if name in kp_name_map:
idx = kp_name_map[name]
kp_array[idx] = [kp['x'], kp['y'], kp['confidence']]
return kp_array
置信度过滤
低置信度的关键点可能是检测错误的结果,会影响模型训练效果,通常可以设置阈值过滤掉置信度低于0.5的关键点:
def filter_low_confidence(keypoints, threshold=0.5):
filtered = []
for kp in keypoints:
if kp['confidence'] >= threshold:
filtered.append(kp)
return filtered
完整处理流程示例
将解析、过滤、归一化、格式转换整合为完整的处理流程:
import json
import numpy as np
def full_process_pipeline(json_path, target_kp_num=17, conf_threshold=0.5):
# 1. 解析JSON
with open(json_path, 'r', encoding='utf-8') as f:
data = json.load(f)
img_width = data.get('image_width')
img_height = data.get('image_height')
raw_keypoints = data.get('keypoints', [])
# 2. 置信度过滤
filtered_kp = filter_low_confidence(raw_keypoints, conf_threshold)
# 3. 坐标归一化
norm_kp = normalize_keypoints(filtered_kp, img_width, img_height)
# 4. 转换为模型输入格式
model_input = convert_to_model_input(norm_kp, target_kp_num)
return model_input
# 调用流程
input_data = full_process_pipeline('pose_data.json')
print(f"模型输入形状: {input_data.shape}")
注意事项
- 解析前先检查JSON文件的编码格式,避免中文路径或字段出现乱码
- 不同数据集的关键点命名和数量可能不同,需要提前整理名称映射表
- 如果原始数据包含可见性字段,需要额外处理不可见关键点的标记逻辑
- 批量处理时可以加入异常处理,避免单个文件解析失败导致整个流程中断