You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于关节角度与肢体段长度的Python人体骨骼绘制方案咨询

高效绘制人体骨骼的方法(基于关节角度与肢体段长)

核心思路:正向运动学(FK)递推关节坐标

不用手动计算每个关节与X轴的夹角,从你设定的根节点(左髋,坐标原点(0,0))出发,通过正向运动学自动递推所有关节的绝对坐标:

  • 以父关节为基准,根据肢体段长度和关节夹角,计算子关节相对于父关节的坐标偏移
  • 累加偏移量得到子关节的绝对坐标
  • 重复此过程遍历所有关节连接

步骤与Python实现

1. 明确关节映射与连接关系

先把关节编号对应到身体部位,定义父-子关节对(对应肢体段):

肢体段父关节子关节长度(cm)
髋间(hip)23(左髋)24(右髋)20.4
躯干(trunk)24(右髋)12(躯干上端)49.3
肩宽(shoulders)12(躯干上端)11(左肩)17.0(肩宽总长度34,左右各半)
肩宽(shoulders)12(躯干上端)14(右肩)17.0
上臂(upper arm)11(左肩)13(左肘)29.41
前臂(forearm)13(左肘)15(左手)27.2
上臂(upper arm)14(右肩)16(右肘)29.41
前臂(forearm)16(右肘)(对应手部节点)27.2
大腿(upper leg)23(左髋)25(左膝)42.33
小腿(lower leg)25(左膝)27(左脚)42.5
大腿(upper leg)24(右髋)26(右膝)42.33
小腿(lower leg)26(右膝)28(右脚)42.5

2. 代码实现(自动计算坐标+绘图)

使用numpy处理角度计算,matplotlib完成绘图:

import numpy as np
import matplotlib.pyplot as plt

# 输入你的数据
joint_angles = {
    (12, 14, 16): 168.54785591626595,
    (14, 12, 24): 172.77150681015084,
    (24, 12, 11): 54.37272304423055,
    (12, 11, 23): 117.01615512185863,
    (11, 23, 24): 108.6334963772736,
    (23, 11, 13): 45.915788777620314,
    (11, 13, 15): 177.83453548133326,
    (23, 24, 12): 79.97762545663724,
    (26, 24, 23): 163.4421588161629,
    (24, 23, 25): 145.8882059820918,
    (28, 26, 24): 103.70318526501839,
    (23, 25, 27): 178.10520631231438
}

segment_lengths = {
    'hip': 20.4,
    'trunk': 49.3,
    'shoulders': 34.0,
    'forearm': 27.2,
    'upper arm': 29.409999999999997,
    'upper leg': 42.33,
    'lower leg': 42.5
}

# 初始化关节坐标,左髋(23)为原点
joint_coords = {23: np.array([0.0, 0.0])}

# 1. 计算右髋(24):左髋到右髋沿X轴正方向
joint_coords[24] = joint_coords[23] + np.array([segment_lengths['hip'], 0.0])

# 2. 计算躯干上端(12):从右髋(24)出发
angle_trunk = np.deg2rad(180 - joint_angles[(23,24,12)])
dx_trunk = segment_lengths['trunk'] * np.cos(angle_trunk)
dy_trunk = segment_lengths['trunk'] * np.sin(angle_trunk)
joint_coords[12] = joint_coords[24] + np.array([dx_trunk, dy_trunk])

# 3. 计算左肩(11):从躯干上端(12)出发
vec_12_24 = joint_coords[24] - joint_coords[12]
angle_12_24 = np.arctan2(vec_12_24[1], vec_12_24[0])
angle_12_11 = angle_12_24 + np.deg2rad(joint_angles[(24,12,11)])
dx_shoulder_left = 17.0 * np.cos(angle_12_11)
dy_shoulder_left = 17.0 * np.sin(angle_12_11)
joint_coords[11] = joint_coords[12] + np.array([dx_shoulder_left, dy_shoulder_left])

# 4. 计算右肩(14):从躯干上端(12)出发
angle_12_14 = angle_12_24 - np.deg2rad(180 - joint_angles[(14,12,24)])
dx_shoulder_right = 17.0 * np.cos(angle_12_14)
dy_shoulder_right = 17.0 * np.sin(angle_12_14)
joint_coords[14] = joint_coords[12] + np.array([dx_shoulder_right, dy_shoulder_right])

# 5. 计算左肘(13):从左肩(11)出发
vec_11_23 = joint_coords[23] - joint_coords[11]
angle_11_23 = np.arctan2(vec_11_23[1], vec_11_23[0])
angle_11_13 = angle_11_23 + np.deg2rad(joint_angles[(23,11,13)])
dx_upper_arm_left = segment_lengths['upper arm'] * np.cos(angle_11_13)
dy_upper_arm_left = segment_lengths['upper arm'] * np.sin(angle_11_13)
joint_coords[13] = joint_coords[11] + np.array([dx_upper_arm_left, dy_upper_arm_left])

