OpenCv高階(十)——光流估計

文章目錄

  • 前言
  • 一、光流估計
  • 二、使用步驟
      • 1、導庫讀取視頻、隨機初始化顏色
      • 2、初始化光流跟蹤
      • 3、視頻幀處理循環
      • 4、光流計算與可視化
      • 5、循環控制與資源釋放
      • 完整代碼
  • 總結


前言

在計算機視覺領域,光流估計是捕捉圖像序列中像素點運動信息的核心技術。它描述了圖像中每個像素點在相鄰幀間的運動方向和速度,能從靜態圖像幀中解析出動態變化。
光流估計基于像素亮度不變和運動平滑兩個關鍵假設,通過數學建模解算出像素運動場,為視頻分析、目標跟蹤等任務提供基礎。OpenCV 集成了稀疏光流、稠密光流等計算方法,廣泛應用于無人機避障、電影特效等場景。
接下來,我們將深入解析光流估計原理、OpenCV 函數使用及實戰應用,探索這項技術的奧秘。

一、光流估計

光流估計是空間運動物體在觀測成像平面上的像素運動的“瞬時速度”,根據各個像素點的速度矢量特征,可以對圖像進行動態分析,例如目標跟蹤。

光流估計的前提:
(1)亮度恒定:同一點隨著時間的變化,其亮度不會發生改變。
(2)小運動:隨著時間的變化不會引起位置的劇烈變化,只有小運動情況下才能用前后幀之間單位位置變化引起的灰度變化去近似灰度對位置的偏導數。
(3)空間一致:一個場景上鄰近的點投影到圖像上也是鄰近點,且鄰近點速度一致。因為光流法基本方程約束只有一個,而要求x,y方向的速度,有兩個未知變量。所以需要連立n多個方程求解。

在這里插入圖片描述
?在這里插入圖片描述

二、使用步驟

1、導庫讀取視頻、隨機初始化顏色

# 導入數值計算庫和計算機視覺庫
import numpy as np
import cv2# 創建視頻捕獲對象,讀取測試視頻
cap = cv2.VideoCapture('../data/test.avi')# 生成100種隨機顏色,用于不同特征點的軌跡繪制
# 格式為(100,3)的數組,每個元素代表BGR顏色值
color = np.random.randint(0, 255, (100, 3))

2、初始化光流跟蹤

# 讀取視頻第一幀
ret, old_frame = cap.read()# 將第一幀轉換為灰度圖像(光流算法需要灰度輸入)
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)# 設置特征點檢測參數字典
feature_params = dict(maxCorners = 100,      # 檢測的最大特征點數量qualityLevel = 0.3,    # 特征點質量閾值(0-1,值越大質量越高)minDistance = 7        # 特征點之間的最小像素距離
)# 使用Shi-Tomasi算法檢測角點特征
# goodFeaturesToTrack:在灰度圖像中尋找適合跟蹤的強角點
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)# 創建與視頻幀同尺寸的全黑圖像,用于繪制運動軌跡
mask = np.zeros_like(old_frame)# 設置Lucas-Kanade光流算法參數
lk_params = dict(winSize = (15, 15),   # 每個金字塔層的搜索窗口大小maxLevel = 2          # 金字塔層數(0表示不使用金字塔)
)

3、視頻幀處理循環

while True:# 讀取新幀ret, frame = cap.read()# 視頻結束或讀取失敗時退出循環if not ret:break# 將當前幀轉換為灰度圖像frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

4、光流計算與可視化

     # 使用Lucas-Kanade金字塔光流法計算特征點運動# p1:新幀中特征點位置# st:狀態標記(1表示成功跟蹤,0表示丟失)# err:跟蹤誤差p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)# 篩選成功跟蹤的特征點good_new = p1[st == 1]  # 新位置有效的點good_old = p0[st == 1]  # 舊位置對應的有效點# 繪制特征點運動軌跡for i, (new, old) in enumerate(zip(good_new, good_old)):# 解包坐標并轉換為整數(光流坐標是浮點數)a, b = new.ravel().astype(int)c, d = old.ravel().astype(int)# 在mask圖像上繪制運動軌跡線# 參數:目標圖像,起點,終點,顏色,線寬mask = cv2.line(mask, (a, b), (c, d), color[i].tolist(), 2)# 顯示純軌跡圖像cv2.imshow("mask", mask)# 將軌跡疊加到原始幀上img = cv2.add(frame, mask)# 顯示疊加后的結果幀cv2.imshow('frame', img)

5、循環控制與資源釋放

    # 等待150ms并檢測ESC按鍵(ASCII 27)k = cv2.waitKey(150)if k == 27:break# 更新前一幀數據old_gray = frame_gray.copy()  # 更新灰度圖像# 更新特征點(只保留成功跟蹤的點)# reshape(-1,1,2)保持與原始p0相同的維度結構p0 = good_new.reshape(-1, 1, 2)# 釋放視頻資源并銷毀所有窗口
cv2.destroyAllWindows()
cap.release()

效果:

