【進階OpenCV】 光流估計--描繪運動物體軌跡

目錄

前言

一、光流估計的核心原理

二、光流估計的計算流程

1. 特征提取:找到 “好跟蹤” 的點

2. 光流計算:匹配幀間特征點

三、完整實現步驟(附代碼)

1. 環境準備

2. 步驟 1:處理視頻第一幀

3. 步驟 2:提取第一幀的特征點(角點)

4. 步驟 3:創建軌跡掩膜與顏色

5. 步驟 4:配置光流計算參數

6. 步驟 5:主循環 —— 跟蹤特征點并繪制軌跡

7. 步驟 6:釋放資源

五、總結


前言


在計算機視覺領域,運動目標跟蹤是核心任務之一,而光流估計則是實現該任務的經典技術。它通過捕捉連續圖像幀間像素的運動向量,讓我們直觀地 “看到” 物體的運動軌跡。本文將從原理到代碼,手把手教你用 OpenCV 實現基于 Lucas-Kanade 金字塔光流的運動軌跡繪制,適合有基礎 OpenCV 知識的開發者進階學習。

一、光流估計的核心原理

光流估計并非憑空計算,其準確性依賴三個關鍵假設,這也是所有傳統光流算法的理論基石:

1.亮度恒定假設
同一物體的像素亮度在連續幀間保持不變。這意味著,物體運動是幀間像素變化的唯一原因,排除了光照突變、物體反光等干擾因素(實際應用中需盡量控制光照環境)。
2. 小運動假設
物體在相鄰兩幀間的位移極小,不會出現 “瞬移” 情況。只有滿足這一假設,才能通過像素灰度對位置的偏導數,近似計算像素的運動速度。
3. 空間一致性假設
場景中相鄰的像素點,投影到圖像平面后仍保持相鄰關系,且這些相鄰點屬于同一物體,運動方向和速度一致。這一假設避免了孤立像素的異常運動對整體軌跡的干擾。

二、光流估計的計算流程


要實現運動軌跡繪制,需先明確光流估計的核心步驟 ——特征提取與光流計算,二者相輔相成:

1. 特征提取:找到 “好跟蹤” 的點

光流計算無需跟蹤所有像素,只需聚焦于易識別、易匹配的特征點(如角點、邊緣)。這類點的灰度梯度大,在幀間變化中具有唯一性,跟蹤穩定性更高。
OpenCV 中常用cv2.goodFeaturesToTrack()函數提取角點,該函數能過濾低質量點、避免點過于密集,為后續光流計算提供可靠輸入。

2. 光流計算:匹配幀間特征點

拿到特征點后,需計算其在相鄰幀間的運動向量。常用算法包括:

  • Lucas-Kanade 算法:稀疏光流算法,僅計算特征點的光流,速度快、適合實時場景;
  • Horn-Schunck 算法:稠密光流算法,計算所有像素的光流,精度高但速度慢;
  • 金字塔 Lucas-Kanade 算法:本文使用的優化版本,通過構建圖像金字塔,解決了 “大位移” 場景下的跟蹤失效問題,兼顧速度與精度(對應 OpenCV 函數cv2.calcOpticalFlowPyrLK())。

三、完整實現步驟(附代碼)


結合上述原理,運動軌跡繪制的整體邏輯為:讀取視頻→提取首幀特征點→創建軌跡掩膜→循環跟蹤特征點并繪制軌跡→顯示結果。下面分步驟拆解實現細節。


1. 環境準備
?

首先確保安裝 OpenCV 和 NumPy(若未安裝,執行以下命令):

pip install opencv-python numpy

2. 步驟 1:處理視頻第一幀

視頻跟蹤的起點是第一幀,需先讀取第一幀并轉換為灰度圖(光流計算僅需單通道,減少計算量):

import cv2
import numpy as np# 1. 讀取視頻(替換為你的視頻路徑,支持avi/mp4格式)
cap = cv2.VideoCapture("test.avi")  # 示例視頻路徑,需根據實際修改# 2. 讀取第一幀,判斷是否讀取成功
ret, old_frame = cap.read()
if not ret:print("視頻讀取失敗!請檢查文件路徑或視頻格式。")cap.release()  # 釋放視頻資源exit()# 3. 將第一幀轉換為灰度圖(光流計算需灰度圖輸入)
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)

3. 步驟 2:提取第一幀的特征點(角點)


使用cv2.goodFeaturesToTrack()提取高質量角點,參數需根據實際場景調整:

# 定義特征點檢測參數
feature_params = dict(maxCorners=100,    # 最多提取100個角點(避免軌跡過多導致畫面雜亂)qualityLevel=0.3,  # 角點質量閾值:僅保留質量≥最強角點質量×0.3的點minDistance=7      # 角點間最小歐氏距離:避免角點過于密集
)# 提取第一幀的角點(mask=None表示全圖檢測,無區域限制)
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
# p0形狀:(-1, 1, 2),即(角點數量,1,(x,y)坐標),例如(50,1,2)表示50個角點

4. 步驟 3:創建軌跡掩膜與顏色


為了不破壞原始視頻幀,我們創建一個全零掩膜(與視頻幀尺寸相同),專門用于繪制軌跡;同時為每個特征點分配隨機顏色,便于區分不同軌跡:

# 創建與視頻幀尺寸、通道數相同的全零掩膜(初始為黑色,后續繪制彩色軌跡)
mask = np.zeros_like(old_frame)# 為每個特征點生成隨機RGB顏色(100個點×3通道,取值0-255)
color = np.random.randint(0, 255, (100, 3))  # 顏色數量與maxCorners一致

5. 步驟 4:配置光流計算參數

使用cv2.calcOpticalFlowPyrLK()前,需定義其參數,控制跟蹤精度與速度:

# Lucas-Kanade金字塔光流參數
lk_params = dict(winSize=(15, 15),  # 搜索窗口大小:窗口越大,跟蹤范圍越廣,但速度越慢maxLevel=2,        # 金字塔最大層級:2表示使用原始圖+2層下采樣圖,解決大位移問題criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)# 迭代終止條件:迭代10次或誤差小于0.03時停止,平衡精度與速度
)

6. 步驟 5:主循環 —— 跟蹤特征點并繪制軌跡

這是核心環節:循環讀取每一幀,計算光流、篩選有效特征點、繪制軌跡,并更新 “上一幀” 數據用于下次計算。

while True:# 1. 讀取當前幀ret, frame = cap.read()if not ret:  # 若讀取失敗(如視頻結束),退出循環break# 2. 將當前幀轉換為灰度圖frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 3. 計算光流:匹配上一幀特征點(p0)在當前幀的位置# p1:當前幀特征點坐標;st:跟蹤狀態(1=成功,0=失敗);err:跟蹤誤差p1, st, err = cv2.calcOpticalFlowPyrLK(prevImg=old_gray,    # 上一幀灰度圖nextImg=frame_gray,  # 當前幀灰度圖prevPts=p0,          # 上一幀特征點nextPts=None,        # 輸出當前幀特征點(設為None自動分配)**lk_params          # 光流參數)# 4. 篩選跟蹤成功的特征點(僅保留st=1的點)good_new = p1[st == 1]  # 當前幀有效特征點good_old = p0[st == 1]  # 上一幀對應有效特征點# 5. 繪制軌跡:在掩膜上連接“上一幀點”與“當前幀點”for i, (new, old) in enumerate(zip(good_new, good_old)):# 提取坐標并轉換為整數(像素坐標需為整數)x_new, y_new = new.ravel()  # ravel()將數組展平為一維x_old, y_old = old.ravel()# 轉換為整數(避免繪圖時因浮點數報錯)x_new, y_new, x_old, y_old = map(int, [x_new, y_new, x_old, y_old])# 在掩膜上繪制線段:連接上一幀點與當前幀點mask = cv2.line(img=mask,          # 繪制目標:掩膜pt1=(x_new, y_new),# 當前幀點pt2=(x_old, y_old),# 上一幀點color=color[i].tolist(),  # 軌跡顏色(與特征點對應)thickness=2        # 線段粗細)# 6. 生成最終圖像:將掩膜(軌跡)疊加到原始幀上result = cv2.add(frame, mask)  # 圖像疊加,軌跡覆蓋在視頻上# 7. 顯示結果cv2.imshow("Motion Trajectory", result)  # 顯示帶軌跡的視頻cv2.imshow("Mask Only", mask)            # 單獨顯示軌跡掩膜(可選)# 8. 按鍵控制:按下Esc鍵(ASCII碼27)退出循環k = cv2.waitKey(30) & 0xFF  # 等待30ms(控制視頻播放速度)if k == 27:break# 9. 更新“上一幀”數據:為下一循環做準備old_gray = frame_gray.copy()  # 上一幀灰度圖更新為當前幀p0 = good_new.reshape(-1, 1, 2)  # 上一幀特征點更新為當前幀有效點(調整形狀)

7. 步驟 6:釋放資源

循環結束后,需釋放視頻捕獲對象與銷毀 OpenCV 窗口,避免內存泄漏:

