OpenCV CUDA 模块光流计算------稀疏光流算法类SparsePyrLKOpticalFlow

  • 操作系统:ubuntu22.04
  • OpenCV版本:OpenCV4.9
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

OpenCV CUDA 模块中实现的稀疏光流算法类,基于 Lucas-Kanade 方法,并支持图像金字塔结构。适用于特征点跟踪任务(如角点、FAST 特征等)。

创建对象方法

静态函数:create()

cpp 复制代码
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() 函数原型

cpp 复制代码
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
图像尺寸 prevImgnextImg 的尺寸必须相同
实时性支持 支持实时处理,适合小数量关键点
替代方案 对于稠密光流,请使用 DenseOpticalFlowNvidiaOpticalFlow 系列接口

示例代码

cpp 复制代码
#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;
}

运行结果

相关推荐
披星の月14 小时前
一次完整大模型Lora训练实现“AI面试风”
人工智能·大模型
帐篷Li14 小时前
教育部:加快普及中小学生人工智能教育政策汇总
人工智能
网络工程小王14 小时前
【大模型(LLM)的业务开发】学习笔记
人工智能·算法·机器学习
y = xⁿ14 小时前
【Leet Code 】滑动窗口
java·算法·leetcode
SLAM必须dunk14 小时前
四足强化入门3---Robot Lab重点机器人配置,训练和调参
人工智能·深度学习·机器学习·机器人
WBluuue14 小时前
数据结构与算法:二项式定理和二项式反演
c++·算法
nianniannnn14 小时前
力扣104.二叉树的最大深度 110. 平衡二叉树
算法·leetcode·深度优先
AI医影跨模态组学14 小时前
ESMO Open 中国医学科学院肿瘤医院:整合影像组学、病理组学和活检适应性免疫评分预测局部晚期直肠癌远处转移
人工智能·深度学习·机器学习·论文·医学·医学影像
Ztopcloud极拓云视角14 小时前
GPT-6 & DeepSeek V4 双雄临近:企业多模型路由网关实战指南
人工智能·gpt·deepseek·gpt-6
hughnz14 小时前
AI和自动化让油田钻工慢慢消失
大数据·人工智能