3. 全局运动估计:基于相位相关的全局配准方法
运动估计,说白了就是搞清楚两张图之间到底「动了多少」。在 HDR 合成里,这个步骤尤其关键——你想想看,手持拍摄的多帧曝光序列,怎么可能纹丝不动?哪怕上了三脚架,按快门那一下也会有微位移。
我最早做 HDR 时,用的是最朴素的模板匹配。后来发现,一旦遇到曝光差异大的帧对,亮度变化会直接把匹配结果带偏。直到我接触到相位相关这个方法,才算是找到了一个真正鲁棒的全局运动估计方案。
3.1 相位相关的核心思想
相位相关为什么能抗亮度变化?因为它根本不看像素值本身,而是看频域里的相位差。
两张图如果只有平移,它们的傅里叶变换幅度谱是一样的,差别只体现在相位上。具体来说:
- 对参考图和待配准图分别做 FFT
- 计算互功率谱的归一化形式
- 对互功率谱做逆 FFT,得到一个脉冲函数
- 脉冲峰值的位置,就是平移量
这个脉冲有多尖锐?理论上,如果图像内容完全一致且只有平移,你会看到一个完美的 Dirac 脉冲。实际中因为噪声和曝光差异,峰值会扩散一些,但依然非常明显。
3.2 数学原理速览
这里我尽量不堆公式,但核心逻辑你得理解。假设参考图 \( f_1(x,y) \) 和待配准图 \( f_2(x,y) \) 满足:
f₂(x,y) = f₁(x - Δx, y - Δy)
傅里叶变换后:
F₂(u,v) = F₁(u,v) · e^{-j2π(uΔx + vΔy)}
互功率谱就是:
R(u,v) = (F₁(u,v) · conj(F₂(u,v))) / |F₁(u,v) · conj(F₂(u,v))|
逆变换后:
r(x,y) = δ(x - Δx, y - Δy)
嗯,就这么简单。你只需要找到 r(x,y) 的最大值位置,就能得到平移量。
3.3 算法实现步骤
我习惯把流程拆成 6 步,每一步都有坑要留意:
- 预处理:将输入图像转为灰度,并应用窗函数(如汉宁窗)抑制边缘效应。这一步不做,频域里会出现高频泄漏。
- FFT 变换:对两帧图像分别做快速傅里叶变换。建议使用浮点精度,避免量化误差。
- 计算互功率谱:按公式计算归一化互功率谱。注意分母加一个小常数防止除零。
- 逆 FFT:对互功率谱做逆变换,得到相关面。
- 峰值检测:找到相关面的最大值坐标。如果峰值不够突出(低于阈值),说明运动模型可能不适用。
- 亚像素细化:对峰值邻域做二次曲面拟合,获得亚像素精度的位移。
3.4 代码示例:OpenCV 实现
下面是我常用的一个实现片段。注意,OpenCV 自带的 phaseCorrelate 函数已经封装好了,但了解底层实现还是有必要的:
import cv2
import numpy as np
def phase_correlation(img1, img2):
# 1. 灰度转换
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# 2. 应用汉宁窗
h, w = gray1.shape
hanning = np.outer(np.hanning(h), np.hanning(w))
win1 = gray1 * hanning
win2 = gray2 * hanning
# 3. FFT
f1 = np.fft.fft2(win1)
f2 = np.fft.fft2(win2)
# 4. 互功率谱
cross = f1 * np.conj(f2)
eps = 1e-10
norm_cross = cross / (np.abs(cross) + eps)
# 5. 逆FFT
result = np.fft.ifft2(norm_cross)
result = np.abs(result)
# 6. 峰值检测
max_loc = np.unravel_index(np.argmax(result), result.shape)
# 7. 亚像素细化(抛物面拟合)
y, x = max_loc
if 1 < y < h-1 and 1 < x < w-1:
dx = (result[y, x+1] - result[y, x-1]) / (2 * result[y, x])
dy = (result[y+1, x] - result[y-1, x]) / (2 * result[y, x])
else:
dx, dy = 0, 0
# 8. 处理中心偏移
shift_x = x - w//2 + dx
shift_y = y - h//2 + dy
return shift_x, shift_y
3.5 相位相关的局限性
没有银弹。相位相关虽然强大,但也有它的软肋:
| 局限 | 原因 | 应对策略 |
|---|---|---|
| 仅支持平移模型 | 相位相关假设纯平移,对旋转、缩放不敏感 | 结合对数极坐标变换处理旋转缩放 |
| 对周期性纹理敏感 | 周期性图案会产生多个峰值 | 增加峰值对比度阈值,或结合空间域验证 |
| 图像内容过少时失效 | 平坦区域缺乏高频信息 | 检测图像梯度能量,低于阈值时改用其他方法 |
| 大位移时精度下降 | 位移超过图像尺寸的 1/4 时,相关面变模糊 | 采用图像金字塔,由粗到细逐步估计 |
我曾经在一个夜景 HDR 项目里吃过亏——画面大部分是黑色天空,只有零星灯光。相位相关直接给出了一个离谱的位移。后来我加了一步预处理:先计算图像的梯度图,再用梯度图做相位相关,效果好了很多。
3.6 知识体系图
下面这张图总结了全局运动估计中相位相关的完整知识脉络:
3.7 工程实践建议
最后,分享几个我在实际项目中积累的经验:
- 先做质量检查:计算相关面的峰值与次峰值之比,如果比值小于 1.5,说明匹配不可靠,建议跳过这一帧。
- 多帧一致性校验:在 HDR 序列中,相邻帧之间的位移应该是平滑变化的。如果某帧的位移突然跳变,大概率是误匹配。
- 结合空间域验证:用相位相关得到初值后,可以在小范围内用 NCC(归一化互相关)做精匹配,两者互补效果更好。
相位相关不是万能的,但在 HDR 全局运动估计这个场景下,它确实是最优雅、最鲁棒的方案之一。掌握了它,你就解决了 HDR 合成中 80% 的对齐问题。