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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
| """ Everybody Tracking Every Body - 多视角自我中心 3D 姿态融合
核心思路: 1. 每人佩戴摄像头 → VIO SLAM 获得头部运动轨迹 2. 第一人称视角 → 推断自身身体姿态 3. 第三人称视角(看到他人)→ 推断他人姿态 4. 扩散模型融合 → 基于头运动+外向观测
关键挑战: - 外向观测稀疏、间歇、可靠性变化大 - 需要同时处理内容和可靠性 """
import torch import torch.nn as nn import torch.nn.functional as F
class EgocentricPoseEncoder(nn.Module): """ 自我中心视角姿态编码器 从第一人称视频提取自身身体姿态估计 """ def __init__(self, feat_dim: int = 256): super().__init__() self.visual_encoder = nn.Sequential( nn.Conv2d(3, 32, 3, stride=2, padding=1), nn.ReLU(), nn.Conv2d(32, 64, 3, stride=2, padding=1), nn.ReLU(), nn.Conv2d(64, 128, 3, stride=2, padding=1), nn.ReLU(), nn.AdaptiveAvgPool2d((4, 4)), nn.Flatten(), nn.Linear(128 * 16, feat_dim) ) def forward(self, ego_frame: torch.Tensor) -> torch.Tensor: return self.visual_encoder(ego_frame)
class ExocentricPoseEncoder(nn.Module): """ 外向视角(看到他人)姿态编码器 从第三人称视角提取他人姿态估计 包含可靠性估计 """ def __init__(self, feat_dim: int = 256): super().__init__() self.visual_encoder = nn.Sequential( nn.Conv2d(3, 32, 3, stride=2, padding=1), nn.ReLU(), nn.Conv2d(32, 64, 3, stride=2, padding=1), nn.ReLU(), nn.Conv2d(64, 128, 3, stride=2, padding=1), nn.ReLU(), nn.AdaptiveAvgPool2d((4, 4)), nn.Flatten(), nn.Linear(128 * 16, feat_dim) ) self.reliability_head = nn.Sequential( nn.Linear(feat_dim, 64), nn.ReLU(), nn.Linear(64, 1), nn.Sigmoid() ) def forward(self, exo_frame: torch.Tensor) -> tuple: feat = self.visual_encoder(exo_frame) reliability = self.reliability_head(feat) return feat, reliability
class DiffusionFusionModel(nn.Module): """ 扩散模型融合 将头部运动先验 + 第一人称 + 第三人称观测 通过扩散过程融合为最终姿态 论文核心:条件于观测内容和可靠性 """ def __init__(self, pose_dim: int = 17 * 3, feat_dim: int = 256): super().__init__() self.pose_dim = pose_dim self.ego_encoder = nn.Linear(feat_dim, 128) self.exo_encoder = nn.Linear(feat_dim, 128) self.head_motion_encoder = nn.Linear(6, 128) self.denoise_net = nn.Sequential( nn.Linear(pose_dim + 128 * 3, 512), nn.ReLU(), nn.Linear(512, 512), nn.ReLU(), nn.Linear(512, 512), nn.ReLU(), nn.Linear(512, pose_dim) ) def forward(self, noisy_pose: torch.Tensor, t: torch.Tensor, ego_feat: torch.Tensor, exo_feat: torch.Tensor, head_motion: torch.Tensor) -> torch.Tensor: """ 去噪一步 Args: noisy_pose: (B, pose_dim) 加噪的姿态 t: (B,) 时间步 ego_feat: (B, 128) 自我中心特征 exo_feat: (B, 128) 外向观测特征 head_motion: (B, 6) 头部运动 """ ego_cond = self.ego_encoder(ego_feat) exo_cond = self.exo_encoder(exo_feat) head_cond = self.head_motion_encoder(head_motion) x = torch.cat([noisy_pose, ego_cond, exo_cond, head_cond], dim=-1) return self.denoise_net(x)
class MultiPersonPoseTracker: """ 多人姿态追踪系统 IMS 远期应用:座舱内多乘员姿态追踪 (不是每人佩戴摄像头,而是车内多个摄像头角度) """ def __init__(self, num_persons: int = 4, num_cameras: int = 3): self.num_persons = num_persons self.num_cameras = num_cameras self.exo_encoders = nn.ModuleList([ ExocentricPoseEncoder() for _ in range(num_cameras) ]) self.fusion = DiffusionFusionModel() def estimate_pose(self, camera_frames: list, head_motion: torch.Tensor): """ 从多个摄像头角度估计所有乘员姿态 Args: camera_frames: 每个摄像头的图像 head_motion: 驾驶员头部运动(从 IMU/SLAM) """ all_feats = [] for i, frame in enumerate(camera_frames): feat, reliability = self.exo_encoders[i](frame) all_feats.append((feat, reliability)) total_feat = sum(f * r for f, r in all_feats) / len(all_feats) noisy_pose = torch.randn(1, 51) for t in range(10, 0, -1): with torch.no_grad(): noise = self.fusion( noisy_pose, torch.tensor([t]), total_feat, total_feat, head_motion ) noisy_pose = noisy_pose - noise * 0.1 return noisy_pose
if __name__ == "__main__": tracker = MultiPersonPoseTracker(num_persons=4, num_cameras=3) frames = [torch.randn(1, 3, 224, 224) for _ in range(3)] head_motion = torch.randn(1, 6) pose = tracker.estimate_pose(frames, head_motion) print(f"输出姿态: {pose.shape} (17 joints × 3D)") print(f"参数量: {sum(p.numel() for p in tracker.parameters()):,}")
|