- 操作系统: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: 上传到 GPU
GpuMat 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: 下载结果到 CPU
Mat 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);
}
}
}