- 操作系統:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 編程語言:C++11
算法描述
cv::cuda::OpticalFlowDual_TVL1類是基于變分優化方法的稠密光流算法實現(Dual TV-L1 光流模型),在 GPU 上加速運行。適用于精度要求較高、但對性能要求不極端的應用場景。
所屬模塊和頭文件
- 模塊:opencv_cudaoptflow
- 頭文件:
#include <opencv2/cudaoptflow.hpp>
功能概述
特性 | 描述 |
---|---|
稠密光流計算 | 計算圖像幀之間的像素級運動矢量(X 和 Y 分量) |
GPU 加速 | 使用 CUDA 在 NVIDIA GPU 上進行加速 |
高精度 | 基于 TV-L1 變分優化模型,適用于需要高精度光流的場景 |
支持參數調節 | 支持多個超參數調整以平衡速度與質量 |
創建對象方法
Ptr<cv::cuda::OpticalFlowDual_TVL1> tvl1 = cv::cuda::OpticalFlowDual_TVL1::create();
你也可以使用以下函數設置默認參數:
Ptr<cv::cuda::OpticalFlowDual_TVL1> tvl1 = cv::cuda::OpticalFlowDual_TVL1::create(double tau = 0.25,double lambda = 0.15,double theta = 0.3,int nscales = 5,int warps = 5,double epsilon = 0.01,int iterations = 300,bool useInitialFlow = false);
主要成員函數
函數名 | 描述 |
---|---|
calc(…) | 計算兩幀圖像之間的光流 |
get/setTau() | 獲取/設置梯度下降步長 τ |
get/setLambda() | 獲取/設置光流平滑約束系數 λ |
get/setTheta() | 獲取/設置對偶變量更新權重 θ |
get/setNumScales() | 獲取/設置金字塔層數 |
get/setWarpingsNumber() | 獲取/設置每層 warp 次數 |
get/setEpsilon() | 獲取/設置收斂閾值 ε |
get/setIterations() | 獲取/設置每次 warp 的迭代次數 |
get/setUseInitialFlow() | 是否使用初始 flow 輸入(如前一幀結果) |
calc() 函數原型
void calc(InputArray I0, // 第一幀圖像(灰度圖)InputArray I1, // 第二幀圖像(灰度圖)InputOutputArray flowX, // 輸出 X 分量InputOutputArray flowY, // 輸出 Y 分量Stream& stream = Stream::Null()
);
參數說明:
參數 | 類型 | 描述 |
---|---|---|
I0, I1 | InputArray | 輸入的兩幀圖像(必須為 CV_8UC1 灰度圖) |
flowX, flowY | InputOutputArray | 輸出的 X/Y 方向光流分量(CV_32FC1) |
stream | Stream& | 可選 CUDA 流,默認為 Stream::Null() |
示例代碼
#include <opencv2/opencv.hpp>
#include <opencv2/cudaoptflow.hpp>using namespace cv;
using namespace cv::cuda;// 自定義繪制函數
void drawOpticalFlow(const Mat& flow, Mat& dst, int step = 16);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: 創建 Dual TVL1 光流對象Ptr<cuda::OpticalFlowDual_TVL1> tvl1 = cuda::OpticalFlowDual_TVL1::create();// Step 4: 設置參數(OpenCV 4.9 支持的參數)tvl1->setNumIterations(100); // 總迭代次數tvl1->setLambda(0.15); // 平滑項權重tvl1->setUseInitialFlow(false); // 是否使用初始 flow// Step 5: 準備輸出光流數據(注意:輸出為 CV_32FC2 格式)GpuMat flow; // 注意:不再是 flowX + flowY 分開// Step 6: 執行光流計算(注意參數順序)tvl1->calc(d_frame1, d_frame2, flow, Stream::Null());// Step 7: 下載結果到 CPUMat host_flow;flow.download(host_flow);// Step 8: 繪制光流矢量圖Mat flowImg;drawOpticalFlow(host_flow, flowImg);imshow("frame1", frame1);imshow("frame2", frame2);imshow("CUDA Dual TV-L1 Flow", flowImg);waitKey(0);return 0;
}// 自定義繪制函數
void drawOpticalFlow(const Mat& flow, Mat& dst, int step) {dst = Mat::zeros(flow.size(), CV_8UC3);for (int y = 0; y < flow.rows; y += step) {for (int x = 0; x < flow.cols; x += step) {Point2f f = flow.at<Point2f>(y, x);line(dst, Point(x, y), Point(cvRound(x + f.x * 5), cvRound(y + f.y * 5)),Scalar(0, 255, 0));circle(dst, Point(cvRound(x + f.x * 5), cvRound(y + f.y * 5)), 1,Scalar(0, 255, 0), -1);}}
}