
本文介绍如何将原本分散在多行中的33个关键点(如nose、left_eye等)的x/y/z坐标,按时间戳对齐并合并为单行记录,确保每个时间戳对应完整的一组33×3=99维坐标特征。
本文介绍如何将原本分散在多行中的33个关键点(如nose、left_eye等)的x/y/z坐标,按时间戳对齐并合并为单行记录,确保每个时间戳对应完整的一组33×3=99维坐标特征。
在人体姿态估计任务中,常需将33个关键点(body_pose)的三维坐标(x/y/z)按帧(timestamp)组织为结构化表格。但原始输出往往将同一帧的关键点数据跨多行存储(例如NOSE_x/y/z在第0行,LEFT_EYE_INNER_x/y/z在第1行……),导致无法直接用于建模或分析。正确做法是:以首个关键点(如NOSE_x)为“行起始信号”,逐行累积同帧数据,直到收集齐全部33个关键点,再输出为一行完整记录。
核心思路:基于关键点标识的流式合并
不依赖固定行号或计数器,而是利用关键点名称作为“锚点”——当读取到 NOSE_x 非空时,即开启新记录;当检测到末尾关键点(如 RIGHT_FOOT_INDEX_z)非空时,视为该帧数据收齐。此方法鲁棒性强,可应对缺失值或顺序微调。
✅ 推荐实现(优化版CSV合并逻辑)
import csv
import pandas as pd
from datetime import datetime
# 定义33个关键点顺序(与body_pose严格一致)
KEYPOINTS = [
'NOSE', 'LEFT_EYE_INNER', 'LEFT_EYE', 'LEFT_EYE_OUTER', 'RIGHT_EYE_INNER',
'RIGHT_EYE', 'RIGHT_EYE_OUTER', 'LEFT_EAR', 'RIGHT_EAR', 'MOUTH_LEFT',
'MOUTH_RIGHT', 'LEFT_SHOULDER', 'RIGHT_SHOULDER', 'LEFT_ELBOW', 'RIGHT_ELBOW',
'LEFT_WRIST', 'RIGHT_WRIST', 'LEFT_PINKY', 'RIGHT_PINKY', 'LEFT_INDEX',
'RIGHT_INDEX', 'LEFT_THUMB', 'RIGHT_THUMB', 'LEFT_HIP', 'RIGHT_HIP',
'LEFT_KNEE', 'RIGHT_KNEE', 'LEFT_ANKLE', 'RIGHT_ANKLE', 'LEFT_HEEL',
'RIGHT_HEEL', 'LEFT_FOOT_INDEX', 'RIGHT_FOOT_INDEX'
]
def merge_keypoints_csv(input_path: str, output_path: str):
"""将分散的keypoint CSV合并为每行含完整33×3坐标的格式"""
# 生成所有列名:Timestamp + [kp+'_x', kp+'_y', kp+'_z' for kp in KEYPOINTS]
columns = ['Timestamp'] + [f"{kp}_{axis}" for kp in KEYPOINTS for axis in ['x','y','z']]
merged_rows = []
current_row = {}
with open(input_path, 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
# 检测新帧开始:NOSE_x存在且非空
if row.get('NOSE_x', '').strip():
# 保存上一帧(若存在)
if current_row:
merged_rows.append(current_row.copy())
# 初始化新帧
current_row = {'Timestamp': row.get('Timestamp', '')}
# 累积当前行的有效坐标
for key, value in row.items():
if value.strip() and '_' in key:
# 解析 key: "NOSE_x" → kp="NOSE", axis="x"
parts = key.rsplit('_', 1)
if len(parts) == 2 and parts[0] in KEYPOINTS and parts[1] in ['x','y','z']:
current_row[key] = value
# 检测帧结束:最后一个关键点的z坐标存在
last_kp_z = f"{KEYPOINTS[-1]}_z"
if row.get(last_kp_z, '').strip() and current_row:
merged_rows.append(current_row.copy())
current_row = {}
# 转为DataFrame并补全缺失列(避免列顺序错乱)
df = pd.DataFrame(merged_rows)
# 确保列顺序严格匹配columns定义
df = df.reindex(columns=columns, fill_value='')
# 保存为Excel(保留原始逻辑)
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
df.to_excel(writer, sheet_name='pose', index=False)
print(f"✅ 合并完成!共生成 {len(df)} 行完整关键点数据,已保存至 {output_path}")
# 使用示例
# merge_keypoints_csv('raw_output.csv', 'koordinat_merged.xlsx')
⚠️ 注意事项
- 时间戳一致性:原始代码中 datetime.now() 在循环内调用会导致同一帧内各关键点时间戳微小差异。应改为在每帧开始时统一获取一次时间戳,并传递给所有关键点。
- 缺失值处理:若某关键点坐标缺失(空字符串/None),上述逻辑会跳过该字段,最终行中对应列为''。生产环境建议替换为np.nan并显式填充。
- 性能优化:对大数据集,避免频繁append(),改用列表推导+pd.concat()批量处理。
- 扩展性:若需支持right_hand/left_hand等多模态数据,可对每个pose_type独立执行此合并流程。
通过此方案,您将获得标准的“每行=1帧+33关键点×3坐标”的宽表结构,完美适配后续的机器学习训练、时序分析或可视化需求。











