Like Share Discussion Bookmark Smile

J.J. Huang   2026-02-23   Python OpenCV 06.視訊與互動篇   瀏覽次數:次   DMCA.com Protection Status

Python | OpenCV 光流分析 (Optical Flow)

📚 前言

在前一篇我們學會了 即時圖片中的物件追蹤
這一篇要介紹 光流分析 (Optical Flow),它是一種用來估計圖片中物件移動的方法。
光流分析常用於運動偵測、物件追蹤、影片穩定化等場景。

🎨 範例影片

這裡我們使用 Pexels 提供的免費影片素材:Tennis Video
下載後將檔名改為 tennis.mp4,在程式碼範例中使用。這段影片中有明顯的移動物件,非常適合用來測試追蹤演算法。

🔎 原理說明

  • 光流 (Optical Flow):描述圖片中像素隨時間的移動。
  • 兩種常用方法
    1. Lucas-Kanade Optical Flow:追蹤特徵點的移動,適合少量特徵點。
    2. Dense Optical Flow (Farneback):計算整張圖片的光流,適合分析整體運動。

🧠 函式與參數說明

📌 cv2.goodFeaturesToTrack()

用途:偵測圖片中的角點 (特徵點)。

1
p0 = cv2.goodFeaturesToTrack(old_gray, maxCorners=100, qualityLevel=0.3, minDistance=7)
  • maxCorners:最多偵測多少角點。
  • qualityLevel:角點品質閾值。
  • minDistance:角點之間的最小距離。

📌 cv2.calcOpticalFlowPyrLK()

用途:計算 Lucas-Kanade 光流,追蹤特徵點移動。

1
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None)
  • old_gray:前一幀圖片 (灰階)。
  • frame_gray:當前圖片 (灰階)。
  • p0:前一幀的特徵點。
  • p1:計算後的新位置。
  • st:追蹤狀態 (1=成功, 0=失敗)。
  • err:誤差值。

📌 cv2.calcOpticalFlowFarneback()

用途:計算 Dense Optical Flow,分析整張圖片的運動。

1
2
flow = cv2.calcOpticalFlowFarneback(prvs, next, None,
0.5, 3, 15, 3, 5, 1.2, 0)
  • prvs:前一幀圖片 (灰階)。
  • next:當前圖片 (灰階)。
  • 其他參數:控制金字塔層數、窗口大小、迭代次數等。

📌 cv2.cartToPolar()

用途:將光流的水平與垂直分量轉換為角度與大小。

1
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
  • mag:光流大小 (速度)。
  • ang:光流方向 (角度)。

💻 範例程式 — Lucas-Kanade Optical Flow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import cv2
import numpy as np

# 讀取影片
cap = cv2.VideoCapture("tennis.mp4")

# 讀取第一幀並轉灰階
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

# 偵測角點 (特徵點)
p0 = cv2.goodFeaturesToTrack(old_gray, maxCorners=100, qualityLevel=0.3, minDistance=7)

# 建立顏色用於繪製軌跡
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)

# 選取成功追蹤的點
good_new = p1[st == 1]
good_old = p0[st == 1]

# 繪製軌跡
for i, (new, old) in enumerate(zip(good_new, good_old)):
x_new, y_new = new.ravel()
x_old, y_old = old.ravel()
mask = cv2.line(mask, (int(x_new), int(y_new)), (int(x_old), int(y_old)), (0, 255, 0), 2)
frame = cv2.circle(frame, (int(x_new), int(y_new)), 5, (0, 0, 255), -1)

img = cv2.add(frame, mask)
cv2.imshow("Lucas-Kanade Optical Flow", img)

if cv2.waitKey(30) & 0xFF == ord('q'):
break

old_gray = frame_gray.copy()
p0 = good_new.reshape(-1, 1, 2)

cap.release()
cv2.destroyAllWindows()


圖:Lucas-Kanade 光流分析,顯示特徵點的移動軌跡

💻 範例程式 — Dense Optical Flow (Farneback)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import cv2
import numpy as np

cap = cv2.VideoCapture("tennis.mp4")

ret, frame1 = cap.read()
prvs = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)

hsv = np.zeros_like(frame1)
hsv[..., 1] = 255 # 設定飽和度

while True:
ret, frame2 = cap.read()
if not ret:
break

next = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)

# 計算光流
flow = cv2.calcOpticalFlowFarneback(prvs, next, None,
0.5, 3, 15, 3, 5, 1.2, 0)

# 將光流轉換為顏色顯示
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
hsv[..., 0] = ang * 180 / np.pi / 2
hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

cv2.imshow("Dense Optical Flow", bgr)

if cv2.waitKey(30) & 0xFF == ord('q'):
break

prvs = next

cap.release()
cv2.destroyAllWindows()


圖:Dense Optical Flow,顯示整張圖片的運動方向與速度

⚠️ 注意事項

  • 光流分析需要 連續影格,若影片斷裂或幀率過低,效果會不佳。
  • Lucas-Kanade 適合少量特徵點,Dense Optical Flow 適合整體運動分析。
  • 光流結果容易受光線變化、遮擋影響。
  • 建議在 灰階圖片上計算光流,以減少計算量。

📊 應用場景

  • 運動分析:分析球員或球的移動軌跡。
  • 監控系統:偵測移動物體。
  • 影片穩定化:估計相機晃動並修正。
  • 自動駕駛:分析道路上物件的移動。

🎯 結語

本篇我們學會了如何使用 OpenCV 光流分析 (Optical Flow),並透過 Lucas-Kanade 與 Dense Optical Flow 方法來追蹤圖片中物件的移動。
這些技術在運動分析、監控與自動駕駛中非常常見,後續可以結合物件偵測與追蹤,打造更完整的系統。

📖 如在學習過程中遇到疑問,或是想了解更多相關主題,建議回顧一下 Python | OpenCV 系列導讀,掌握完整的章節目錄,方便快速找到你需要的內容。

註:以上參考了
OpenCV Tutorials
OpenCV-Python Tutorials
Pexels — 免費影片素材