奇异值分解(SVD)在3D骨骼旋转中的应用:原理与实现

奇异值分解(SVD)在3D骨骼旋转中的应用:原理与实现

引言

在做在三维计算机视觉的人物姿态识别的项目过程中,遇到一个问题,摄像头只有一个,只采集了一个正面的数据,但是在实际测试过程中,摄像头的位置可能是人物的其他角度,比如30度或者随机。为了做数据增强,将这些采集的数据3D骨骼数据,全部做每个角度旋转的数据增强。

一、 实现思路

在 3D 空间中,对骨骼数据进行旋转通常有两种场景:

  1. 已知目标角度:直接构造旋转矩阵并相乘。
  2. 已知目标姿态(但不知具体角度):通过 SVD 求解最优旋转矩阵(Kabsch 算法)。

该项目符合场景 1 的设定,但使用场景 2 的算法流程。具体思路如下:

  1. 定义数据 :构建一个 N×3N \times 3N×3 的矩阵存储 3D 骨骼关节坐标。
  2. 中心化:将骨骼中心点平移至原点,消除平移分量,仅保留旋转信息。
  3. 构造目标 :根据指定角度(如 30°)构造真实的旋转矩阵 RtrueR_{true}Rtrue,生成旋转后的目标数据 YYY。
  4. SVD 求解 :计算原始数据与目标数据的交叉协方差矩阵 H=XTYH = X^T YH=XTY,对其进行 SVD 分解,按公式 R=VUTR = V U^TR=VUT 提取纯旋转矩阵。
  5. 应用旋转 :将求得的旋转矩阵 RRR 乘回原始数据,完成旋转对齐。

二、 代码实现

以下代码仅定义了一个变量 skeleton 作为 3D 骨骼数据,其余均为过程变量。

python 复制代码
import numpy as np

==

1. 定义 3D 骨骼数据 (6个关节, xyz坐标)

==

skeleton = np.array([
    [0, 0, 0],    # 髋部
    [0, 10, 0],   # 脊柱
    [5, 10, 0],   # 右肩
    [-5, 10, 0],  # 左肩
    [5, 20, 0],   # 右肘
    [-5, 20, 0]   # 左肘
], dtype=float)

==

2. 中心化(消除平移,聚焦旋转)

==

centroid = skeleton.mean(axis=0)
skeleton_centered = skeleton - centroid

==

3. 设定目标角度并构造真实旋转矩阵

==

angle = np.radians(30)  # 转为弧度
绕 Y 轴旋转的矩阵(右手系顺时针)

R_true = np.array([
    [np.cos(angle), 0, np.sin(angle)],
    [0, 1, 0],
    [-np.sin(angle), 0, np.cos(angle)]
])

生成旋转后的目标数据(模拟已知目标姿态)

skeleton_target = skeleton_centered @ R_true.T

==

4. 利用 SVD 求解旋转矩阵 (Kabsch 算法)

==

4.1 计算交叉协方差矩阵 H

H = skeleton_centered.T @ skeleton_target

4.2 对 H 进行 SVD 分解

U, S, Vt = np.linalg.svd(H)
V = Vt.T

4.3 组合出纯旋转矩阵 R_svd

R_svd = V @ U.T

4.4 确保是纯旋转(行列式为 +1,避免反射)

if np.linalg.det(R_svd) < 0:
    V[:, -1] *= -1
    R_svd = V @ U.T

==

5. 应用 SVD 求得的旋转矩阵

==

skeleton_rotated = skeleton_centered @ R_svd.T + centroid

验证结果

print("SVD 求得的旋转矩阵是否与真实矩阵一致:", np.allclose(R_svd, R_true))

三、 原理解析

Q1: 代码中的 @ 运算符是什么意思?

@ 是 Python 中用于矩阵乘法的运算符。

  • 对于 NumPy 数组,A @ B 等价于 np.dot(A, B)。
  • 它执行的是线性代数中的矩阵乘法(行乘列求和),而非逐元素相乘(* 运算符)。
  • 在代码中,skeleton_centered.T @ skeleton_target 执行了 (3×N)×(N×3)(3 \times N) \times (N \times 3)(3×N)×(N×3) 的乘法,得到一个 3×33 \times 33×3 的矩阵。

Q2: np.linalg.svd 背后的数学原理是什么?

np.linalg.svd(H) 对矩阵 HHH 进行奇异值分解,将其拆解为三个矩阵的乘积:

H=UΣVT H = U \Sigma V^T H=UΣVT

  • UUU:左奇异向量矩阵(m×mm \times mm×m,正交矩阵)。
  • Σ\SigmaΣ:奇异值矩阵(m×nm \times nm×n,对角线为非负实数,按降序排列)。
  • VTV^TVT:右奇异向量矩阵的转置(n×nn \times nn×n,正交矩阵)。

