基于運動補償的前景檢測算法

這段代碼實現了基于運動補償的前景檢測算法。

主要功能包括:

  • 運動補償模塊:使用基于網格的 KLT 特征跟蹤算法計算兩幀之間的運動,然后通過單應性變換實現幀間運動補償。
  • 前景檢測模塊:結合兩幀運動補償結果,通過幀間差分計算前景掩碼。
  • 異常處理:添加了圖像加載檢查和異常捕獲,提高了代碼的健壯性。
  • 路徑處理:自動創建保存目錄,避免因目錄不存在導致的錯誤。

使用時需要提供三幀連續圖像:兩個參考幀和當前幀。代碼會計算出前景掩碼并保存為圖像文件。

import cv2
import numpy as np
import os
import sysdef motion_compensate(frame1, frame2):"""使用基于網格的KLT特征跟蹤實現兩幀之間的運動補償參數:frame1: 前一幀圖像(BGR格式)frame2: 當前幀圖像(BGR格式)返回:compensated: 運動補償后的圖像mask: 補償區域的掩碼avg_dst: 平均運動距離motion_x: x方向平均運動量motion_y: y方向平均運動量homography_matrix: 單應性變換矩陣"""# 設置LK光流參數lk_params = dict(winSize=(15, 15), maxLevel=3,criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 30, 0.003))# 圖像預處理和網格點生成width = frame2.shape[1]height = frame2.shape[0]scale = 2  # 放大圖像以獲得更精確的跟蹤# 調整圖像大小以提高特征點檢測精度frame1_grid = cv2.resize(frame1, (960 * scale, 540 * scale), dst=None, interpolation=cv2.INTER_CUBIC)frame2_grid = cv2.resize(frame2, (960 * scale, 540 * scale), dst=None, interpolation=cv2.INTER_CUBIC)width_grid = frame2_grid.shape[1]height_grid = frame2_grid.shape[0]gridSizeW = 32 * 2  # 網格寬度gridSizeH = 24 * 2  # 網格高度# 生成網格點作為特征點p1 = []grid_numW = int(width_grid / gridSizeW - 1)grid_numH = int(height_grid / gridSizeH - 1)for i in range(grid_numW):for j in range(grid_numH):# 將點放置在每個網格中心point = (np.float32(i * gridSizeW + gridSizeW / 2.0), np.float32(j * gridSizeH + gridSizeH / 2.0))p1.append(point)p1 = np.array(p1)pts_num = grid_numW * grid_numHpts_prev = p1.reshape(pts_num, 1, 2)# 計算光流pts_cur, st, err = cv2.calcOpticalFlowPyrLK(frame1_grid, frame2_grid, pts_prev, None, **lk_params)# 選擇跟蹤成功的點good_new = pts_cur[st == 1]  # 當前幀中的跟蹤點good_old = pts_prev[st == 1]  # 前一幀中的跟蹤點# 計算運動距離和位移motion_distance = []translate_x = []translate_y = []for i, (new, old) in enumerate(zip(good_new, good_old)):a, b = new.ravel()c, d = old.ravel()motion_distance0 = np.sqrt((a - c) * (a - c) + (b - d) * (b - d))# 過濾異常大的運動值if motion_distance0 > 50:continuetranslate_x0 = a - ctranslate_y0 = b - dmotion_distance.append(motion_distance0)translate_x.append(translate_x0)translate_y.append(translate_y0)motion_dist = np.array(motion_distance)motion_x = np.mean(np.array(translate_x)) if translate_x else 0motion_y = np.mean(np.array(translate_y)) if translate_y else 0avg_dst = np.mean(motion_dist) if motion_dist.size > 0 else 0# 計算單應性變換矩陣if len(good_old) < 15:# 點太少時使用近似恒等變換homography_matrix = np.array([[0.999, 0, 0], [0, 0.999, 0], [0, 0, 1]])else:# 使用RANSAC算法估計單應性矩陣homography_matrix, status = cv2.findHomography(good_new, good_old, cv2.RANSAC, 3.0)# 應用單應性變換進行運動補償compensated = cv2.warpPerspective(frame1, homography_matrix, (width, height), flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP)# 生成掩碼以指示變換區域vertex = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=np.float32).reshape(-1, 1, 2)homo_inv = np.linalg.inv(homography_matrix)vertex_trans = cv2.perspectiveTransform(vertex, homo_inv)vertex_transformed = np.array(vertex_trans, dtype=np.int32).reshape(1, 4, 2)im = np.zeros(frame1.shape[:2], dtype='uint8')cv2.polylines(im, vertex_transformed, 1, 255)cv2.fillPoly(im, vertex_transformed, 255)mask = 255 - imreturn compensated, mask, avg_dst, motion_x, motion_y, homography_matrixdef FD_mask(lastFrame1, lastFrame2, currentFrame, save_path='data/mask.jpg'):"""使用兩幀運動補償計算前景掩碼參數:lastFrame1: 第一參考幀(BGR格式)lastFrame2: 第二參考幀(BGR格式)currentFrame: 當前幀(BGR格式)save_path: 結果掩碼保存路徑"""# 圖像預處理:高斯模糊和灰度轉換lastFrame1 = cv2.GaussianBlur(lastFrame1, (11, 11), 0)lastFrame1 = cv2.cvtColor(lastFrame1, cv2.COLOR_BGR2GRAY)lastFrame2 = cv2.GaussianBlur(lastFrame2, (11, 11), 0)lastFrame2 = cv2.cvtColor(lastFrame2, cv2.COLOR_BGR2GRAY)currentFrame = cv2.GaussianBlur(currentFrame, (11, 11), 0)currentFrame = cv2.cvtColor(currentFrame, cv2.COLOR_BGR2GRAY)# 計算第一參考幀到第二參考幀的運動補償img_compensate1, mask1, avg_dist1, motion_x1, motion_y1, homo_matrix = motion_compensate(lastFrame1, lastFrame2)frameDiff1 = cv2.absdiff(lastFrame2, img_compensate1)# 計算當前幀到第二參考幀的運動補償img_compensate2, mask2, avg_dist2, motion_x2, motion_y2, homo_matrix2 = motion_compensate(currentFrame, lastFrame2)frameDiff2 = cv2.absdiff(lastFrame2, img_compensate2)# 融合兩個差分結果frameDiff = (frameDiff1 + frameDiff2) / 2# 保存結果os.makedirs(os.path.dirname(save_path), exist_ok=True)cv2.imwrite(save_path, frameDiff)print(f'前景掩碼已保存至: {save_path}')return frameDiffif __name__ == "__main__":# 示例:加載三幀圖像并計算前景掩碼# 請確保這些圖像存在,或者修改為您自己的圖像路徑try:lastFrame1 = cv2.imread('data/Test_images/images/phantom05_0600.jpg')lastFrame3 = cv2.imread('data/Test_images/images/phantom05_0602.jpg')currentFrame = cv2.imread('data/Test_images/images/phantom05_0604.jpg')if lastFrame1 is None or lastFrame3 is None or currentFrame is None:print("錯誤: 無法加載圖像,請檢查文件路徑!")else:FD_mask(lastFrame1, lastFrame3, currentFrame)except Exception as e:print(f"程序執行出錯: {e}")    
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
#include <numeric>
#include <cmath>using namespace cv;
using namespace std;struct MotionCompensationResult {Mat compensated;Mat mask;float avg_dst;float motion_x;float motion_y;Mat homography_matrix;
};MotionCompensationResult motion_compensate(const Mat& frame1, const Mat& frame2) {// KLT 跟蹤參數TermCriteria term_criteria(TermCriteria::EPS | TermCriteria::COUNT, 30, 0.003);Size win_size(15, 15);int max_level = 3;// 圖像縮放int scale = 2;Mat frame1_grid, frame2_grid;resize(frame1, frame1_grid, Size(960 * scale, 540 * scale), 0, 0, INTER_CUBIC);resize(frame2, frame2_grid, Size(960 * scale, 540 * scale), 0, 0, INTER_CUBIC);// 創建網格點int gridSizeW = 32 * 2;int gridSizeH = 24 * 2;int grid_numW = static_cast<int>(frame2_grid.cols / gridSizeW - 1);int grid_numH = static_cast<int>(frame2_grid.rows / gridSizeH - 1);vector<Point2f> p1;for (int i = 0; i < grid_numW; i++) {for (int j = 0; j < grid_numH; j++) {p1.push_back(Point2f(i * gridSizeW + gridSizeW / 2.0f, j * gridSizeH + gridSizeH / 2.0f));}}int pts_num = grid_numW * grid_numH;Mat pts_prev = Mat(p1).reshape(2, pts_num);// 計算光流vector<Point2f> pts_cur;vector<uchar> status;vector<float> err;calcOpticalFlowPyrLK(frame1_grid, frame2_grid, pts_prev, pts_cur, status, err, win_size, max_level, term_criteria);// 篩選好點vector<Point2f> good_new, good_old;for (size_t i = 0; i < status.size(); i++) {if (status[i]) {good_new.push_back(pts_cur[i]);good_old.push_back(p1[i]);}}// 計算運動距離和位移vector<float> motion_distance;vector<float> translate_x, translate_y;for (size_t i = 0; i < good_new.size(); i++) {float dx = good_new[i].x - good_old[i].x;float dy = good_new[i].y - good_old[i].y;float dist = sqrt(dx * dx + dy * dy);if (dist > 50) continue;motion_distance.push_back(dist);translate_x.push_back(dx);translate_y.push_back(dy);}// 計算平均值float avg_dst = 0, motion_x = 0, motion_y = 0;if (!motion_distance.empty()) {avg_dst = accumulate(motion_distance.begin(), motion_distance.end(), 0.0f) / motion_distance.size();}if (!translate_x.empty()) {motion_x = accumulate(translate_x.begin(), translate_x.end(), 0.0f) / translate_x.size();motion_y = accumulate(translate_y.begin(), translate_y.end(), 0.0f) / translate_y.size();}// 計算單應性矩陣Mat homography_matrix;if (good_old.size() < 15) {homography_matrix = (Mat_<double>(3, 3) << 0.999, 0, 0, 0, 0.999, 0, 0, 0, 1);} else {homography_matrix = findHomography(good_new, good_old, RANSAC, 3.0);}// 運動補償Mat compensated;warpPerspective(frame1, compensated, homography_matrix, Size(frame1.cols, frame1.rows), INTER_LINEAR + WARP_INVERSE_MAP);// 計算掩膜vector<Point2f> vertex;vertex.push_back(Point2f(0, 0));vertex.push_back(Point2f(frame1.cols, 0));vertex.push_back(Point2f(frame1.cols, frame1.rows));vertex.push_back(Point2f(0, frame1.rows));Mat vertex_mat = Mat(vertex).reshape(2);Mat homo_inv = homography_matrix.inv();vector<Point2f> vertex_trans;perspectiveTransform(vertex_mat, vertex_trans, homo_inv);vector<Point> vertex_transformed;for (const auto& pt : vertex_trans) {vertex_transformed.push_back(Point(static_cast<int>(pt.x), static_cast<int>(pt.y)));}Mat mask = Mat::zeros(frame1.size(), CV_8UC1);vector<vector<Point>> contours;contours.push_back(vertex_transformed);polylines(mask, contours, true, Scalar(255), 1);fillPoly(mask, contours, Scalar(255));mask = 255 - mask;return {compensated, mask, avg_dst, motion_x, motion_y, homography_matrix};
}void FD_mask(const Mat& lastFrame1, const Mat& lastFrame2, const Mat& currentFrame, const string& save_path = "mask.jpg") {// 圖像預處理Mat lastFrame1_gray, lastFrame2_gray, currentFrame_gray;GaussianBlur(lastFrame1, lastFrame1_gray, Size(11, 11), 0);GaussianBlur(lastFrame2, lastFrame2_gray, Size(11, 11), 0);GaussianBlur(currentFrame, currentFrame_gray, Size(11, 11), 0);cvtColor(lastFrame1_gray, lastFrame1_gray, COLOR_BGR2GRAY);cvtColor(lastFrame2_gray, lastFrame2_gray, COLOR_BGR2GRAY);cvtColor(currentFrame_gray, currentFrame_gray, COLOR_BGR2GRAY);// 第一組運動補償auto result1 = motion_compensate(lastFrame1_gray, lastFrame2_gray);Mat frameDiff1;absdiff(lastFrame2_gray, result1.compensated, frameDiff1);// 第二組運動補償auto result2 = motion_compensate(currentFrame_gray, lastFrame2_gray);Mat frameDiff2;absdiff(lastFrame2_gray, result2.compensated, frameDiff2);// 計算最終差分Mat frameDiff;frameDiff1.convertTo(frameDiff1, CV_32F);frameDiff2.convertTo(frameDiff2, CV_32F);frameDiff = (frameDiff1 + frameDiff2) / 2;frameDiff.convertTo(frameDiff, CV_8U);// 保存結果imwrite(save_path, frameDiff);cout << "done!" << endl;
}int main() {// 讀取圖像Mat lastFrame1 = imread("data/Test_images/images/phantom05_0600.jpg");Mat lastFrame3 = imread("data/Test_images/images/phantom05_0602.jpg");Mat currentFrame = imread("data/Test_images/images/phantom05_0604.jpg");/*Mat lastFrame1 = imread("250514_430.bmp");Mat lastFrame3 = imread("250514_463.bmp");Mat currentFrame = imread("250514_490.bmp");*/// 檢查圖像是否成功加載if (lastFrame1.empty() || lastFrame3.empty() || currentFrame.empty()) {cout << "無法加載圖像!" << endl;return -1;}// 執行幀間差分FD_mask(lastFrame1, lastFrame3, currentFrame);return 0;
}

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

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

