- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
cv::cuda::DensePyrLKOpticalFlow是OpenCV CUDA模块中实现Lucas-Kanade稀疏光流(Sparse Optical Flow)的类,但它也可以通过参数配置来计算稠密光流(Dense Optical Flow)。
这个类是 cv::cuda::DenseOpticalFlow 的子类,因此它遵循统一的接口,并支持在 GPU 上高效运行 Lucas-Kanade 类型的光流算法。
类定义概览
属性 | 说明 |
---|---|
头文件 | <opencv2/cudaoptflow.hpp> |
命名空间 | cv::cuda |
继承自 | cv::cuda::DenseOpticalFlow |
用途 | 在 GPU上实现基于金字塔的Lucas-Kanade光流算法(稀疏或稠密) |
加速方式 | 利用CUDA进行GPU加速 |
算法背景:Lucas-Kanade 光流
Lucas-Kanade (LK) 是一种经典的稀疏光流算法,用于追踪图像中的关键点运动。标准LK只适用于小位移,但通过构建图像金字塔(PyrLK),可以处理更大范围的运动。
虽然LK本质上是“稀疏”的,但DensePyrLKOpticalFlow支持在整幅图像上进行稠密估计(即每个像素都计算一个运动向量)。
创建对象与常用函数
创建实例:
cv::Ptr<cv::cuda::DensePyrLKOpticalFlow> optflow = cv::cuda::DensePyrLKOpticalFlow::create
(
cv::Size winSize, // 窗口大小,如 cv::Size(21, 21)
int numLevels, // 图像金字塔层数
int itersPerLevel, // 每层迭代次数
bool useInitialFlow // 是否使用初始光流估计
);
示例:
cv::Ptr<cv::cuda::DensePyrLKOpticalFlow> optflow = cv::cuda::DensePyrLKOpticalFlow::create
(
cv::Size(21, 21), // 窗口大小
5, // 金字塔层数
30, // 每层迭代次数
false // 不使用初始 flow
);
常用成员函数
函数名 | 描述 |
---|---|
calc(InputArray I0, InputArray I1, InputOutputArray flow, Stream& stream = Stream::Null()) | 计算光流(必须为灰度图 CV_8UC1 或 CV_32FC1) |
getWinSize() / setWinSize(cv::Size) | 获取/设置窗口大小 |
getNumLevels() / setNumLevels(int) | 获取/设置金字塔层数 |
getIterations() / setIterations(int) | 获取/设置每层迭代次数 |
collectGarbage() | 手动释放内部缓存资源 |
代码示例
#include <opencv2/cudaoptflow.hpp>
#include <opencv2/cudaimgproc.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: 上传到 GPU
GpuMat d_frame1, d_frame2;
d_frame1.upload(frame1);
d_frame2.upload(frame2);
// Step 3: 创建 DensePyrLKOpticalFlow 对象
Ptr<DensePyrLKOpticalFlow> optflow = DensePyrLKOpticalFlow::create(
Size(21, 21), // 窗口大小
5, // 金字塔层数
30, // 每层迭代次数
false // 不使用初始 flow
);
// Step 4: 准备输出矩阵(CV_32FC2 格式)
GpuMat d_flow;
// Step 5: 执行光流计算
optflow->calc(d_frame1, d_frame2, d_flow);
// Step 6: 下载结果到 CPU
Mat host_flow;
d_flow.download(host_flow); // host_flow 类型为 CV_32FC2
// Step 7: 分离 flow_x 和 flow_y
std::vector<Mat> flow_parts(2);
split(host_flow, flow_parts); // flow_parts[0] = dx, flow_parts[1] = dy
// Step 8: 显示 flow_x 和 flow_y
normalize(flow_parts[0], flow_parts[0], 0, 1, NORM_MINMAX);
normalize(flow_parts[1], flow_parts[1], 0, 1, NORM_MINMAX);
imshow("Flow X", flow_parts[0]);
imshow("Flow Y", flow_parts[1]);
// Step 9: 合成彩色光流图(HSV 表示方向和强度)
Mat mag, ang;
cartToPolar(flow_parts[0], flow_parts[1], mag, ang, true);
Mat hsv_channels[] = {
ang,
Mat::ones(ang.size(), CV_32F),
mag
};
Mat hsv_merged;
merge(hsv_channels, 3, hsv_merged);
hsv_merged.convertTo(hsv_merged, CV_8U, 255);
Mat bgr_out;
cv::cvtColor(hsv_merged, bgr_out, cv::COLOR_HSV2BGR);
imshow("Optical Flow HSV", bgr_out);
waitKey(0);
return 0;
}