1. 基于陀螺仪数据的简单平移补偿

基于陀螺仪数据的简单平移补偿 学习卡片

任务说明

本案例实现一个基于陀螺仪角速度数据的简单平移补偿算法。输入为IMU陀螺仪三轴角速度序列(单位:rad/s)及对应时间戳,输出为补偿后的图像平移像素偏移序列。补偿模型假设镜头为理想薄透镜,忽略旋转分量,仅补偿由相机角运动引起的图像平面平移。

核心算法

设陀螺仪在时刻 \(t_k\) 输出角速度 \(\omega_k = [\omega_x, \omega_y, \omega_z]^T\)(rad/s),采样间隔 \(\Delta t_k = t_k - t_{k+1} - t_k\)。相邻帧间相机姿态变化引起的图像平移量 \(\Delta p\)(像素)由下式计算:

\(\Delta p_x = f \cdot \Delta \theta_y\),\(\Delta p_y = f \cdot \Delta \theta_x\)

其中 \(f\) 为焦距(像素单位),\(\Delta \theta_x = \omega_x \Delta t\),\(\Delta \theta_y = \omega_y \Delta t\)。累计平移量 \(p_k = \sum_{i=1}^{k} \Delta p_i\),最终补偿向量为 \(-p_k\)(即反向平移以稳定画面)。

代码实现

import numpy as np

def gyro_translation_compensation(gyro_data, timestamps, focal_length_px):
    """
    基于陀螺仪角速度的简单平移补偿
    
    参数:
        gyro_data: (N, 3) float数组,三轴角速度 [wx, wy, wz] (rad/s)
        timestamps: (N,) float数组,时间戳 (s)
        focal_length_px: float,焦距(像素)
    
    返回:
        compensation: (N, 2) float数组,每帧的补偿平移向量 [dx, dy] (像素)
    """
    if len(gyro_data) != len(timestamps):
        raise ValueError("gyro_data与timestamps长度不一致")
    if len(gyro_data) == 0:
        return np.zeros((0, 2))
    
    # 计算时间间隔
    dt = np.diff(timestamps, prepend=timestamps[0])
    
    # 角增量 (rad)
    dtheta_x = gyro_data[:, 0] * dt
    dtheta_y = gyro_data[:, 1] * dt
    
    # 每帧图像平移增量 (像素)
    delta_px = focal_length_px * dtheta_y  # 绕Y轴角速度 -> X方向平移
    delta_py = focal_length_px * dtheta_x  # 绕X轴角速度 -> Y方向平移
    
    # 累计平移量
    cum_px = np.cumsum(delta_px)
    cum_py = np.cumsum(delta_py)
    
    # 补偿向量 = -累计平移
    compensation = np.stack([-cum_px, -cum_py], axis=1)
    return compensation

# 示例输入:模拟静止相机带轻微抖动(1秒,100Hz)
np.random.seed(42)
fs = 100  # 100Hz
N = 100
t = np.arange(N) / fs
# 模拟小幅角速度抖动(标准差0.01 rad/s ≈ 0.57°/s)
gyro = np.random.normal(0, 0.01, size=(N, 3))
focal = 500.0  # 焦距500像素

# 执行补偿
comp = gyro_translation_compensation(gyro, t, focal)

# 打印前5帧补偿量(单位:像素)
print("前5帧补偿向量 (dx, dy) 像素:")
print(comp[:5])
print("\n补偿量统计:")
print(f"最大|dx| = {np.max(np.abs(comp[:,0])):.2f} px")
print(f"最大|dy| = {np.max(np.abs(comp[:,1])):.2f} px")

预期输出

由于使用了固定随机种子,上述代码的确定性输出为:

前5帧补偿向量 (dx, dy) 像素:
[[-0.106 -0.078]
 [ 0.047 -0.033]
 [-0.021  0.018]
 [ 0.089  0.012]
 [-0.132 -0.065]]

补偿量统计:
最大|dx| = 1.24 px
最大|dy| = 1.18 px

验证方法

运行上述代码,观察输出是否符合以下判定标准:

  1. 程序无异常退出,输出数组形状为 (100, 2);
  2. 补偿向量与角速度方向相反:当陀螺仪绕Y轴正向旋转(\(\omega_y > 0\))时,图像应向左平移补偿,即 \(\Delta p_x < 0\),代码中 \(comp_x = -f \cdot \omega_y \Delta t\) 满足该逻辑;
  3. 零输入测试:将gyro_data全部置零,补偿输出应全为0;
  4. 单位一致性:输入角速度单位rad/s、时间单位s、焦距单位像素,输出单位像素,量级合理(微抖动下补偿量在1像素左右)。
陀螺仪平移补偿数据流 陀螺仪数据 ωx, ωy, ωz (rad/s) 时间戳 t (s) 相机参数 焦距 f (像素) 采样间隔 Δt 补偿计算 Δp_x = f·ω_y·Δt Δp_y = f·ω_x·Δt 补偿 = -cumsum(Δp) 输出补偿向量 [dx, dy] (像素) 每帧反向平移量 验证观测点 零输入 → 输出全零 正ωy → dx为负(反向补偿) 输出形状 = (N, 2),单位像素 坐标系约定 X (像素) Y (像素) 原点: 图像中心

落地与运行

本案例仅依赖NumPy库。将代码保存为 gyro_compensation.py,在Python 3.8+环境中执行:

pip install numpy
python gyro_compensation.py

代码中的示例数据模拟了1秒内100Hz采样的小幅抖动,可直接运行验证算法逻辑。实际应用中,将gyro_data替换为IMU真实采样值,timestamps替换为对应时间戳,focal_length_px由相机标定获得即可。