数值计算原理 :SVD 通常通过求解 HTHH^T HHTH 和 HHTH H^THHT 的特征值与特征向量来间接获得。对 HTHH^T HHTH 做特征分解,其特征向量构成 VVV,特征值的平方根构成 Σ\SigmaΣ;对 HHTH H^THHT 做特征分解,其特征向量构成 UUU。

Q3: 为什么在进行奇异值分解之前要计算协方差矩阵 HHH?

计算 H=XTYH = X^T YH=XTY 是为了将"寻找最优旋转"这一几何问题转化为"最大化矩阵迹"的代数问题。

  • 目标函数 :我们希望找到旋转矩阵 RRR 使得 ∥XR−Y∥F2\| X R - Y \|_F^2∥XR−Y∥F2 最小。
  • 化简 :展开后可得,最小化该误差等价于最大化 tr(RT(XTY))\text{tr}(R^T (X^T Y))tr(RT(XTY)),即 tr(RTH)\text{tr}(R^T H)tr(RTH)。
  • SVD 的作用 :数学上已证明,对于正交矩阵 RRR,使得 tr(RTH)\text{tr}(R^T H)tr(RTH) 最大化的解是 R=VUTR = V U^TR=VUT(其中 H=UΣVTH = U \Sigma V^TH=UΣVT)。因此,计算 HHH 是为了给 SVD 提供一个能够解码出最优旋转的"关系矩阵"。

Q4: 为什么协方差矩阵是 H = skeleton_centered.T @ skeleton_target 这样计算的?

这涉及矩阵乘法的维度与内积的几何意义。

  • 维度匹配 :skeleton_centered 是 N×3N \times 3N×3,转置后为 3×N3 \times N3×N。与目标 N×3N \times 3N×3 相乘,得到 3×33 \times 33×3 的矩阵 HHH。
  • 元素含义 :HHH 的第 iii 行第 jjj 列元素为 Hij=∑k=1NXkiYkjH_{ij} = \sum_{k=1}^N X_{ki} Y_{kj}Hij=∑k=1NXkiYkj。这表示源点集的第 iii 个坐标轴与目标点集的第 jjj 个坐标轴之间的内积。
  • 协方差本质 :在中心化后,内积正比于两个向量之间的协方差。HHH 打包了原始坐标系与目标坐标系之间所有轴的对应关系,描述了从一个空间到另一个空间的线性变换强度与方向。

Q5: 为什么需要检查 np.linalg.det(R_svd) < 0 并修正?

SVD 分解得到的 UUU 和 VVV 是正交矩阵,因此 R=VUTR = V U^TR=VUT 也是正交矩阵,但它可能包含反射(即行列式为 −1-1−1)。

  • 纯旋转要求 :在三维空间中,纯旋转矩阵的行列式必须为 +1+1+1。
  • 修正方法 :若 det⁡(VUT)<0\det(V U^T) < 0det(VUT)<0,则将 VVV 的最后一列乘以 −1-1−1(等价于在 Σ\SigmaΣ 中引入一个负号),重新计算 R=VUTR = V U^TR=VUT,此时行列式变为 +1+1+1,确保得到的是纯旋转而非反射变换。
相关推荐
Martina_03211 小时前
AI生成的3D白模单帧没问题,镜头一移动就被挡?用6步检查遮挡与构图
图像处理·人工智能·数学建模·3d·ai·自然语言处理·游戏策划
时间的情敌2 天前
Cesium 建筑单体化、3DTiles 分类、楼层显隐、分户高亮(BIM + 倾斜孪生高频)
前端·3d·cesium
加搜科技观察3 天前
哪个品牌 3D 相机好用?工业 3D 相机品牌选型评估指南
数码相机·3d
Martina_03215 天前
AI生成3D场景的霓虹灯一开就糊成光团?用6步检查Emissive、Bloom与曝光
人工智能·3d·ai·自然语言处理·游戏引擎·材质·贴图
Martina_03215 天前
AI生成3D场景从白模换成精模后镜头全偏了?用6步检查单位、枢轴与层级替换
图像处理·人工智能·3d·ai·自然语言处理·材质·1024程序员节
时间的情敌6 天前
Cesium 加载 3D Tiles 倾斜摄影、压平、样式设置(Vue3 实战)
vue.js·3d·cesium
AGI_Eval8 天前
AI 3D生成技术:从“可用”走向“可靠”还有多远?
人工智能·3d
翌日阳9 天前
二十分之一的压缩比:Spatial Vivid 1.0 把 3DGS 全链路参考实现按 MIT 开源了
3d·开源
Dream-Y.ocean10 天前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
硕迪科技SOLIDWORKS10 天前
SOLIDWORKS Electrical 2027:从线束定义到2D–3D更改分析
3d·solidworks 202