- 操作系統:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 編程語言:C++11
算法描述
cv::cuda::BroxOpticalFlow 是 OpenCV CUDA 模塊中實現Brox光流算法的類。該類用于在 GPU 上高效地計算兩幀圖像之間的稠密光流(Dense Optical Flow)。
什么是 Brox 光流?
Brox 光流算法是由 Thomas Brox 等人在 2004 年提出的一種基于變分法的稠密光流估計方法,它結合了:
- 亮度一致性約束(Brightness Constancy Constraint)
- 運動平滑性約束(Smoothness Constraint)
- 梯度一致性約束(Gradient Constancy Constraint)
這個算法在準確性和魯棒性方面表現良好,尤其適用于小到中等運動的場景。
cv::cuda::BroxOpticalFlow 類概述
屬性 | 描述 |
---|---|
頭文件 | <opencv2/cudaoptflow.hpp> |
命名空間 | cv::cuda |
繼承自 | cv::cuda::DenseOpticalFlow |
用途 | 計算兩個圖像幀之間的稠密光流(每個像素都有一個運動向量) |
GPU 加速 | 支持 CUDA GPU 加速 |
創建與初始化
創建對象
cv::Ptr<cv::cuda::BroxOpticalFlow> brox = cv::cuda::BroxOpticalFlow::create
(float alpha,float gamma,float scale_factor,int inner_iterations,int outer_iterations,int solver_iterations
);
參數說明:
參數名 | 類型 | 含義 |
---|---|---|
alpha | float | 控制光流平滑程度的正則化參數(越大越平滑) |
gamma | float | 控制梯度一致性的權重 |
scale_factor | float | 圖像金字塔縮放因子(通常為 0.5 表示每層縮小一半) |
inner_iterations | int | 內部迭代次數(求解線性系統) |
outer_iterations | int | 外部迭代次數(優化整體光流場) |
solver_iterations | int | 求解器每次迭代的次數(Jacobi 迭代次數) |
使用流程
- 準備輸入圖像(必須是灰度圖)
cv::Mat frame1_gray, frame2_gray;
cv::cvtColor(frame1, frame1_gray, cv::COLOR_BGR2GRAY);
cv::cvtColor(frame2, frame2_gray, cv::COLOR_BGR2GRAY);
- 轉換為浮點格式并歸一化([0, 1] 區間)
cv::Mat frame1_32f, frame2_32f;
frame1_gray.convertTo(frame1_32f, CV_32F, 1.0 / 255.0);
frame2_gray.convertTo(frame2_32f, CV_32F, 1.0 / 255.0);
- 上傳圖像到 GPU
cv::cuda::GpuMat d_frame1, d_frame2;
d_frame1.upload(frame1_32f);
d_frame2.upload(frame2_32f);
- 初始化 BroxOpticalFlow 對象
cv::Ptr<cv::cuda::BroxOpticalFlow> brox = cv::cuda::BroxOpticalFlow::create(0.197f, // alpha50.0f, // gamma0.8f, // scale_factor10, // inner_iterations77, // outer_iterations10 // solver_iterations
);
- 創建輸出矩陣(類型為 CV_32FC2)
cv::cuda::GpuMat d_flow; // 輸出光流,每個像素是一個 (dx, dy) 向量
- 執行光流計算
brox->calc(d_frame1, d_frame2, d_flow);
- 分離 flow_x 和 flow_y(可選)
std::vector<cv::cuda::GpuMat> flow_parts(2);
cv::split(d_flow, flow_parts); // flow_parts[0] = dx, flow_parts[1] = dy
- 下載結果到 CPU(顯示或保存用)
cv::Mat host_flowx, host_flowy;
flow_parts[0].download(host_flowx);
flow_parts[1].download(host_flowy);
代碼示例
#include <opencv2/cudaimgproc.hpp> // for split
#include <opencv2/cudaoptflow.hpp> // for BroxOpticalFlow
#include <opencv2/opencv.hpp> // core OpenCVusing namespace cv;
using namespace cv::cuda;int main()
{// Step 1: 加載圖像std::string path1 = "/media/dingxin/data/study/OpenCV/sources/images/frame1.png";std::string path2 = "/media/dingxin/data/study/OpenCV/sources/images/frame2.png";Mat frame1 = imread(path1, IMREAD_GRAYSCALE);Mat frame2 = imread(path2, IMREAD_GRAYSCALE);if (frame1.empty() || frame2.empty()){std::cerr << "無法加載圖像!路徑:" << path1 << " 或 " << path2 << std::endl;return -1;}// Step 2: 轉換為浮點格式 CV_32FC1 并歸一化到 [0,1]Mat frame1_32f, frame2_32f;frame1.convertTo(frame1_32f, CV_32F, 1.0 / 255.0);frame2.convertTo(frame2_32f, CV_32F, 1.0 / 255.0);// Step 3: 上傳到 GPUGpuMat d_frame1, d_frame2;d_frame1.upload(frame1_32f);d_frame2.upload(frame2_32f);// Step 4: 創建 BroxOpticalFlow 對象Ptr<BroxOpticalFlow> brox = BroxOpticalFlow::create();// Step 5: 創建輸出矩陣(CV_32FC2 類型)GpuMat d_flow;// Step 6: 執行光流計算brox->calc(d_frame1, d_frame2, d_flow);// Step 7: 下載光流結果到CPUMat host_flow;d_flow.download(host_flow); // 先下載到CPU// Step 8: 分離 flow_x 和 flow_y (在CPU上進行)std::vector<Mat> flow_parts(2);split(host_flow, flow_parts); // 現在使用的是CPU上的cv::splitMat host_flowx = flow_parts[0];Mat host_flowy = flow_parts[1];// Step 9: 歸一化顯示Mat flowx_show, flowy_show;normalize(host_flowx, flowx_show, 0, 1, NORM_MINMAX, CV_32F);normalize(host_flowy, flowy_show, 0, 1, NORM_MINMAX, CV_32F);imshow("Flow X", flowx_show);imshow("Flow Y", flowy_show);// Step 10: 合成彩色光流圖(HSV 表示方向和強度)Mat mag, ang;cartToPolar(host_flowx, host_flowy, mag, ang, true); // 計算 magnitude & angleMat hsv_channels[3];hsv_channels[0] = ang; // Hue 表示方向hsv_channels[1] = Mat::ones(ang.size(), CV_32F); // Saturation 固定最大hsv_channels[2] = mag; // Value 表示運動強度Mat hsv_merged, bgr_out;merge(hsv_channels, 3, hsv_merged); // 合并通道hsv_merged.convertTo(hsv_merged, CV_8U, 255); // 轉換為 0~255cv::cvtColor(hsv_merged, bgr_out, cv::COLOR_HSV2BGR); // 顯式使用 CPU 版本imshow("Optical Flow Color Map", bgr_out);waitKey(0); // 等待按鍵關閉窗口return 0;
}