相關文章

使用matlab進行數據擬合

目錄 一、工作區建立數據 二、曲線擬合器(在"APP"中) 三、曲線擬合函數及參數 四、 在matlab中編寫代碼 一、工作區建立數據 首先&#xff0c;將數據在matlab工作區中生成。如圖1所示&#xff1a; 圖 1 二、曲線擬合器(在"APP"中) 然后&#xff0c;…

Playwright 安裝配置文件詳解

Playwright 安裝&配置文件詳解 環境準備 Node.js 14.0&#xff08;推薦 LTS 版本&#xff09;npm&#xff08;推薦使用最新版&#xff09;支持 Windows、macOS、Linux 一步到位的官方推薦安裝方式 1. 進入你的項目目錄 # Windows cd 路徑\到\你的項目 # macOS/Linux cd…

中國古代史4

東漢 公元25年&#xff0c;劉秀建立東漢&#xff0c;定都洛陽&#xff0c;史稱光武中興 白馬寺&#xff1a;漢明帝時期建立&#xff0c;是佛教傳入中國后興建的第一座官辦寺院&#xff0c;有中國佛教的“祖庭”和“釋源”之稱&#xff0c;距今1900多年歷史 班超—西域都護—投…

springboot + mysql8降低版本到 mysql5.7

springboot mysql8降低版本到 mysql5.7 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version></dependency>spring:datasource:driverClassName: com.mysql.jdbc.D…

