![]() |
OpenCV 4.12.0
開源計算機視覺
|
上一個教程: 均值漂移和 Camshift
下一個教程: 級聯分類器
在本章中,
光流是影像物件在連續兩幀之間由於物體或攝像機運動而產生的表觀運動模式。它是一個二維向量場,其中每個向量都是一個位移向量,顯示了點從第一幀到第二幀的移動。考慮下圖(圖片來源:維基百科光流文章)。
它顯示了一個球在5個連續幀中的運動。箭頭顯示了它的位移向量。光流在許多領域都有應用,例如
光流基於以下幾個假設:
考慮第一幀中的畫素 \(I(x,y,t)\)(注意,這裡添加了一個新維度:時間。之前我們只處理影像,所以不需要時間)。它在 \(dt\) 時間後的下一幀中移動了距離 \((dx,dy)\)。因此,由於這些畫素是相同的且強度不變,我們可以說,
\[I(x,y,t) = I(x+dx, y+dy, t+dt)\]
然後對右側進行泰勒級數近似,去掉相同項併除以 \(dt\),得到以下方程
\[f_x u + f_y v + f_t = 0 \;\]
其中
\[f_x = \frac{\partial f}{\partial x} \; ; \; f_y = \frac{\partial f}{\partial y}\]
\[u = \frac{dx}{dt} \; ; \; v = \frac{dy}{dt}\]
上述方程稱為光流方程。在其中,我們可以找到 \(f_x\) 和 \(f_y\),它們是影像梯度。類似地,\(f_t\) 是沿時間的梯度。但 \((u,v)\) 是未知量。我們無法用兩個未知變數求解這個方程。因此,提供了幾種方法來解決這個問題,其中之一就是 Lucas-Kanade 方法。
我們之前見過一個假設,即所有相鄰畫素將具有相似的運動。Lucas-Kanade 方法在點周圍取一個 3x3 的影像塊。因此,所有 9 個點都具有相同的運動。我們可以找到這 9 個點的 \((f_x, f_y, f_t)\)。所以現在我們的問題變成了求解一個包含兩個未知變數的 9 個方程組,這是一個超定系統。使用最小二乘擬合方法可以獲得更好的解決方案。下面是最終的解決方案,它是一個二方程兩未知量問題,求解即可得到答案。
\[\begin{bmatrix} u \\ v \end{bmatrix} = \begin{bmatrix} \sum_{i}{f_{x_i}}^2 & \sum_{i}{f_{x_i} f_{y_i} } \\ \sum_{i}{f_{x_i} f_{y_i}} & \sum_{i}{f_{y_i}}^2 \end{bmatrix}^{-1} \begin{bmatrix} - \sum_{i}{f_{x_i} f_{t_i}} \\ - \sum_{i}{f_{y_i} f_{t_i}} \end{bmatrix}\]
(檢查逆矩陣與 Harris 角點檢測器的相似性。它表明角點是更好的跟蹤點。)
因此,從使用者角度來看,這個想法很簡單,我們提供一些點來跟蹤,然後接收這些點的光流向量。但仍然存在一些問題。到目前為止,我們只處理小範圍運動,因此當運動幅度較大時,它會失效。為了解決這個問題,我們使用金字塔。當我們沿著金字塔向上時,小範圍運動會被消除,大範圍運動會變成小範圍運動。因此,透過在那裡應用 Lucas-Kanade 方法,我們可以獲得光流以及尺度資訊。
OpenCV 將所有這些功能整合在一個函式中:cv.calcOpticalFlowPyrLK()。在這裡,我們建立一個簡單的應用程式來跟蹤影片中的某些點。為了確定這些點,我們使用 cv.goodFeaturesToTrack()。我們獲取第一幀,在其中檢測一些 Shi-Tomasi 角點,然後使用 Lucas-Kanade 光流迭代跟蹤這些點。對於函式 cv.calcOpticalFlowPyrLK(),我們傳入前一幀、前一個點和下一幀。它返回下一個點以及一些狀態數字,如果找到下一個點,則狀態值為 1,否則為 0。我們迭代地將這些下一個點作為前一個點在下一步中傳遞。請參閱下面的程式碼。
(此程式碼不檢查下一個關鍵點的正確性。因此,即使影像中的任何特徵點消失,光流也有可能找到看起來與其接近的下一個點。所以,實際上為了進行穩健的跟蹤,應該以特定的間隔檢測角點。OpenCV 示例中包含這樣一個示例,它每 5 幀查詢一次特徵點。它還會對獲得的光流點進行反向檢查,以僅選擇好的點。請檢視 samples/python/lk_track.py)。
檢視我們得到的結果
Lucas-Kanade 方法計算稀疏特徵集(在我們的示例中,是使用 Shi-Tomasi 演算法檢測到的角點)的光流。OpenCV 提供了另一種演算法來查詢稠密光流。它計算幀中所有點的光流。該演算法基於 Gunnar Farneback 在 2003 年的論文《基於多項式展開的雙幀運動估計》中解釋的 Gunnar Farneback 演算法。
以下示例展示瞭如何使用上述演算法查詢稠密光流。我們獲得一個包含光流向量 \((u,v)\) 的雙通道陣列。我們計算它們的幅度和方向。為了更好的視覺化,我們對結果進行了顏色編碼。方向對應於影像的色相值。幅度對應於亮度平面。請參閱下面的程式碼。
請參閱下面的結果