# 釋放視頻資源
cap.release()
# 銷毀所有OpenCV窗口
cv2.destroyAllWindows()

運行結果如下:為一個視頻檢測人們的運動軌跡

五、總結


本文通過 OpenCV 實現了基于 Lucas-Kanade 金字塔光流的運動軌跡繪制,核心邏輯是 “提取特征點→跟蹤特征點→繪制幀間連線”。該方法兼顧實時性與精度,適用于攝像頭監控、車輛跟蹤、機器人視覺等場景。
掌握光流估計后,可進一步探索更復雜的應用,如結合目標檢測(如 YOLO)實現特定物體的軌跡跟蹤,或使用稠密光流算法(如cv2.calcOpticalFlowFarneback())獲取全像素運動信息。
希望本文能幫助你理解光流估計的實踐邏輯,動手嘗試調整參數,感受不同場景下的軌跡繪制效果吧!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/100498.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/100498.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/100498.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

InnoDB ACID實現:數據庫可靠性的核心秘密

這段內容出自 MySQL 官方文檔第 17.2 節《InnoDB 與 ACID 模型》,深入解釋了 InnoDB 是如何實現 ACID 特性 的。ACID 是數據庫系統中最核心的設計原則,確保數據在各種異常情況下依然可靠、一致、安全。 我們來逐部分解析并通俗理解:&#x1f…

CoolUtils Total Excel Converter:全能的 Excel 文件轉換工具

一、軟件簡介 CoolUtils Total Excel Converter 是一款功能強大的 Excel 文件轉換工具,專為高效處理和轉換 Excel 文件而設計。它支持將 Excel 文件(包括 XLS 和 XLSX 格式)轉換為多種常見的文件格式,如 PDF、CSV、HTML、TXT 等&…

告別靜態圖譜!TextSSL如何用「稀疏學習」實現更智能的文檔分類?

文章鏈接:https://mp.weixin.qq.com/s/danmd9lSQpmck4tVsM37bQ 今天分享一篇將圖神經網絡應用于文本分類的創新模型——TextSSL。在傳統的文檔理解中,模型往往難以同時捕捉文本的局部句法細節和全局語義關聯。針對這一挑戰,TextSSL提出了一種…

開源商城mall項目功能評估與優化建議

項目地址:https://github.com/macrozheng/mall 開源項目是大多數程序員用來練手的最好途徑,但是技術面和技術深度同樣重要。一個商城項目能夠稱之為商城不光有基礎的商品后臺管理、移動端、支付管理,要打造一個全鏈路的生態系統,…

我的頁面開發