完整代碼

# 導入必要的庫
import numpy as np
import cv2# 創建視頻捕獲對象,讀取視頻文件
cap = cv2.VideoCapture('../data/test.avi')# 生成隨機顏色數組,用于繪制不同特征點的軌跡(100種顏色)
color = np.random.randint(0, 255, (100, 3))# 讀取視頻的第一幀
ret, old_frame = cap.read()# 將第一幀轉換為灰度圖像
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)# 設置特征點檢測參數
feature_params = dict(maxCorners=100,   # 最大特征點數量qualityLevel=0.3, # 特征點質量等級(0-1之間,越大質量越高)minDistance=7     # 特征點之間的最小歐氏距離
)# 使用Shi-Tomasi方法檢測初始特征點(角點檢測)
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)# 創建一個與視頻幀大小相同的全黑圖像,用于繪制軌跡
mask = np.zeros_like(old_frame)# Lucas-Kanade光流算法參數設置
lk_params = dict(winSize=(15, 15),  # 每個金字塔層的搜索窗口大小maxLevel=2         # 金字塔層數(0表示僅當前層)
)# 主循環處理視頻幀
while True:# 讀取新的一幀ret, frame = cap.read()if not ret:  # 如果讀取失敗(如視頻結束)則退出循環break# 將當前幀轉換為灰度圖像frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 計算光流(Lucas-Kanade方法)p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray,  # 前一幀的灰度圖像frame_gray, # 當前幀的灰度圖像p0,         # 需要跟蹤的特征點None,       # 不使用前一幀的特征點位置**lk_params)# 篩選成功跟蹤的特征點(st=1表示成功跟蹤)good_new = p1[st == 1]good_old = p0[st == 1]# 繪制特征點運動軌跡for i, (new, old) in enumerate(zip(good_new, good_old)):# 將浮點坐標轉換為整數a, b = new.ravel().astype(int)c, d = old.ravel().astype(int)# 在mask上繪制運動軌跡線(使用隨機顏色)mask = cv2.line(mask, (a, b), (c, d), color[i].tolist(), 2)# 將軌跡mask與當前幀疊加顯示img = cv2.add(frame, mask)cv2.imshow('frame', img)cv2.imshow('mask', mask)  # 單獨顯示軌跡mask# 等待按鍵(150ms延遲),ESC鍵退出k = cv2.waitKey(150)if k == 27:break# 更新前一幀的灰度圖像和特征點old_gray = frame_gray.copy()p0 = good_new.reshape(-1, 1, 2)  # 更新為當前幀的有效特征點# 釋放資源并關閉所有窗口
cv2.destroyAllWindows()
cap.release()

總結

光流估計的應用:
視頻增強與創作:光流不僅用于運動補償壓縮(如MPEG標準),還被應用于視頻插幀(生成中間幀提升流暢度)和特效合成(如電影中動態背景替換),英偉達SDK已展示其商業化潛力。

醫療精準化:在超聲影像中,光流估計校正探頭移動導致的圖像偏移,輔助心臟手術的實時導航;還可量化器官運動參數(如心肌應變率),為疾病診斷提供動態指標。

工業智能化升級:生產線中,光流實時監測機械臂運動軌跡,結合異常檢測算法預防故障;在精密裝配場景,通過微位移分析提升質檢精度。

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

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

相關文章

AIGC實戰之如何構建出更好的大模型RAG系統

一、RAG 系統核心架構解析 1. 檢索模塊深度優化 1.1 混合檢索技術實現 技術原理:結合稀疏檢索(BM25)與密集檢索(DPR),通過動態權重分配提升檢索精度。例如,在醫療領域,BM25 負責精…

Rust 學習筆記:函數和控制流

Rust 學習筆記:函數和控制流 Rust 學習筆記:函數和控制流函數(Function)語句和表達式帶返回值的函數注釋控制流if 表達式使用 else if 處理多個條件在 let 語句中使用 if循環loop從循環中返回值循環標簽消除多個循環之間的歧義帶 …

c#加密證件號的中間部分,改為*號

前言 使用場景:在我項目中,我需要給前端提供接口,所以我要吧證件號進行加密。例如:411421199510225612,這是一個身份證號,18為的,那么我加密完成之后就會是 411421********5612,類似…

存儲新勢力:助力DeepSeek一體機

寶子們,今天要給大家分享一個超酷的科技話題——各大廠商陸續推出的DeepSeek訓推一體機方案。 【集成人工智能訓推平臺】 它就像是一個超級智能的大腦中樞,為各種復雜的AI任務搭建AI模型流水線。預置算法模版、訓練框架、推理框架、模型任務調度和自動…

同樣機身尺寸下伺服電機比無刷電機扭矩更大的原因

點擊下面圖片帶您領略全新的嵌入式學習路線 🔥爆款熱榜 88萬閱讀 1.6萬收藏 在電機應用領域,伺服電機和無刷電機(BLDC)都是常見的動力源,但兩者在性能上存在顯著差異。尤其是在相同機身尺寸下,伺服電機的…

