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;
}

运行结果

相关推荐
爱看科技1 小时前
5G-A技术浪潮勾勒通信产业新局,微美全息加快以“5.5G+ AI”新势能深化场景应用
人工智能·5g
muyun28002 小时前
History 模式 vs Hash 模式:Vue Router 技术决策因素详解
vue.js·算法·哈希算法
打马诗人3 小时前
【YOLO11】【DeepSort】【NCNN】使用YOLOv11和DeepSort进行行人目标跟踪。(基于ncnn框架,c++实现)
人工智能·算法·目标检测
倒悬于世3 小时前
基于千问2.5-VL-7B训练识别人的表情
人工智能
瓦香钵钵鸡4 小时前
机器学习通关秘籍|Day 02:特征降维、用KNN算法和朴素贝叶斯实现分类
算法·机器学习·分类·贝叶斯·knn·超参数搜索·交叉验证
大哥喝阔落4 小时前
chatgpt plus简单得,不需要求人,不需要野卡,不需要合租,不需要昂贵的价格
人工智能·chatgpt
Godspeed Zhao4 小时前
自动驾驶中的传感器技术21——Camera(12)
人工智能·机器学习·自动驾驶·图像评测
hurrycry_小亦4 小时前
补:《每日AI-人工智能-编程日报》--2025年7月31日
人工智能
静心问道4 小时前
量化大型语言模型的评估
人工智能·语言模型·自然语言处理
小蜜蜂爱编程5 小时前
使用opencv基于realsense D435i展示基本的图像
opencv·realsense