- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
cv::cuda::FarnebackOpticalFlow 是 OpenCV CUDA 模块中实现 Farneback 光流算法 的类。该类用于在 GPU 上高效地计算两帧图像之间的稠密光流(Dense Optical Flow),特别适合视频分析和运动估计。
类定义概览
属性 | 说明 |
---|---|
头文件 | <opencv2/cudaoptflow.hpp> |
命名空间 | cv::cuda |
继承自 | cv::cuda::DenseOpticalFlow |
用途 | 计算两个图像帧之间的稠密光流(每个像素都有一个运动向量) |
GPU 加速 | 支持 CUDA GPU 加速 |
创建与初始化
创建对象
cpp
cv::Ptr<cv::cuda::FarnebackOpticalFlow> farneback = cv::cuda::FarnebackOpticalFlow::create();
你也可以通过设置参数来定制化这个对象:
cpp
cv::Ptr<cv::cuda::FarnebackOpticalFlow> farneback = cv::cuda::FarnebackOpticalFlow::create(
int numLevels = 5, // 图像金字塔的层数
double pyrScale = 0.5, // 金字塔缩放因子
bool fastPyramids = false, // 是否使用快速金字塔构建
int winSize = 13, // 滑动窗口大小
int numIters = 10, // 迭代次数
int polyN = 5, // 多项式展开邻域大小
double polySigma = 1.1, // 高斯权重的标准差
int flags = 0 // 标志位
);
或者,你可以创建默认对象后单独设置参数:
cpp
farneback->setNumLevels(5); // 设置金字塔层数
farneback->setPyrScale(0.5); // 设置金字塔缩放因子
farneback->setFastPyramids(false); // 是否使用快速金字塔
farneback->setWinSize(13); // 设置滑动窗口大小
farneback->setNumIters(10); // 设置迭代次数
farneback->setPolyN(5); // 设置多项式展开邻域大小
farneback->setPolySigma(1.1); // 设置高斯权重的标准差
farneback->setFlags(0); // 设置标志位
代码示例
cpp
#include <opencv2/cudaimgproc.hpp> // for upload/download
#include <opencv2/cudaoptflow.hpp>
#include <opencv2/opencv.hpp> // for imread, imshow 等
int main()
{
// Step 1: 加载灰度图像
cv::Mat frame1 = cv::imread( "/media/dingxin/data/study/OpenCV/sources/images/frame1.png", cv::IMREAD_GRAYSCALE );
cv::Mat frame2 = cv::imread( "/media/dingxin/data/study/OpenCV/sources/images/frame2.png", cv::IMREAD_GRAYSCALE );
if (frame1.empty() || frame2.empty()) {
std::cerr << "无法加载图像" << std::endl;
return -1;
}
// Step 2: 上传到 GPU
cv::cuda::GpuMat d_frame1, d_frame2;
d_frame1.upload(frame1);
d_frame2.upload(frame2);
// Step 3: 创建 FarnebackOpticalFlow 对象,并设置参数
cv::Ptr<cv::cuda::FarnebackOpticalFlow> farneback =
cv::cuda::FarnebackOpticalFlow::create(
5, // numLevels
0.5, // pyrScale
false, // fastPyramids
21, // winSize
20, // numIters
7, // polyN
1.5, // polySigma
0 // flags
);
// Step 4: 准备输出 flow 图像(CV_32FC2)
cv::cuda::GpuMat d_flow;
farneback->calc(d_frame1, d_frame2, d_flow);
// Step 5: 下载结果到 CPU
cv::Mat host_flow;
d_flow.download(host_flow); // CV_32FC2
// Step 6: 分离 dx 和 dy 通道
std::vector<cv::Mat> flow_parts(2);
cv::split(host_flow, flow_parts); // flow_parts[0] = dx, flow_parts[1] = dy
// Step 7: 计算 magnitude 和 angle
cv::Mat mag, ang;
cv::cartToPolar(flow_parts[0], flow_parts[1], mag, ang, true); // 角度单位为 degree
// Step 8: 构建 HSV 图像
std::vector<cv::Mat> hsv_channels;
// Hue: 角度归一化到 [0, 1]
ang.convertTo(ang, CV_32F);
ang = ang.mul(cv::Mat::ones(ang.size(), CV_32F) / 360.0f); // [0, 1]
// Saturation: 固定最大
cv::Mat sat = cv::Mat::ones(ang.size(), CV_32F) * 255; // [0, 255]
// Value: magnitude 归一化到 [0, 255]
cv::Mat val;
cv::normalize(mag, val, 0, 255, cv::NORM_MINMAX, CV_32F);
// 合并通道
hsv_channels.push_back(ang); // H: [0, 1]
hsv_channels.push_back(sat); // S: [0, 255]
hsv_channels.push_back(val); // V: [0, 255]
cv::Mat hsv_merged;
cv::merge(hsv_channels, hsv_merged);
// Step 9: 转换为 BGR 显示
cv::Mat bgr_out;
hsv_merged.convertTo(hsv_merged, CV_8U); // 必须先转成 8U
cv::cvtColor(hsv_merged, bgr_out, cv::COLOR_HSV2BGR);
// Step 10: 显示图像
cv::imshow("Optical Flow (Magnitude)", mag);
cv::imshow("Optical Flow (Angle)", ang);
cv::imshow("Optical Flow (HSV)", bgr_out);
cv::waitKey(0);
return 0;
}
运行结果