.dat 文件一般可以用什么打開

DAT文件是一種常見的文件格式,通常由多種應用程序生成。打開DAT文件的方法取決于其內容和生成它的軟件。 使用文本編輯器 如果DAT文件是一個簡單的文本文件,可以使用Windows的記事本或macOS的文本編輯器打開它。 右鍵點擊文件 -> 選擇“打開方式” -> 選擇“記事本”…

Java實現加密(七)國密SM2算法的簽名和驗簽(附商用密碼檢測相關國家標準/國密標準下載)

目錄 一、國密標準中,關于SM2簽名驗簽的定義二、SM2簽名和驗簽的實現原理1. 前置知識2. 簽名生成過程3. 驗簽過程4. 數學正確性證明5. 安全性與注意事項 三、帶userId、不帶userId的區別1. 核心區別2.算法區別(1) 哈希計算過程(2) 簽名驗簽流程 四、Java代碼實現1. …

Feign接口調用失敗降級機制

是的,通過 FallbackFactory 實現的降級邏輯在 Feign 接口調用失敗時會被觸發,但需要注意以下關鍵點以確保降級生效: 一、代碼有效性分析 降級邏輯是否生效? ? 是的,當 Feign 調用 BaseServiceFeign 接口的 updateMoni…

React-JSX語法

1、React和Vue的區別 (1)設計理念:react是一個聲明式UI庫,強調的是函數式編程,學習難度較高,vue是漸進式框架,學習難度較低 (2)模板語法:react使用的是JSX語…

RocketMQ 主題與隊列的協同作用解析(既然隊列存儲在不同的集群中,那要主題有什么用呢?)---管理命令、配置安裝

學習之前呢需要會使用linux的基礎命令 一.RocketMQ 主題與隊列的協同作用解析 在 RocketMQ 中,?主題(Topic)?與?隊列(Queue)?的協同設計實現了消息系統的邏輯抽象與物理存儲分離。雖然隊列實際存儲在不同集群的 B…

三菱FX PLC頻率采集

基于高速計數器,計算從X點輸入方波個數,定時提取計數器值,換算得到頻率。直接通過定時器數值判斷來實現定時計數的精度不高,提高精度需要考慮定時中斷方式。 初始化寄存器,通過M8235,M8236復位來選擇C235&a…

一種專用車輛智能配電模塊的設計解析:技術革新與未來展望

關鍵詞:智能配電模塊、STM32、CAN總線、電子開關、新能源汽車 引言:傳統配電系統的痛點與智能化轉型 傳統配電系統依賴繼電器和保險絲,存在體積大、壽命短、智能化低等缺陷(如圖1)。而新能源汽車和無人駕駛技術對配電…

python——異常

1、定義 異常是在代碼執行過程中發生的,它會影響到程序的正常運行。python程序不會自動來進行異常處理。python中常見異常父類:Exception。 2、常見異常 TypeError:類型錯誤異常。ValueError:值的異常。KeyError:鍵…

深入淺出Sentinel:分布式系統的流量防衛兵

引言 在當今的微服務架構和分布式系統中,服務間的依賴關系錯綜復雜,一個服務的故障可能會像多米諾骨牌一樣引發整個系統的崩潰。如何有效地保護系統免受突發流量、不穩定依賴服務的影響,成為每個架構師和開發者必須面對的挑戰。今天&#xf…

leetcode0106. 從中序與后序遍歷序列構造二叉樹-medium

1 題目:從中序與后序遍歷序列構造二叉樹 官方標定難度:中 給定兩個整數數組 inorder 和 postorder ,其中 inorder 是二叉樹的中序遍歷, postorder 是同一棵樹的后序遍歷,請你構造并返回這顆 二叉樹 。 示例 1: 輸入…

【Pandas】pandas DataFrame rsub

Pandas2.2 DataFrame Binary operator functions 方法描述DataFrame.add(other)用于執行 DataFrame 與另一個對象(如 DataFrame、Series 或標量)的逐元素加法操作DataFrame.add(other[, axis, level, fill_value])用于執行 DataFrame 與另一個對象&…

【信息系統項目管理師】高分論文:論人力資源管理與成本管理(醫院信息系統)

更多內容請見: 備考信息系統項目管理師-專欄介紹和目錄 文章目錄 論文一、規劃人力資源管理二、組建項目團隊三、建設項目團隊四、管理項目團隊論文 一個完善的醫院信息系統通常由上百個子系統構成,而這些系統隨著醫院發展需求逐步建設的,他們來源于不同廠家,基于不同的技…

【python】如何將python程序封裝為cpython的庫

python程序在發布時,往往會打包為cpython的庫,并且根據應用服務器的不同架構(x86/aarch64),以及python的不同版本,封裝的輸出類型也是非常多。本文介紹不同架構指定python下的代碼打包方式: 首…

Android 14 修改側滑手勢動畫效果

涉及關鍵類 SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt 修改如下: 一,覆蓋系統的默認手勢效果 SystemUI/src/com/andro…