OpenCV CUDA 模块光流计算------稀疏光流算法类SparsePyrLKOpticalFlow
·
- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
OpenCV CUDA 模块中实现的稀疏光流算法类,基于 Lucas-Kanade 方法,并支持图像金字塔结构。适用于特征点跟踪任务(如角点、FAST 特征等)。
创建对象方法
静态函数:create()
static Ptr<cv::cuda::SparsePyrLKOpticalFlow> cv::cuda::SparsePyrLKOpticalFlow::create(
cv::Size winSize = cv::Size(21, 21),
int maxLevel = 3,
int iters = 30,
bool useInitialFlow = false
);
参数说明:
| 参数名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| winSize | Size | Size(21,21) | Lucas-Kanade 算法使用的窗口大小(必须为奇数) |
maxLevel | int | 3 | 金字塔最大层级数(0 表示不使用金字塔) |
iters | int | 30 | 每层金字塔上的最大迭代次数 |
useInitialFlow | bool | false | 是否使用初始 flow 输入 |
主要成员函数
深色版本
| 函数名 | 返回类型 | 描述 |
|---|---|---|
calc() | void | 计算两帧图像之间的稀疏光流 |
getWinSize() | Size | 获取当前窗口大小 |
getMaxLevel() | int | 获取金字塔最大层级 |
getIterations() | int | 获取每层迭代次数 |
getUseInitialFlow() | bool | 获取是否启用初始 flow 输入 |
setUseInitialFlow(bool flag) | void | 设置是否启用初始 flow 输入 |
getStream() | Stream& | 获取当前使用的 CUDA 流 |
setStream(const Stream& stream) | void | 设置使用的 CUDA 流 |
collectGarbage() | void | 显式释放内部资源(如显存) |
calc() 函数原型
void cv::cuda::SparsePyrLKOpticalFlow::calc(
InputArray prevImg, // 前一帧图像 (灰度图 CV_8UC1)
InputArray nextImg, // 当前帧图像 (灰度图 CV_8UC1)
InputArray prevPts, // 上一帧中要追踪的点集 (CV_32FC2)
InputOutputArray nextPts, // 输出:当前帧中追踪到的点集
OutputArray status, // 输出:每个点是否成功追踪 (uchar)
OutputArray err = noArray(), // 可选输出:误差值
Stream& stream = Stream::Null()
);
参数说明:
| 参数名 | 类型 | 描述 |
|---|---|---|
prevImg | InputArray | 前一帧图像(灰度图,CV_8UC1) |
nextImg | InputArray | 当前帧图像(灰度图,CV_8UC1) |
prevPts | InputArray | 上一帧的特征点位置(CV_32FC2 格式) |
nextPts | InputOutputArray | 输出:当前帧中对应点的位置(CV_32FC2) |
status | OutputArray | 输出:每个点是否成功追踪(uchar,1 成功,0 失败) |
err | OutputArray / noArray() | 可选输出:误差值 |
stream | Stream& | 可选 CUDA 流,默认为 Stream::Null() |
注意事项与要求
| 条件 | 要求 |
|---|---|
| 输入图像格式 | 必须为灰度图(CV_8UC1) |
| 关键点格式 | 必须为 CV_32FC2 格式,且是单行矩阵(rows == 1) |
| 图像尺寸 | prevImg 和 nextImg 的尺寸必须相同 |
| 实时性支持 | 支持实时处理,适合小数量关键点 |
| 替代方案 | 对于稠密光流,请使用 DenseOpticalFlow 或 NvidiaOpticalFlow 系列接口 |
示例代码
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/cudaoptflow.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: 检测角点作为追踪起点
std::vector< Point2f > corners;
goodFeaturesToTrack( frame1, corners, 500, 0.01, 10 ); // 最多检测500个角点
// Step 4: 转换为 GPU 可用数组
GpuMat d_prevPts;
// 构造一行多列的 CV_32FC2 格式 Mat
Mat m_prevPts( 1, corners.size(), CV_32FC2 );
for ( size_t i = 0; i < corners.size(); ++i )
{
m_prevPts.at< cv::Vec2f >( 0, i ) = cv::Vec2f( corners[ i ].x, corners[ i ].y );
}
d_prevPts.upload( m_prevPts );
// Step 5: 创建稀疏光流对象
Ptr< cuda::SparsePyrLKOpticalFlow > lk = cuda::SparsePyrLKOpticalFlow::create();
// Step 6: 准备输出变量
GpuMat d_nextPts;
GpuMat d_status;
GpuMat d_err;
// Step 7: 计算稀疏光流
lk->calc( d_frame1, d_frame2, d_prevPts, d_nextPts, d_status, d_err );
// Step 8: 下载结果
Mat nextPts, status;
d_nextPts.download( nextPts );
d_status.download( status );
// Step 9: 绘制跟踪结果
Mat output;
cv::cvtColor( frame1, output, COLOR_GRAY2BGR );
// 注意:status 和 nextPts 都是单行矩阵,所以使用 (0, i)
for ( int i = 0; i < status.cols; ++i )
{
if ( ( int )status.at< uchar >( 0, i ) == 1 )
{
Point2f pt1 = corners[ i ];
Point2f pt2 = nextPts.at< Point2f >( 0, i );
// 确保点在图像范围内
if ( pt2.x >= 0 && pt2.y >= 0 && pt2.x < frame1.cols && pt2.y < frame1.rows )
{
line( output, pt1, pt2, Scalar( 0, 255, 0 ), 1 );
circle( output, pt2, 2, Scalar( 0, 0, 255 ), -1 );
}
}
}
imshow( "Sparse PyrLK Optical Flow", output );
waitKey( 0 );
return 0;
}
运行结果

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)