COCO 2017 与 MPII 数据集实战:3步完成关键点标注格式转换与可视化
COCO 2017与MPII数据集实战:3步完成关键点标注格式转换与可视化
在计算机视觉领域,人体姿态估计是一个基础且重要的研究方向。无论是动作识别、行为分析还是人机交互,精准的姿态估计都是前置任务。而要实现这一目标,高质量的数据集和高效的数据处理流程不可或缺。本文将聚焦两个业界标杆数据集——COCO 2017和MPII,通过实战演示如何快速完成标注格式转换与可视化。
1. 环境准备与数据加载
开始之前,我们需要配置必要的Python环境。推荐使用conda创建虚拟环境以避免依赖冲突:
conda create -n pose_est python=3.8 conda activate pose_est pip install numpy matplotlib opencv-python scipy h5py pycocotools1.1 数据集下载与结构
COCO 2017和MPII数据集可以通过官方渠道获取:
- COCO 2017:包含118,287张训练图像(train2017)、5,000张验证图像(val2017)和40,670张测试图像(test2017)
- MPII:约25,000张图像,标注以MATLAB格式(.mat)存储
下载后建议按以下结构组织文件:
datasets/ ├── coco/ │ ├── annotations/ # 存放person_keypoints_train2017.json等文件 │ └── images/ # 存放train2017, val2017等图像文件夹 └── mpii/ ├── annotations/ # 存放mpii_human_pose_v1_u12_1.mat └── images/ # 存放原始图像1.2 关键点定义对比
两种数据集的关键点定义有所不同,这是后续转换需要特别注意的地方:
| 身体部位 | COCO序号 | MPII序号 | COCO名称 | MPII名称 |
|---|---|---|---|---|
| 鼻子 | 0 | 9 | nose | head_top |
| 左眼 | 1 | - | left_eye | - |
| 右眼 | 2 | - | right_eye | - |
| 左肩 | 5 | 12 | left_shoulder | r_shoulder |
| 右髋 | 12 | 2 | right_hip | r_hip |
注意:MPII的左右定义与COCO相反,这是转换过程中最容易出错的地方。建议在代码中显式处理这种差异。
2. 标注格式转换实战
2.1 COCO JSON格式解析
COCO使用标准的JSON格式存储标注,其关键点数据结构如下:
{ "images": [{ "id": int, "width": int, "height": int, "file_name": str }], "annotations": [{ "id": int, "image_id": int, "category_id": int, "keypoints": [x1,y1,v1, x2,y2,v2,...], # v表示可见性(0=不可见,1=遮挡,2=可见) "num_keypoints": int }] }使用pycocotools可以方便地加载COCO标注:
from pycocotools.coco import COCO coco = COCO('datasets/coco/annotations/person_keypoints_train2017.json') img_ids = coco.getImgIds(catIds=[1]) # 1对应person类别 ann_ids = coco.getAnnIds(imgIds=img_ids[0], catIds=[1]) annotations = coco.loadAnns(ann_ids)2.2 MPII MAT格式解析
MPII使用MATLAB的.mat文件存储标注,其结构更为复杂:
import h5py import numpy as np mpii = h5py.File('datasets/mpii/annotations/mpii_human_pose_v1_u12_1.mat', 'r') # 获取图像信息 images = np.array(mpii['RELEASE']['annolist'][0]['image']['name'][0]) # 获取标注信息 annolist = np.array(mpii['RELEASE']['annolist'][0]['annorect'][0])2.3 统一格式转换
我们需要将两种格式转换为统一的中间表示。以下是一个通用的关键点数据结构设计:
class PoseAnnotation: def __init__(self): self.image_path = '' # 图像路径 self.image_size = (0, 0) # (width, height) self.keypoints = [] # 每个元素是(x, y, visibility) self.skeleton = [] # 骨架连接关系 def to_coco_format(self): """转换为COCO格式的标注""" pass def to_mpii_format(self): """转换为MPII格式的标注""" pass具体转换代码示例(COCO到统一格式):
def coco_to_unified(coco_ann, img_info): pose = PoseAnnotation() pose.image_path = f"datasets/coco/images/train2017/{img_info['file_name']}" pose.image_size = (img_info['width'], img_info['height']) # 处理关键点 (COCO有17个点) kps = np.array(coco_ann['keypoints']).reshape(-1, 3) for i in range(17): x, y, v = kps[i] pose.keypoints.append((x, y, v)) # 定义骨架连接 pose.skeleton = [ [15,13], [13,11], [16,14], [14,12], [11,12], [5,11], [6,12], [5,6], [5,7], [6,8], [7,9], [8,10], [0,1], [0,2], [1,3], [2,4] ] return pose3. 可视化实现与技巧
3.1 基础可视化
使用OpenCV可以快速实现关键点可视化:
import cv2 import random def visualize_pose(image_path, keypoints, skeleton, save_path=None): img = cv2.imread(image_path) colors = [(random.randint(0,255), random.randint(0,255), random.randint(0,255)) for _ in range(len(keypoints))] # 绘制关键点 for i, (x, y, v) in enumerate(keypoints): if v > 0: # 只绘制可见点 cv2.circle(img, (int(x), int(y)), 4, colors[i], -1) # 绘制骨架 for i, j in skeleton: if i < len(keypoints) and j < len(keypoints): x1, y1, v1 = keypoints[i] x2, y2, v2 = keypoints[j] if v1 > 0 and v2 > 0: cv2.line(img, (int(x1), int(y1)), (int(x2), int(y2)), (0,255,0), 2) if save_path: cv2.imwrite(save_path, img) return img3.2 高级可视化技巧
对于更专业的可视化需求,可以考虑以下增强功能:
- 不同身体部位着色:将上肢、下肢、躯干等用不同颜色区分
- 关键点置信度可视化:用点的大小或透明度表示置信度
- 多姿态对比:在同一图像中显示多个姿态估计结果
- 动态可视化:使用matplotlib动画功能展示连续帧的姿态变化
def enhanced_visualization(image_path, poses, limb_colors=None): """增强版可视化,支持多姿态和自定义颜色""" img = cv2.imread(image_path) if limb_colors is None: limb_colors = { 'arm': (255,0,0), # 红色表示手臂 'leg': (0,0,255), # 蓝色表示腿部 'torso': (0,255,0), # 绿色表示躯干 'head': (255,255,0) # 青色表示头部 } for pose in poses: # 绘制不同身体部位 draw_limb(img, pose, 'left_arm', limb_colors['arm']) draw_limb(img, pose, 'right_arm', limb_colors['arm']) # 其他部位绘制... return img3.3 批量处理与结果保存
对于大规模数据集,我们需要批量处理并保存结果:
import os from tqdm import tqdm def batch_visualize(dataset_dir, output_dir, dataset_type='coco'): os.makedirs(output_dir, exist_ok=True) if dataset_type == 'coco': annotations = load_coco_annotations(os.path.join(dataset_dir, 'annotations')) else: annotations = load_mpii_annotations(os.path.join(dataset_dir, 'annotations')) for ann in tqdm(annotations[:1000]): # 限制处理1000个样本 pose = convert_to_unified(ann, dataset_type) img = visualize_pose(pose.image_path, pose.keypoints, pose.skeleton) output_path = os.path.join(output_dir, os.path.basename(pose.image_path)) cv2.imwrite(output_path, img)4. 常见问题与性能优化
4.1 典型问题解决方案
在实际处理中,我们可能会遇到以下问题:
坐标越界:关键点坐标超出图像范围
# 解决方案:坐标裁剪 x = max(0, min(x, img_width-1)) y = max(0, min(y, img_height-1))关键点顺序不一致:不同数据集的关键点索引不同
# 建立映射关系 COCO_TO_MPII = { 0: 9, # nose -> head_top 5: 12, # left_shoulder -> r_shoulder # 其他映射... }可见性标注差异:COCO使用0,1,2表示可见性,而MPII可能使用不同标准
# 统一转换为0(不可见)/1(可见) visibility = 1 if original_v > 0 else 0
4.2 性能优化技巧
当处理大规模数据集时,这些优化策略能显著提升效率:
并行处理:使用multiprocessing或joblib并行处理图像
from joblib import Parallel, delayed def process_image(ann): # 处理单个图像 pass results = Parallel(n_jobs=4)(delayed(process_image)(ann) for ann in annotations)内存优化:对于大尺寸图像,使用下采样处理
img = cv2.imread(image_path, cv2.IMREAD_REDUCED_COLOR_2) # 长宽各缩小一半缓存机制:将解析后的标注保存为中间文件,避免重复解析
import pickle # 保存 with open('coco_parsed.pkl', 'wb') as f: pickle.dump(parsed_annotations, f) # 加载 with open('coco_parsed.pkl', 'rb') as f: parsed_annotations = pickle.load(f)可视化加速:对于视频或连续帧,使用OpenCV的GUI模式实时显示而非保存图像
4.3 三种格式对比总结
下表对比了COCO、MPII和MMPose三种常见格式的特点:
| 特性 | COCO格式 | MPII格式 | MMPose格式 |
|---|---|---|---|
| 存储格式 | JSON | MAT | JSON |
| 关键点数量 | 17 | 16 | 可自定义 |
| 可见性标注 | 0/1/2 | 0/1 | 0/1/2 |
| 骨架定义 | 包含 | 不包含 | 包含 |
| 多人支持 | 是 | 是 | 是 |
| 典型应用 | 通用姿态估计 | 学术研究 | 工业级应用 |
| 处理难度 | 简单 | 复杂 | 中等 |
在实际项目中,我通常会将所有格式统一转换为MMPose格式,因为它在保持丰富信息量的同时,又具备较好的可读性和处理效率。特别是当需要处理多个数据源时,统一的中间格式能大大简化后续的开发流程。
