在 `scipy` 库中实现光流法的方法是使用 `scipy.ndimage.interpolation.shift` 函数进行图像位移,并利用最小二乘法拟合最优的位移矢量,来计算像素点的光流。具体步骤如下:
1. 首先,将两张图像转化为灰度图。
```python
import scipy as sp
import scipy.ndimage
im1 = sp.misc.imread('frame1.png', flatten=True).astype(float)
im2 = sp.misc.imread('frame2.png', flatten=True).astype(float)
```
2. 接下来,选择一个兴趣区域,用于确定所需计算的运动方向,比如可以选择图像的中心区域。然后将第一张图像中的兴趣区域作为参考块,建立搜索窗口区域,并在第二张图像中寻找良好的匹配参考块的搜索窗口块。在这两个块中,使用一个二维高斯函数建立一个权重矩阵。
```python
from scipy import signal
import numpy as np
window_size = 3
sigma = 1.5
kernel = np.zeros([window_size, window_size])
for i in range(window_size):
for j in range(window_size):
kernel[i,j] = np.exp(-((i-window_size/2)**2 + (j-window_size/2)**2)/(2*sigma**2))
kernel /= np.sum(kernel)
# Define delta for shift calculation
delta = np.array([0., 0.])
```
3. 接下来,迭代计算位移矢量,需要用到的函数是 `ndimage.interpolation.shift`,它将图像向某个方向移动,并按照高斯核的权重给每个像素赋一个值。
```python
bright_history = [np.mean(im1)]
shift_history = [delta]
# Iterate to calculate optical flow
n_iterations = 10
for _ in range(n_iterations):
im1_warped = sp.ndimage.interpolation.shift(im1, -delta, order=3)
# Define the window around the current position
x, y = np.clip(len(im2)//2 + delta, window_size//2, len(im2)-window_size//2).astype('int')
window = im2[x-window_size//2:x+window_size//2+1, y-window_size//2:y+window_size//2+1]
best_match, match_error = None, None
for ii in range(-1, 2):
for jj in range(-1, 2):
# Shift the search window accordingly
search_area = im1_warped[x-window_size//2+ii:x+window_size//2+1+ii, y-window_size//2+jj:y+window_size//2+1+jj]
match = signal.fftconvolve(window, search_area[::-1, ::-1] * kernel, mode='same')
if best_match is None or match.max() > best_match.max():
best_match = match
match_error = np.sum((window - search_area * kernel)**2)
# Define the delta according to best match
deltaX, deltaY = np.array(np.unravel_index(best_match.argmax(), best_match.shape)) - window_size//2
new_delta = delta + [deltaX, deltaY]
# Record the history
shift_history.append(new_delta)
bright_history.append(np.mean(im2))
delta = new_delta.copy()
```
在函数中,我们可以定义一个数组 `shift_history`,用于存储每一次迭代后对应的位移矢量。最后计算出的位移矢量即为光流向量,可以根据需要以可视化方式呈现。