- 操作系統:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 編程語言:C++11
算法描述
OpenCV CUDA 模塊中實現的稀疏光流算法類,基于 Lucas-Kanade 方法,并支持圖像金字塔結構。適用于特征點跟蹤任務(如角點、FAST 特征等)。
創建對象方法
靜態函數:create()
static Ptr<cv::cuda::SparsePyrLKOpticalFlow> cv::cuda::SparsePyrLKOpticalFlow::create(cv::Size winSize = cv::Size(21, 21),int maxLevel = 3,int iters = 30,bool useInitialFlow = false
);
參數說明:
參數名 | 類型 | 默認值 | 描述 |
---|---|---|---|
winSize | Size | Size(21,21) | Lucas-Kanade 算法使用的窗口大小(必須為奇數) |
maxLevel | int | 3 | 金字塔最大層級數(0 表示不使用金字塔) |
iters | int | 30 | 每層金字塔上的最大迭代次數 |
useInitialFlow | bool | false | 是否使用初始 flow 輸入 |
主要成員函數
深色版本
函數名 | 返回類型 | 描述 |
---|---|---|
calc() | void | 計算兩幀圖像之間的稀疏光流 |
getWinSize() | Size | 獲取當前窗口大小 |
getMaxLevel() | int | 獲取金字塔最大層級 |
getIterations() | int | 獲取每層迭代次數 |
getUseInitialFlow() | bool | 獲取是否啟用初始 flow 輸入 |
setUseInitialFlow(bool flag) | void | 設置是否啟用初始 flow 輸入 |
getStream() | Stream& | 獲取當前使用的 CUDA 流 |
setStream(const Stream& stream) | void | 設置使用的 CUDA 流 |
collectGarbage() | void | 顯式釋放內部資源(如顯存) |
calc() 函數原型
void cv::cuda::SparsePyrLKOpticalFlow::calc(InputArray prevImg, // 前一幀圖像 (灰度圖 CV_8UC1)InputArray nextImg, // 當前幀圖像 (灰度圖 CV_8UC1)InputArray prevPts, // 上一幀中要追蹤的點集 (CV_32FC2)InputOutputArray nextPts, // 輸出:當前幀中追蹤到的點集OutputArray status, // 輸出:每個點是否成功追蹤 (uchar)OutputArray err = noArray(), // 可選輸出:誤差值Stream& stream = Stream::Null()
);
參數說明:
參數名 | 類型 | 描述 |
---|---|---|
prevImg | InputArray | 前一幀圖像(灰度圖,CV_8UC1) |
nextImg | InputArray | 當前幀圖像(灰度圖,CV_8UC1) |
prevPts | InputArray | 上一幀的特征點位置(CV_32FC2 格式) |
nextPts | InputOutputArray | 輸出:當前幀中對應點的位置(CV_32FC2) |
status | OutputArray | 輸出:每個點是否成功追蹤(uchar,1 成功,0 失敗) |
err | OutputArray / noArray() | 可選輸出:誤差值 |
stream | Stream& | 可選 CUDA 流,默認為 Stream::Null() |
注意事項與要求
條件 | 要求 |
---|---|
輸入圖像格式 | 必須為灰度圖(CV_8UC1) |
關鍵點格式 | 必須為 CV_32FC2 格式,且是單行矩陣(rows == 1 ) |
圖像尺寸 | prevImg 和 nextImg 的尺寸必須相同 |
實時性支持 | 支持實時處理,適合小數量關鍵點 |
替代方案 | 對于稠密光流,請使用 DenseOpticalFlow 或 NvidiaOpticalFlow 系列接口 |
示例代碼
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/cudaoptflow.hpp>
#include <opencv2/opencv.hpp>using namespace cv;
using namespace cv::cuda;int main()
{// Step 1: 讀取兩幀圖像(灰度圖)Mat frame1 = imread( "/media/dingxin/data/study/OpenCV/sources/images/frame1.png", IMREAD_GRAYSCALE );Mat frame2 = imread( "/media/dingxin/data/study/OpenCV/sources/images/frame2.png", IMREAD_GRAYSCALE );if ( frame1.empty() || frame2.empty() ){std::cerr << "無法加載圖像" << std::endl;return -1;}// Step 2: 上傳到 GPUGpuMat d_frame1, d_frame2;d_frame1.upload( frame1 );d_frame2.upload( frame2 );// Step 3: 檢測角點作為追蹤起點std::vector< Point2f > corners;goodFeaturesToTrack( frame1, corners, 500, 0.01, 10 ); // 最多檢測500個角點// Step 4: 轉換為 GPU 可用數組GpuMat d_prevPts;// 構造一行多列的 CV_32FC2 格式 MatMat m_prevPts( 1, corners.size(), CV_32FC2 );for ( size_t i = 0; i < corners.size(); ++i ){m_prevPts.at< cv::Vec2f >( 0, i ) = cv::Vec2f( corners[ i ].x, corners[ i ].y );}d_prevPts.upload( m_prevPts );// Step 5: 創建稀疏光流對象Ptr< cuda::SparsePyrLKOpticalFlow > lk = cuda::SparsePyrLKOpticalFlow::create();// Step 6: 準備輸出變量GpuMat d_nextPts;GpuMat d_status;GpuMat d_err;// Step 7: 計算稀疏光流lk->calc( d_frame1, d_frame2, d_prevPts, d_nextPts, d_status, d_err );// Step 8: 下載結果Mat nextPts, status;d_nextPts.download( nextPts );d_status.download( status );// Step 9: 繪制跟蹤結果Mat output;cv::cvtColor( frame1, output, COLOR_GRAY2BGR );// 注意:status 和 nextPts 都是單行矩陣,所以使用 (0, i)for ( int i = 0; i < status.cols; ++i ){if ( ( int )status.at< uchar >( 0, i ) == 1 ){Point2f pt1 = corners[ i ];Point2f pt2 = nextPts.at< Point2f >( 0, i );// 確保點在圖像范圍內if ( pt2.x >= 0 && pt2.y >= 0 && pt2.x < frame1.cols && pt2.y < frame1.rows ){line( output, pt1, pt2, Scalar( 0, 255, 0 ), 1 );circle( output, pt2, 2, Scalar( 0, 0, 255 ), -1 );}}}imshow( "Sparse PyrLK Optical Flow", output );waitKey( 0 );return 0;
}