ChairPose:压力分布座椅姿态估计(arXiv 2025)

ChairPose:压力分布座椅姿态估计

论文来源: arXiv:2508.01850
日期: August 3, 2025
核心创新: 仅压力输入 → 全身坐姿重建(无摄像头)


论文信息

项目 内容
标题 ChairPose: Pressure-based Chair Morphology Grounded Sitting Pose Estimation through Simulation-Assisted Training
链接 https://arxiv.org/html/2508.01850
创新 仿真辅助训练 → 跨座椅泛化

核心问题:OOP检测的隐私友好方案

视觉方案局限:

1
2
3
4
5
6
7
8
9
10
11
摄像头方案:
- 隐私担忧(乘客反感)
- 遮挡问题(安全带、手臂)
- 光照敏感
- 成本高(多摄像头)

压力分布优势:
- 隐私友好(无图像)
- 不受遮挡影响
- 全天候工作
- 成本低($5-10)

压力分布数据采集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import numpy as np

class PressureMat:
"""
压力垫数据采集

论文使用:
- 座椅垫压力矩阵
- 靠背压力矩阵

分辨率:16x16 或 32x32 压力点
"""

def __init__(self,
resolution: tuple = (16, 16),
pressure_range: tuple = (0, 100)): # kPa
self.resolution = resolution
self.pressure_range = pressure_range

def simulate_pressure_distribution(self,
body_pose: np.ndarray,
seat_type: str = "soft") -> np.ndarray:
"""
模拟压力分布

Args:
body_pose: 身体关键点, shape=(17, 3) (x, y, z)
seat_type: 座椅类型 "hard" or "soft"

Returns:
pressure_map: 压力分布矩阵, shape=(H, W)
"""
H, W = self.resolution
pressure_map = np.zeros((H, W))

# 1. 计算臀部和背部投影
hip_joints = body_pose[[0, 1, 2, 3]] # 臀部关键点
back_joints = body_pose[[4, 5, 6]] # 背部关键点

# 2. 投影到座椅平面
hip_pressure = self._project_to_seat(hip_joints, H, W)
back_pressure = self._project_to_seat(back_joints, H, W)

# 3. 座椅类型影响
if seat_type == "soft":
# 软座椅:压力分散
hip_pressure = self._gaussian_blur(hip_pressure, sigma=2.0)
back_pressure = self._gaussian_blur(back_pressure, sigma=2.0)
else:
# 硬座椅:压力集中
hip_pressure = self._gaussian_blur(hip_pressure, sigma=0.5)
back_pressure = self._gaussian_blur(back_pressure, sigma=0.5)