我的頁面開發 后端data\me_page.js我的頁面靜態數據module.exports () > {return {superCard: {beanCount: 1555,tips: "下單得5倍吃貨豆,兌專享紅包",},cards: [{label: "常用功能",size: 30,items: [{iconUrl: "/imgs/me_page/coupang.png"…

Java Swagger2 能顯示頁面但看不到一個接口

反復檢查之后,發現問題出在的代碼如下: ApiModelProperty(value "材料鏈接地址", example "{ApiHost}/storage/test.pdf")private String url; 結論:example的值包括了 { 和 } ,導致網頁解析的JSON數據失敗…

2025年- H143-Lc344. 反轉字符串(字符串)--Java版

1.題目2.思路 方法一&#xff1a;比如有5個元素 s[0],s[1],s[2],s[3],s[4] 反轉之后對應 s[4],s[3],s[2],s[1],s[0] 所以s[0]s[4], s[1]s[3] s[i]s[n-1-i] 方法2:雙指針 left0,rights.length-1; 當left<right的時候&#xff0c;交換兩個元素的位置&#xff0c;左指針左移&am…

微服務高可用流程講解

如何理解從前端nginx到后端微服務高可用架構問題&#xff0c;下面從nginx、gateway、nacos、各個服務節點的角度講解下應該如何進行高可用&#xff0c;比如nginx是前端向后端進行的負載均衡&#xff0c;也相當于均衡地向各個gateway網關進行請求&#xff0c;再由gateway網關拉取…

留個檔,Unity,Animation控制相機,出現抖動的問題記錄

起因是項目用了一段高度自定義的過程復雜的相機Animation&#xff0c;來控制虛擬相機位移旋轉。 發現在不同的電腦上&#xff0c;出現了不同程度的抖動。 搜索過程中&#xff0c;發現關鍵詞&#xff1a;World Origin Rebasing。 Unity 世界坐標使用 float&#xff08;單精度浮點…

組合對沖策略(外匯版)

在復雜多變的外匯市場中&#xff0c;投資者常常面臨著匯率波動帶來的風險。為了降低這種風險&#xff0c;對沖策略成為了一種有效的風險管理工具。以下將詳細介紹三種組合對沖策略&#xff0c;它們分別是基于多貨幣正負相關對沖、區域性貨幣對沖以及全日元貨幣對沖的策略。①多…

GPT-5-Codex 正式發布:邁向真正的“自主編程”時代

在 Anthropic Claude 近期遭遇爭議的同時&#xff0c;OpenAI 推出了其編程領域的王牌產品——GPT-5-Codex。這并非簡單的模型升級&#xff0c;而是基于 GPT-5 專為“自主編程”&#xff08;Autonomous Programming&#xff09;場景深度優化的專用版本&#xff0c;標志著 AI 編程…

java面試:了解redis的集群么,怎么通過redis的集群來實現redis的高可用?

我們知道&#xff0c;為了幫助數據庫緩解高并發的壓力&#xff0c;我們會上reids緩存幫助數據庫分攤&#xff0c;雖說常見場景的并發量還不足以讓redis宕機&#xff0c;但假設出現了極高的并發場景&#xff0c;redis依舊是有宕機的可能的&#xff0c;畢竟單點部署的redis容易出…

氧氣科技亮相GDMS全球數字營銷峰會,分享AI搜索時代GEO新觀

2025年9月16日&#xff0c;全球數字營銷領域的年度盛會——GDMS&#xff08;Global Digital Marketing Summit&#xff09;在上海國家會展中心盛大舉行。作為品牌數字化轉型的風向標&#xff0c;本屆峰會匯聚來自全球的CEO、CMO、CDO及營銷領域高管&#xff0c;共同探討AI驅動下…

搭建Gin通用框架

Gin Web 開發腳手架技術文檔 項目概述 本項目是一個基于 Gin 框架的 Go Web 開發腳手架模板&#xff0c;提供了完整的項目結構、配置管理、日志記錄、MySQL 和 Redis 數據庫連接等常用功能集成。 項目結構 gindemo/ ├── gindemo.exe # 編譯后的可執行文件 ├── g…

windows 平臺下 ffmpeg 硬件編解碼環境查看

環境&#xff1a; 1&#xff0c;nvidia 顯卡 2&#xff0c;驅動安裝 powershell 下 執行如下命令&#xff0c;出現GPU信息 說明驅動安裝正常。 nvidia-smi 3&#xff0c;安裝支持 NVENC 的 FFmpeg &#xff08;1&#xff09;Windows 下 編譯 FFmpeg 需要 CUDA Toolkit &am…

08_多層感知機

1. 單層感知機 1.1 感知機① 線性回歸輸出的是一個實數&#xff0c;感知機輸出的是一個離散的類。1.2 訓練感知機 ① 如果分類正確的話y<w,x>為正數&#xff0c;負號后變為一個負數&#xff0c;max后輸出為0&#xff0c;則梯度不進行更新。 ② 如果分類錯了&#xff0c;y…

安卓實現miniLzo壓縮算法

LZO官方源碼 http://www.oberhumer.com/opensource/lzo 找到miniLZO點擊Dowload miniLZO下載源碼 http://www.oberhumer.com/opensource/lzo/download/minilzo-2.10.tar.gz demo源碼(包含安卓) https://github.com/xzw421771880/MiniLzo_Mobile.git 1.代碼部分 1.1.測試…

如何在ubuntu下用pip安裝aider,解決各種報錯問題

aider中文文檔網站上給出的安裝說明比較簡單&#xff1a; https://aider.doczh.com/docs/install.html 但是在一個干凈的ubuntu環境中按文檔中的命令安裝時&#xff0c;會報錯&#xff0c;經過一番嘗試之后&#xff0c;解決了報錯問題&#xff0c;成功完成了安裝。 成功安裝執…

Kotlin flow詳解

流式數據處理基礎 Kotlin Flow 是基于協程的流式數據處理 API&#xff0c;要深入理解 Flow&#xff0c;首先需要明確流的概念及其處理方式。 流(Stream)如同水流&#xff0c;是一種連續不斷的數據序列&#xff0c;在編程中具有以下核心特征&#xff1a; 數據按順序產生和消費支…

DeepSeek V3 深度解析:MoE、MLA 與 GRPO 的架構革新

簡介 DeepSeek&#xff08;深度求索&#xff09;是一家源自中國的人工智能公司&#xff0c;成立于2023年&#xff0c;總部位于中國杭州。前身是國內量化投資巨頭幻方量化的子公司。公司專注于開發低成本、高性能的AI模型&#xff0c;致力于通過技術創新推動人工智能技術的普惠…