### Lucas-Kanade 光流算法原理
Lucas-Kanade 光流算法是一种经典的计算机视觉技术,主要用于估计图像序列中的运动。该算法的核心思想是利用时间连续性和空间局部性的假设,在一个小区域内近似认为所有像素具有相同的运动矢量[^3]。
#### 数学模型
Lucas-Kanade 方法通过最小化邻域内的像素误差来估计光流。其目标函数可以表示为:
\[
E(u,v) = \sum_{(x,y)} [I(x+u, y+v, t+1) - I(x, y, t)]^2 W(x,y)
\]
其中 \(I(x, y, t)\) 表示当前帧的灰度值,\(I(x+u, y+v, t+1)\) 是下一帧对应位置的灰度值,而 \(W(x,y)\) 则是一个加权窗口函数,通常采用高斯权重分布。
为了简化求解过程,引入了泰勒展开近似和亮度恒定假设(即同一物体在相邻两帧间的亮度不变),从而得到线性方程组的形式:
\[
\begin{bmatrix}
\nabla I_x \\
\nabla I_y
\end{bmatrix}^\top
\cdot
\begin{bmatrix}
u \\ v
\end{bmatrix}
= -\nabla I_t
\]
最终可以通过矩阵运算解决上述方程组,获得光流矢量 \((u, v)\)[^5]。
---
### OpenCV 中的实现方法
OpenCV 提供了一个高效的接口 `cv2.calcOpticalFlowPyrLK()` 来计算稀疏光流。以下是其实现的主要步骤:
1. **提取特征点**
首先需要从初始帧中提取一组稳定的特征点(如角点)。这一步可通过 Harris 角点检测器或 Shi-Tomasi 特征检测器完成。
2. **构建金字塔结构**
由于光流算法可能无法处理大位移的情况,因此常使用图像金字塔降低分辨率,逐步逼近真实运动矢量[^4]。
3. **调用核心 API**
调用 `cv2.calcOpticalFlowPyrLK(prevImg, nextImg, prevPts)` 函数即可获取前后两帧之间的匹配点及其对应的光流矢量。
下面是一段完整的 Python 示例代码展示如何应用此功能:
```python
import numpy as np
import cv2
# 初始化视频捕获设备
cap = cv2.VideoCapture('input_video.mp4')
# 创建参数用于 ShiTomasi 角点检测
feature_params = dict(maxCorners=100,
qualityLevel=0.3,
minDistance=7,
blockSize=7)
# 设置 LK 光流参数
lk_params = dict(winSize=(15, 15),
maxLevel=2,
criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
# 获取第一帧并查找角点
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
mask = np.zeros_like(old_frame)
while True:
ret, frame = cap.read()
if not ret:
break
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 计算光流
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# 选择好的点
good_new = p1[st == 1]
good_old = p0[st == 1]
# 绘制轨迹
for i, (new, old) in enumerate(zip(good_new, good_old)):
a, b = new.ravel().astype(int)
c, d = old.ravel().astype(int)
mask = cv2.line(mask, (a,b), (c,d), (0, 255, 0), 2)
frame = cv2.circle(frame, (a,b), 5, (0, 0, 255), -1)
img = cv2.add(frame, mask)
cv2.imshow('frame', img)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
# 更新前一帧和前一点集
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1, 1, 2)
cv2.destroyAllWindows()
cap.release()
```
---
### 总结
Lucas-Kanade 光流算法以其高效性和准确性成为许多实时应用场景的基础工具之一。尽管它是稀疏光流的一种形式,但在实际开发过程中往往能够满足大多数需求。如果需要更精确的结果,则可以考虑结合其他密集型光流算法(如 Horn-Schunck 法)或者现代深度学习框架下的端到端解决方案。
---