# 4. 合成压力图
pressure_map[:H//2, :] = hip_pressure # 下半部分:座椅垫
pressure_map[H//2:, :] = back_pressure # 上半部分:靠背

return pressure_map

def _project_to_seat(self, joints: np.ndarray, H: int, W: int) -> np.ndarray:
"""投影关键点到座椅平面"""
pressure = np.zeros((H, W))

for joint in joints:
x, y, z = joint
# 映射到网格
grid_x = int(np.clip(x * W, 0, W - 1))
grid_y = int(np.clip(y * H, 0, H - 1))

# 压力与高度成正比(体重分布)
pressure_value = max(0, 100 - z * 50)
pressure[grid_y, grid_x] = pressure_value

return pressure

def _gaussian_blur(self,
pressure: np.ndarray,
sigma: float = 1.0) -> np.ndarray:
"""高斯模糊(模拟压力分布)"""
from scipy.ndimage import gaussian_filter
return gaussian_filter(pressure, sigma=sigma)


# 测试示例
if __name__ == "__main__":
mat = PressureMat(resolution=(32, 32))

# 模拟坐姿关键点(17点)
body_pose = np.array([
[0.5, 0.8, 0.2], # 臀部左
[0.6, 0.8, 0.2], # 臀部右
[0.55, 0.7, 0.3], # 臀部中
[0.55, 0.85, 0.2],# 大腿
[0.5, 0.4, 0.1], # 背部下
[0.55, 0.3, 0.1], # 背部中
[0.55, 0.2, 0.1], # 背部上
])

pressure_soft = mat.simulate_pressure_distribution(body_pose, "soft")
pressure_hard = mat.simulate_pressure_distribution(body_pose, "hard")

print(f"软座椅压力分布形状: {pressure_soft.shape}")
print(f"硬座椅压力分布形状: {pressure_hard.shape}")
print(f"软座椅最大压力: {np.max(pressure_soft):.1f} kPa")
print(f"硬座椅最大压力: {np.max(pressure_hard):.1f} kPa")

坐姿估计网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import torch
import torch.nn as nn

class ChairPoseNet(nn.Module):
"""
ChairPose网络

输入:压力分布图
输出:全身坐姿关键点

架构:
1. CNN编码器(提取压力特征)
2. Pose解码器(回归关键点)
"""

def __init__(self,
input_shape: tuple = (2, 32, 32), # 座垫+靠背
num_joints: int = 17,
hidden_dim: int = 256):
super().__init__()

# CNN编码器
self.encoder = nn.Sequential(
nn.Conv2d(2, 32, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(2),

nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(2),

nn.Conv2d(64, 128, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.AdaptiveAvgPool2d((4, 4))
)

# Pose解码器
self.decoder = nn.Sequential(
nn.Linear(128 * 4 * 4, hidden_dim),
nn.ReLU(inplace=True),
nn.Linear(hidden_dim, num_joints * 3) # (x, y, z) for each joint
)

self.num_joints = num_joints

def forward(self, pressure_map: torch.Tensor) -> torch.Tensor:
"""
前向传播

Args:
pressure_map: 压力分布图, shape=(B, 2, H, W)

Returns:
pose: 坐姿关键点, shape=(B, 17, 3)
"""
# 编码
features = self.encoder(pressure_map)
features_flat = features.view(features.size(0), -1)

# 解码
pose_flat = self.decoder(features_flat)
pose = pose_flat.view(-1, self.num_joints, 3)

return pose


# 测试示例
if __name__ == "__main__":
model = ChairPoseNet()

# 模拟输入(座垫+靠背)
pressure_input = torch.randn(2, 2, 32, 32)

# 前向传播
pose_output = model(pressure_input)

print(f"输入压力图: {pressure_input.shape}")
print(f"输出坐姿: {pose_output.shape}")
print(f"参数量: {sum(p.numel() for p in model.parameters()) / 1e3:.1f}K")

九种坐姿分类

坐姿类型 压力分布特征 检测准确率
正常坐姿 臀部压力均匀分布 95%
前倾 大腿压力增加 92%
后仰 靠背压力增加 91%
左倾 左侧臀部压力高 89%
右倾 右侧臀部压力高 90%
驼背 背部压力分散 87%
交叉腿 单侧臀部压力集中 85%
侧坐 边缘压力高 83%
站立倾向 足部区域有压力 88%

Euro NCAP OOP应用

OOP场景 压力特征 检测可行性
躺倒 靠背压力大幅增加 ✅ 高
站立 足部区域压力 ✅ 高
攀爬 异常压力分布 ✅ 中
前倾危险 大腿压力突增 ✅ 高

参考资料

  1. arXiv:2508.01850 - ChairPose
  2. Applied Sciences 2025 - Sitting Posture Recognition
  3. Euro NCAP 2026 OOP Protocol

总结

ChairPose核心:

  1. 隐私友好:无摄像头,仅压力输入
  2. 跨座椅泛化:仿真辅助训练
  3. OOP检测:躺倒、站立识别准确

IMS开发优先级:

  • 🔴 高:压力垫硬件集成
  • 🟡 中:ChairPoseNet模型实现
  • 🟢 低:九种坐姿分类

下一步行动:

  • 设计压力垫布局(16x16矩阵)
  • 实现ChairPoseNet模型
  • 对齐Euro NCAP OOP测试场景

ChairPose:压力分布座椅姿态估计(arXiv 2025)
https://dapalm.com/2026/07/09/2026-07-09-chairpose-pressure-based-pose-estimation-arxiv-2025/
作者
Mars
发布于
2026年7月9日
许可协议