1. 基于帧间差分法的抖动检测
任务目标
实现基于帧间差分的全局运动检测算法:输入连续视频帧,计算相邻帧间的平移运动矢量 (dx, dy),为后续图像稳定提供运动估计基础。本案例聚焦于全局平移运动的检测,不涉及旋转与缩放。
核心原理
帧间差分法假设相邻帧间的全局运动主要表现为像素的整体平移。通过最小化两帧间像素差的值之和(SAD),在搜索窗口内寻找最佳偏移量,该偏移量即为估计的运动矢量。为降低噪声影响并提升计算效率,算法在灰度图上执行,并采用金字塔下采样策略。
完整实现代码
import numpy as np
import cv2
def compute_motion_vector(prev_gray, curr_gray, search_range=8, downscale=2):
"""
基于帧间差分法计算全局平移运动矢量。
步骤:下采样 -> 全搜索SAD匹配 -> 上采样补偿。
"""
# 1. 下采样加速
prev_small = cv2.pyrDown(prev_gray, dstsize=(prev_gray.shape[1]//downscale,
prev_gray.shape[0]//downscale))
curr_small = cv2.pyrDown(curr_gray, dstsize=(curr_gray.shape[1]//downscale,
curr_gray.shape[0]//downscale))
h, w = prev_small.shape
# 2. 在低分辨率上全搜索最佳偏移
min_sad = float('inf')
best_dx_small, best_dy_small = 0, 0
for dy in range(-search_range, search_range+1):
for dx in range(-search_range, search_range+1):
# 平移当前帧(用M矩阵平移,边界填充0)
M = np.float32([[1, 0, dx], [0, 1, dy]])
shifted = cv2.warpAffine(curr_small, M, (w, h), flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_CONSTANT, borderValue=0)
diff = cv2.absdiff(prev_small, shifted)
sad = np.sum(diff)
if sad < min_sad:
min_sad = sad
best_dx_small, best_dy_small = dx, dy
# 3. 映射回原始分辨率(乘以下采样倍数)
dx = best_dx_small * downscale
dy = best_dy_small * downscale
return dx, dy
# ---------- 最小可运行验证示例 ----------
if __name__ == "__main__":
# 构造两帧测试图像:第二帧相对第一帧向右平移3像素、向下平移2像素
h, w = 120, 160
prev = np.zeros((h, w), dtype=np.uint8)
cv2.rectangle(prev, (30, 30), (100, 80), 255, -1) # 白色矩形
cv2.circle(prev, (120, 60), 15, 200, -1) # 灰色圆形
M_true = np.float32([[1, 0, 3], [0, 1, 2]])
curr = cv2.warpAffine(prev, M_true, (w, h), flags=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_CONSTANT, borderValue=0)
# 调用算法
dx_est, dy_est = compute_motion_vector(prev, curr, search_range=8, downscale=2)
print(f"估计运动矢量: dx={dx_est}, dy={dy_est}")
print(f"真实运动矢量: dx=3, dy=2")
print(f"误差: dx_err={abs(dx_est-3)}, dy_err={abs(dy_est-2)}")
assert abs(dx_est-3) <= 2 and abs(dy_est-2) <= 2, "运动估计误差过大"
print("验证通过:估计值与真实值偏差在允许范围内")
运行与验证
- 依赖:Python 3.7+,NumPy,OpenCV(
pip install numpy opencv-python) - 运行方式:将上述代码保存为
motion_detect.py,在终端执行python motion_detect.py - 通过条件:程序输出估计运动矢量,且断言通过(误差≤2像素)。示例中真实平移为 (3, 2),算法应输出接近该值的估计结果。
关键说明
- 搜索窗口
search_range决定最大可检测位移(当前为±8像素,下采样后实际覆盖±16像素)。 - 下采样倍数
downscale降低计算量,但会损失亚像素精度,适用于整数像素级运动检测。 - 边界填充使用常数0,避免平移时引入非真实边缘信息。
- 若视频存在局部运动或光照突变,SAD全搜索可能失效,此时可先进行高斯平滑预处理。