4.4java常用類

在 Java 中&#xff0c;System 和 Runtime 類都是 java.lang 包下非常重要的類&#xff0c;它們提供了與系統交互以及管理 Java 虛擬機&#xff08;JVM&#xff09;運行時環境的功能。 System 類 System 類包含了一些有用的類字段和方法&#xff0c;它不能被實例化&#xff0…

【嵌入式筆記】Modbus TCP

1.概述 定義&#xff1a;Modbus TCP 是 Modbus 協議的變體&#xff0c;基于 TCP/IP 協議棧&#xff0c;用于通過以太網實現工業設備間的通信。 背景&#xff1a;由施耐德電氣&#xff08;原 Modicon 公司&#xff09;在 1999 年發布&#xff0c;將傳統的 Modbus RTU/ASCII 適配…

《解鎖React Native與Flutter:社交應用啟動速度優化秘籍》

React Native和Flutter作為當下熱門的跨平臺開發框架&#xff0c;在優化應用啟動性能方面各有千秋。今天&#xff0c;我們就深入剖析它們獨特的策略與方法。 React Native應用的初始包大小對啟動速度影響顯著。在打包階段&#xff0c;通過精準分析依賴&#xff0c;去除未使用的…

R語言學習--Day02--實戰經驗反饋

最近在做需要用R語言做數據清洗的項目&#xff0c;在網上看再多的技巧與語法&#xff0c;都不如在項目中實戰學習的快&#xff0c;下面是我通過實戰得來的經驗。 判斷Rstudio是否卡死 很多時候&#xff0c;我們在運行R語言代碼時&#xff0c;即使只是運行框選的幾行代碼&#…

