Gunnar-Farneback算法原理 & Farneback光流法在UCSD異常數據集上的Demo

Gunnar-Farneback算法

論文:Two-Frame Motion Estimation Based on Polynomial Expansion

會議:13th Scandinavian Conference on Image Analysis (SCIA 2003)

作者:Gunnar Farnebäck(Computer Vision Laboratory, Link¨oping University, SE-581 83 Link¨oping, Sweden)

備註:[email protected] http://www.isy.liu.se/cvl/

一、多項式展開

多項式展開的想法是把每個像素點的鄰域都用多項式來表示:

f(x)\sim x^{T}Ax + b^{T}x + c(1)

其中A是對稱矩陣,b是向量,c是常量。係數是根據鄰域內信號值的加權最小二乘法估計出來的。權重由兩個組成部分,稱爲確定性和適用性。確定性與鄰近區域的信號值耦合,而適用性則根據點在鄰域中的位置確定鄰域中點的相對權重。

二、位移估計

由於每個鄰域都可以用一個多項式來逼近,所以首先分析一個多項式經過平移後會發生什麼變化。考慮以下二次多項式:

f_{1}(x) = x^{T}A_{1}x + b_{1}^{T}x + c_{1}     (2)

整體位移d個單位後得到信號f_{2}

f_{2} = f_{1}(x - d)^{T}A_{1}(x - d) + b_{1}^{T}(x - d) + c_{1} = x^{T}A_{2}x + b_{2}^{T} + c_{2}     (3)

設二次多項式等式如下:

A_{2} = A_{1}     (4)

b_{2} = b_{1} - 2A_{1}d     (5)

c_{2} = d^{T}A_{1}d - b_{1}^{T}d + c_{1}     (6)

A_{1}是非奇異矩陣時,可以解出d

2A_{1}d = -(b_{2} - b_{1})     (7)

d = -\frac{1}{2}A_{1}^{-1}(b_{2} - b_{1})     (8)

實際情況中,不存在整個信號表示爲一個多項式以及這兩個圖像信號的全局平移,但上述公式(7)仍然適用於實際信號。

這裏用局部多項式逼近方程(2)中的全局多項式。然後對兩個圖像做多項式展開,第一個圖像對應係數爲A_1(x)b_{1}(x)c_{1}(x),第二個圖像同理。理想情況下,根據方程(4)應該有A_{2} = A_{1},但實際上應該求解近似值:

A(x) = \frac{A_1(x) + A_{2}(x)}{2}     (9)

\Delta b(x) = -\frac{1}{2}(b_{2}(x) - b_{1}(x))     (10)

然後用d(x)代替前面的全局變量d

A(x)d(x) = \Delta b(x)     (11)

下面開始解決鄰域估計的問題。根據方程(11)可以對每個像素點進行運算,但考慮到龐大的運算量這樣做顯然不太現實。假設位移過程是緩慢進行的,那麼應當儘可能的縮小x的鄰域I的搜索範圍並找到符合方程(11)的d(x)

$\sum_{\Delta x\epsilon I}^{.} w(\Delta x)\left \| A(x + \Delta x)d(x) - \Delta b(x + \Delta x) \right\|^{2}     (12)

這裏設w(\Delta x)爲像素點對應的權重函數,根據最小二乘法可得:

d(x) = (\sum wA^{T}A)^{-1}\sum wA^{T}\Delta b     (13)

三、參數化位移場

爲了提高算法魯棒性,對於一些運動模式應該建立參數化模型。下面來構建帶有8個參數的2D運動模型:

d_{x}(x, y) = a_{1} + a_{2}x + a_{3}y + a_{7}x^{2} + a_{8}xy     (15)

d_{y}(x, y) = a_{4} + a_{5}x + a_{6}y + a_{7}x^{2} + a_{8}xy

上式可以表示成:

d = S_{P}      (16)

S = \binom{1,x,y,0,0,0,x^{2},xy}{0,0,0,1,x,y,xy,y^{2}}     (17)

P = (a_{1},a_{2},a_{3},a_{4},a_{5},a_{6},a_{7},a_{8})^{T}      (18)

帶入到方程(12)中,即可得到加權最小二乘問題:

\sum_{i}^{.}w_{i}\left \| A_{i}S_{i}P - \Delta b_{i} \right \|^{2}     (19)

現在用i去索引像素點鄰域中的座標,用最小二乘法求解可以得出:

P = (\sum_{i}^{.}w_{i}S_{i}^{T}A_{i}^{T}A_{i}S_{i})^{-1}\sum_{i}^{.}w_{i}S_{i}^{T}A_{i}^{T}\Delta b_{i}     (20)

這裏可以像前面一樣分別計算出S_{i}^{T}A_{i}^{T}A_{i}S_{i}S_{i}^{T}A_{i}^{T}\Delta b_{i},然後用w做加權平均求出位移d(x)

四、利用先驗信息

目前爲止仍存在一個問題,就是兩個信號在相同座標下的局部多項式除了位移之外都是一致的。由於這裏的多項式展開是局部模型,所以會隨着在空間位移而發生變化,所以會引入(11)中的誤差,且這個誤差會隨着位移的增大而增大。所以這裏引入先驗位移信息,即比較第一個信號在x的多項展開式和第二個信號在x + \tilde{d}(x)的多項展開式,其中\tilde{d}(x)爲先驗位移四捨五入得出的整型值,這樣就只需要計算出真實值和基於先驗位移的預估值。

替代上面的(9)和(10)爲:

A(x) = \frac{A_{1}(x) + A_{2}(\tilde{x})}{2}     (21)

\Delta b(x) = -\frac{1}{2}(b_{2}(\tilde{x}) - b_{1}(x)) + A(x)\tilde{d(x)}     (22)

其中,

\tilde{x} = x + \tilde{d}(x)     (23)

五、迭代與多尺度位移估計

在算法中採用先驗位移場的優勢在於可以閉合循環並迭代。具備一個好的先驗估計意味着相對位移更小,這反過來又可以提高位移估計的精度。這裏考慮兩種不同的方法,迭代位移估計和多尺度位移估計。

在這兩種方法中,迭代估計一步的位移,作爲下一步的先驗位移。第一步中的先驗位移場通常被初始化爲零,除非有明確的信息。在第一種方法中,在所有迭代中使用相同的多項式展開係數,並且只需要計算一次。這存在一個問題是,如果第一次迭代位移(相對於先驗位移)過大,輸出的位移就不能期望得到改善,迭代也就失去了意義。通過在較粗的尺度上進行分析,可以減少位移過大的問題。這意味着我們對多項式展開具有高適用性。其結果是,該估計算法可以處理較大的位移,但同時精度卻降低了。

多尺度位移估計方法,從一個較粗的尺度開始,得到一個粗略但合理的位移估計,接着通過逐級細化尺度獲得越來越精確的估計。這樣的缺點是需要重新計算每個尺度的多項式展開係數,但是可以通過在尺度變換之間進行二次採樣來降低此成本。

 

Farneback光流法在UCSD異常數據集上的Demo

實驗環境:Win10 | Python 3.7.3 | OpenCV 4.1.0

實驗代碼:

def draw_flow(im, flow, step=16):
    # 在間隔分開的像素採樣點處繪製光流
    h, w = im.shape[:2]
    y, x = mgrid[step/2:h:step, step/2:w:step].reshape(2, -1).astype(int)
    fx, fy = flow[y, x].T
    # 創建線的終點
    lines = vstack([x, y, x+fx, y+fy]).T.reshape(-1, 2, 2)
    lines = int32(lines)
    # 創建圖像並繪製
    vis = cv2.cvtColor(im, cv2.COLOR_GRAY2BGR)
    for (x1, y1), (x2, y2) in lines:
      cv2.line(vis, (x1, y1), (x2, y2), (0, 255, 0), 1)
      cv2.circle(vis, (x1, y1), 1, (0, 255, 0), -1)
    return vis

# 省略N行代碼......

# 提取第一幀
first_rgbframe = cv2.imread(frame_path + frames[0], 1)
del frames[0]
prev_gray = cv2.cvtColor(first_rgbframe, cv2.COLOR_BGR2GRAY)

for frame_i in frames:
  rgbframe = cv2.imread(frame_path + frame_i, 1)
  gray = cv2.cvtColor(rgbframe, cv2.COLOR_BGR2GRAY)
  # 計算流
  flow = cv2.calcOpticalFlowFarneback(prev_gray, gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)
  prev_gray = gray

  drawImg = draw_flow(gray, flow)
  cv2.imwrite(frameFB_path + frame_i, drawImg)
  # 畫出流矢量
  cv2.imshow('Optical flow', drawImg)
  if cv2.waitKey(10) == 27:
     break
  time.sleep(0.1)

實驗結果:

UCSDped1\Test\Test014

UCSDped2\Test\Test005

上面分別是UCSD anomaly dataset中的兩個Test片段,可以看到人羣或者單車/車輛經過的地方,綠色點都會伴隨聯動。

 

附錄:

數據集鏈接:UCSD Anomaly Detection Dataset

OpenCV - calcOpticalFlowFarneback() 參數解釋:

prev:前一張8位單通道輸入圖像

next:後一張8位單通道輸入圖像

flow:計算得出的與輸入圖像大小一致且類型爲CV_32FC2的光流圖

pyr_scale:構建金字塔時圖像的縮放係數(<1);比如係數=0.5時是典型金字塔模型,沒下一個層級圖像爲上一級的一半大小

levels:金字塔的層數;層數爲1時表示沒有額外的層級直接輸入原圖

winsize:平均窗口大小;窗口越大對於圖像噪聲越不敏感,能捕獲到更多的快動作,但會產生更遺漏的動作場

iterations:每個金字塔層級中算法的迭代次數

poly_n:像素的鄰域大小,鄰域是爲了做多項式展開的;鄰域越大,表示圖像越光滑,算法魯棒性更強且運動場更模糊,標準參考值爲5或者7

poly_sigma:用於平滑用作多項式展開基礎的導數的高斯函數的標準差;poly_n=5時,可以設置poly_sigma爲1.1;poly_n=7時,可以設置poly_sigma=1.5

flags:可以設置爲以下兩個標誌之一

OPTFLOW_USE_INITIAL_FLOW:使用輸入的光流圖作爲初始光流估計值

OPTFLOW_FARNEBACK_GAUSSIAN:使用高斯winsize×winsize濾波器代替相同大小的盒式濾波器進行光流估計;通常,此選項以較低的速度提供比盒式濾波器更精確的z流;通常,高斯窗口的winsize應設置爲更大的值以達到相同的魯棒性級別。

OpenCV官方原文解釋:點擊跳轉到官方文檔

 

參考資料:

1. Gunnar Farnebäck. Two-Frame Motion Estimation Based on Polynomial Expansion[C]// 13th Scandinavian Conference on Image Analysis (SCIA 2003). Springer-Verlag, 2003.

2. OpenCV官方文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章