# 6. 计算左手(15):从左肘(13)出发
vec_13_11 = joint_coords[11] - joint_coords[13]
angle_13_11 = np.arctan2(vec_13_11[1], vec_13_11[0])
angle_13_15 = angle_13_11 + np.deg2rad(180 - joint_angles[(11,13,15)])
dx_forearm_left = segment_lengths['forearm'] * np.cos(angle_13_15)
dy_forearm_left = segment_lengths['forearm'] * np.sin(angle_13_15)
joint_coords[15] = joint_coords[13] + np.array([dx_forearm_left, dy_forearm_left])

# 7. 计算左膝(25):从左髋(23)出发
vec_23_24 = joint_coords[24] - joint_coords[23]
angle_23_24 = np.arctan2(vec_23_24[1], vec_23_24[0])
angle_23_25 = angle_23_24 + np.deg2rad(joint_angles[(24,23,25)])
dx_upper_leg_left = segment_lengths['upper leg'] * np.cos(angle_23_25)
dy_upper_leg_left = segment_lengths['upper leg'] * np.sin(angle_23_25)
joint_coords[25] = joint_coords[23] + np.array([dx_upper_leg_left, dy_upper_leg_left])

# 8. 计算左脚(27):从左膝(25)出发
vec_25_23 = joint_coords[23] - joint_coords[25]
angle_25_23 = np.arctan2(vec_25_23[1], vec_25_23[0])
angle_25_27 = angle_25_23 + np.deg2rad(180 - joint_angles[(23,25,27)])
dx_lower_leg_left = segment_lengths['lower leg'] * np.cos(angle_25_27)
dy_lower_leg_left = segment_lengths['lower leg'] * np.sin(angle_25_27)
joint_coords[27] = joint_coords[25] + np.array([dx_lower_leg_left, dy_lower_leg_left])

# 9. 计算右膝(26):从右髋(24)出发
vec_24_23 = joint_coords[23] - joint_coords[24]
angle_24_23 = np.arctan2(vec_24_23[1], vec_24_23[0])
angle_24_26 = angle_24_23 + np.deg2rad(180 - joint_angles[(26,24,23)])
dx_upper_leg_right = segment_lengths['upper leg'] * np.cos(angle_24_26)
dy_upper_leg_right = segment_lengths['upper leg'] * np.sin(angle_24_26)
joint_coords[26] = joint_coords[24] + np.array([dx_upper_leg_right, dy_upper_leg_right])

# 10. 计算右脚(28):从右膝(26)出发
vec_26_24 = joint_coords[24] - joint_coords[26]
angle_26_24 = np.arctan2(vec_26_24[1], vec_26_24[0])
angle_26_28 = angle_26_24 + np.deg2rad(joint_angles[(28,26,24)])
dx_lower_leg_right = segment_lengths['lower leg'] * np.cos(angle_26_28)
dy_lower_leg_right = segment_lengths['lower leg'] * np.sin(angle_26_28)
joint_coords[28] = joint_coords[26] + np.array([dx_lower_leg_right, dy_lower_leg_right])

# 补充右肘(16)坐标
vec_14_12 = joint_coords[12] - joint_coords[14]
angle_14_12 = np.arctan2(vec_14_12[1], vec_14_12[0])
angle_14_16 = angle_14_12 + np.deg2rad(180 - joint_angles[(12,14,16)])
joint_coords[16] = joint_coords[14] + np.array([segment_lengths['upper arm']*np.cos(angle_14_16), segment_lengths['upper arm']*np.sin(angle_14_16)])

# 绘制骨骼图
plt.figure(figsize=(8, 10))
# 定义骨骼连线
bones = [
    (23,24), (24,12), (12,11), (12,14),
    (11,13), (13,15), (14,16),
    (23,25), (25,27), (24,26), (26,28)
]

for bone in bones:
    x = [joint_coords[bone[0]][0], joint_coords[bone[1]][0]]
    y = [joint_coords[bone[0]][1], joint_coords[bone[1]][1]]
    plt.plot(x, y, 'b-', linewidth=3)
# 绘制关节点
for j_id, coord in joint_coords.items():
    plt.scatter(coord[0], coord[1], c='red', s=50, zorder=5)
    plt.text(coord[0]+1, coord[1]+1, str(j_id), fontsize=10)

plt.gca().set_aspect('equal', adjustable='box')
plt.title('人体骨骼可视化')
plt.xlabel('X坐标(cm)')
plt.ylabel('Y坐标(cm)')
plt.grid(True)
plt.show()

3. 优化建议

  • 把关节坐标计算逻辑封装成通用函数,比如get_child_coord(parent_coord, ref_angle, joint_angle, seg_len),避免重复代码
  • 如果需要3D可视化,可扩展坐标到三维,使用matplotlib的3D模块,或PyVista、Open3D库
  • 若处理时序角度数据,可循环计算每一帧坐标,实现骨骼动画

替代工具

  • OpenCV:适合实时骨骼绘制,可对接视频流应用
  • Blender Python API:生成高精度3D骨骼模型,支持渲染导出
  • Maya Python API:专业3D动画流程,适合复杂骨骼绑定需求

内容的提问来源于stack exchange,提问作者Anónimo salvaje

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 17:09:49