How Sam‘s Club nudge customers into buying more

Here’s how Sam’s Club (or similar warehouse memberships) nudge customers into buying more: It’s a classic psychological strategy rooted in sunk cost fallacy and loss aversion. 1. Prepaid Membership Creates a “Sunk Cost” Once you’ve paid the annual …

OpenHarmony系統HDF驅動開發介紹(補充)

一、HDF驅動簡介 HDF&#xff08;Hardware Driver Foundation&#xff09;驅動框架&#xff0c;為驅動開發者提供驅動框架能力&#xff0c;包括驅動加載、驅動服務管理、驅動消息機制和配置管理。 簡單來說&#xff1a;HDF框架的驅動和Linux的驅動比較相似都是由配置文件和驅動…

自然語言處理 (NLP) 入門:NLTK 與 SpaCy 的初體驗

自然語言處理入門&#xff1a;NLTK 與 SpaCy 的初體驗 在當今數字化飛速發展的浪潮中&#xff0c;自然語言處理&#xff08;NLP&#xff09;已經成為了極具熱度的技術領域。自然語言處理的核心目標是讓計算機能夠理解、分析并生成人類語言&#xff0c;其應用場景極為廣泛&…

LLaVA:開源多模態大語言模型深度解析

一、基本介紹 1.1 項目背景與定位 LLaVA(Large Language and Vision Assistant)是由Haotian Liu等人開發的開源多模態大語言模型,旨在實現GPT-4級別的視覺-語言交互能力。該項目通過視覺指令微調技術,將預訓練的視覺編碼器與語言模型深度融合,在多個多模態基準測試中達到…

如何利用大模型對文章進行分段,提高向量搜索的準確性?

利用大模型對文章進行分段以提高向量搜索準確性,需結合文本語義理解、分塊策略優化以及向量表示技術。以下是系統性的解決方案: 一、分塊策略的核心原則 語義完整性優先 分塊需確保每個文本單元在語義上獨立且完整。研究表明,當分塊內容保持單一主題時,向量嵌入的語義表征能…

Java高頻面試之并發編程-17

volatile 和 synchronized 的區別 在 Java 并發編程中&#xff0c;volatile 和 synchronized 是兩種常用的同步機制&#xff0c;但它們的適用場景和底層原理有顯著差異。以下是兩者的詳細對比&#xff1a; 1. 核心功能對比 特性volatilesynchronized原子性不保證復合操作的原…

技術債務積累,如何進行有效管理

識別和評估技術債務、明確技術債務的優先級、制定系統的還債計劃、持續監控與預防技術債務產生是有效管理技術債務積累的重要策略。其中尤其要注重識別和評估技術債務&#xff0c;只有準確識別技術債務的種類和嚴重程度&#xff0c;才能制定出高效且有針對性的解決方案&#xf…

安裝windows版本的nacos

一、下載nacos安裝包 瀏覽器搜索nacos&#xff0c;進入nacos官網 https://nacos.io/docs/latest/overview/ 選擇下載windows版本的nacos 二、解壓縮 三、進入bin目錄&#xff0c;cmd命令行窗口 四、啟動nacos 查看日志 五、打開可視化頁面查看 以上&#xff0c;就是安裝wind…

小結:Android系統架構

https://developer.android.com/topic/architecture?hlzh-cn Android系統的架構&#xff0c;分為四個主要層次&#xff1a;應用程序層、應用框架層、庫和運行時層以及Linux內核層。&#xff1a; 1. 應用程序層&#xff08;Applications&#xff09; 功能&#xff1a;這一層包…

鴻蒙5.0項目開發——鴻蒙天氣項目的實現(歡迎頁)

【高心星出品】 文章目錄 歡迎頁面效果數據字典創建數據庫表格Splash頁面頁面功能歡迎頁代碼亮點 項目按照從數據庫連接層–視圖層–業務邏輯層這種三層架構開發&#xff0c;所以先設計了數據庫表格的結構&#xff0c;在EntryAbility中創建表格。 歡迎頁面效果 數據字典 sear…

使用譜聚類將相似度矩陣分為2類

使用譜聚類將相似度矩陣分為2類的步驟如下&#xff1a; 構建相似度矩陣&#xff1a;提供的1717矩陣已滿足對稱性且對角線為1。 計算度矩陣&#xff1a;對每一行求和得到各節點的度&#xff0c;形成對角矩陣。 計算歸一化拉普拉斯矩陣&#xff1a;采用對稱歸一化形式 LsymI?D…

MySQL 8.0 OCP 英文題庫解析(三)

Oracle 為慶祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免費考取原價245美元的MySQL OCP 認證。 從今天開始&#xff0c;將英文題庫免費公布出來&#xff0c;并進行解析&#xff0c;幫助大家在一個月之內輕松通過OCP認證。 本期公布試題16~25 試題16:…