C/C++开发,opencv光流法跟踪特征点

news2024/11/5 15:50:09

目录

一、Lucas-Kanade光流法

1.1cv::ORB特征点提取方法

1.2 cv::calcOpticalFlowPyrLK函数

二、完整案例实现

2.1 程序代码

2.2 程序编译及输出

2.3 读取视频文件方式补充


一、Lucas-Kanade光流法

          在 OpenCV 中,使用 特征检测器(例如ORB ,Oriented FAST and Rotated BRIEF,更多的特征点提取方法见本栏博文:C/C++开发,opencv-features2d模块,SIFT等特征检测器应用-CSDN博客)与 cv::calcOpticalFlowPyrLK 光流跟踪器结合是一种有效的方法,用于跟踪视频序列中的关键点变化。

1.1cv::ORB特征点提取方法

        在OpenCV中,ORB(Oriented FAST and Rotated BRIEF)是一种快速的特征点检测和描述符提取算法,它结合了FAST(Features from Accelerated Segment Test)特征点检测器和BRIEF(Binary Robust Independent Elementary Features)描述符的优点,并增加旋转不变性和尺度不变性。

        在实际使用中,主要用到cv::ORB::create创建对象,然后使用detect*函数提取特征点。

//函数原型,OpenCV 4.x为例
cv::Ptr<cv::ORB> cv::ORB::create(  
    int nfeatures = 500,         // 最大特征点数量  
    float scaleFactor = 1.2f,    // 金字塔图像间的尺度参数(每层图像之间的尺度比例)  
    int nlevels = 8,             // 金字塔层数(包括原始图像层)  
    int edgeThreshold = 31,      // 用于FAST检测的边缘阈值(边缘像素不会被认为是关键点)  
    int firstLevel = 0,          // 使用的金字塔的第一层(通常设置为0)  
    int WTA_K = 2,               // 生成描述子时用于局部比较的点数  
    int scoreType = cv::ORB::HARRIS_SCORE, // 角点检测评分类型(HARRIS_SCORE或FAST_SCORE)  
    int patchSize = 31,          // 用于描述子计算的邻域大小(以像素为单位)  
    int fastThreshold = 20        // FAST角点检测的阈值(低于此值的点不会被认为是角点)  
);

        cv::ORB::create 是一个静态成员函数,用于创建并配置一个ORB(Oriented FAST and Rotated BRIEF)特征检测器对象。cv::ORB::create 函数允许你通过传递不同的参数来定制ORB检测器的行为。这个函数是可选的,因为cv::Ptr<cv::ORB>可以直接通过new关键字和构造函数来创建ORB对象,但使用create函数是一种更简洁、更现代的方式,它会自动处理内存管理(通过智能指针)。

         cv::ORB::detectAndCompute 函数是ORB特征检测器的一个关键方法,它同时执行特征点检测和描述符计算两个步骤。该函数的参数允许用户指定输入图像、掩码(可选)、输出关键点向量和输出描述符矩阵。

//函数原型
void cv::ORB::detectAndCompute(InputArray image,  
                               InputArray mask,  
                               std::vector<KeyPoint>& keypoints,  
                               OutputArray descriptors,  
                               bool useProvidedKeyPoints = false);
/*
参数:
    1)image (InputArray): 输入图像,可以是灰度图像或彩色图像。ORB算法通常在灰度图像上运行得更好,因此如果输入是彩色图像,ORB可能会在内部将其转换为灰度图。
    2)mask (InputArray, 可选): 一个与输入图像大小相同的掩码图像,用于指定哪些区域应该被考虑用于特征检测。掩码图像必须是单通道、8位深度的图像,其中非零像素表示要检测特征的区域,零像素表示要忽略的区域。如果掩码为空(即传递Mat()),则没有区域会被忽略。
    3)keypoints (std::vector<KeyPoint>&): 输出参数,用于存储检测到的关键点。每个关键点包含位置(x, y)、尺度(size)、方向(angle,对于ORB是可选的,因为ORB可能不计算方向)等信息。
    4)descriptors (OutputArray): 输出参数,用于存储关键点的描述符。ORB使用BRIEF或rBRIEF作为描述符,因此每个描述符是一个二进制字符串,通常表示为一个uchar类型的向量或矩阵。
    5)useProvidedKeyPoints (bool, 默认为false): 一个可选参数,指定是否使用用户提供的关键点来计算描述符。如果设置为true,则detectAndCompute函数将仅计算由keypoints参数提供的关键点的描述符,而不会执行特征点检测。这通常用于当你已经有了关键点位置,但需要计算这些关键点的描述符时。
*/

        调整cv::ORB::create函数中的参数,如nfeatures(特征点数量)、scaleFactor(尺度因子)、nlevels(金字塔层数)等,可以控制ORB检测器的detectAndCompute 行为,以适应不同的应用场景和需求。 

1.2 cv::calcOpticalFlowPyrLK函数

        在C++中使用OpenCV库进行光流法(Lucas-Kanade)跟踪特征点是一种常见的技术,特别适用于视频测振处理、运动估计和物体跟踪等应用。OpenCV中的光流法实现是通过cv::calcOpticalFlowPyrLK函数来跟踪视频中的特征点。

//函数原型
void cv::calcOpticalFlowPyrLK(InputArray prevImg, InputArray nextImg,  
                              InputArray prevPts, OutputArray nextPts,  
                              OutputArray status,  
                              OutputArray err,  
                              Size winSize = Size(21, 21),  
                              int maxLevel = 3,  
                              TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),  
                              int flags = 0,  
                              double minEigThreshold = 1e-4);
/*
参数说明:
    prevImg:前一帧图像,类型为 CV_8UC1 或 CV_32FC1。
    nextImg:当前帧图像,与 prevImg 类型相同。
    prevPts:前一帧中特征点的坐标,类型为 Point2f 的 vector 或 Mat。
    nextPts:输出参数,存储当前帧中对应特征点的坐标,类型与 prevPts 相同。
    status:输出状态数组,用于表示每个特征点是否成功找到对应点,类型为 uchar 的 vector 或 Mat。
    err:输出数组,存储每个特征点的光流误差估计,类型为 float 的 vector 或 Mat。
    winSize:搜索窗口的大小,默认为 Size(21, 21)。
    maxLevel:金字塔的最大层数,默认为 3。
    criteria:迭代算法的终止条件,默认为迭代 30 次或达到某个最小误差(0.01)。
    flags:操作标志,默认为 0。
    minEigThreshold:最小特征值阈值,用于检测跟踪质量,默认为 1e-4。
*/

        通常是先读取视频或捕获摄像头,选用第一帧中检测 ORB 特征点,并将它们作为初始点集传递给 cv::calcOpticalFlowPyrLK。然后,在视频序列的每一帧中,计算这些点的光流,并更新它们的位置。通常,由于使用了光流跟踪,因此不需要在每帧中都重新检测特征点,除非跟踪失败或需要重新初始化。

        在实际应用中,由于遮挡、快速运动或光照变化等原因,一些特征点可能会丢失或变得不可靠。因此,可能需要实现一些额外的逻辑来处理这些情况,比如重新检测丢失的特征点或删除不可靠的跟踪点。

        由于 cv::calcOpticalFlowPyrLKprevPtsnextPts 需要在每次迭代后更新,因此确保在每次迭代开始时正确地设置了这些变量是很重要的。

二、完整案例实现

2.1 程序代码

        main.cpp代码,使用OpenCV的VideoCapture类来从文件或摄像头捕获视频帧,使用ORB特征检测(cv::ORB::create,cv::ORB::detectAndCompute),使用光流法(cv::calcOpticalFlowPyrLK)跟踪特征点。获得了特征点的位置随时间的变化,进行了这些特征点绘制(在原图像上绘制圆点、变化线等),也可以进一步分析这些变化来估计振动参数,如频率、振幅等。

#include <opencv2/opencv.hpp>  
#include <vector>
#include <iostream>

int main(int argc, char* argv[]) 
{  
    cv::VideoCapture cap; // 视频捕获对象 
    if(argc< 2){ 
        cap.open(0);        //0是摄像头的索引
	}else{        
        // 加载视频 
        cap.open(argv[1]);  //如果是视频文件,则传入文件路径  
    }
    // cv::VideoCapture cap(0); // 0是摄像头的索引,如果是视频文件,则传入文件路径  
    if (!cap.isOpened()) {  
        std::cerr << "Error opening video stream or file" << std::endl;  
        return -1;  
    }  
	
	cv::Mat frame, gray, prevGray;  
    cv::Ptr<cv::ORB> detector = cv::ORB::create(500); // 创建ORB检测器,这里设置最大特征点数为500  
  
    std::vector<cv::Point2f> prevPts, nextPts;  
    std::vector<uchar> status;  
    std::vector<float> err;  
  
    // 读取第一帧并检测ORB特征点  
    if (cap.read(frame)) {  
        cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);  
        std::vector<cv::KeyPoint> keypoints;  
        cv::Mat descriptors;  
        detector->detectAndCompute(gray, cv::Mat(), keypoints, descriptors);  
  
        // 将关键点坐标转换为Point2f  
        for (const auto& kp : keypoints) {  
            prevPts.push_back(kp.pt);  
        }   
    }  
	prevGray = gray.clone();  
    // 循环读取视频帧并计算光流  
    while (cap.read(frame)) {  
        cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);  
  
        // 使用金字塔Lucas-Kanade方法计算光流  
        cv::calcOpticalFlowPyrLK(prevGray, gray, prevPts, nextPts, status, err);  
  
        // 绘制跟踪点  
        for (size_t i = 0; i < nextPts.size(); i++) {  
            if (status[i]) {  
                // cv::circle(frame, prevPts[i], 2, cv::Scalar(0, 255, 0), -1); 
                cv::circle(frame, nextPts[i], 2, cv::Scalar(255, 0, 0), -1); 
                cv::line(frame, prevPts[i], nextPts[i], cv::Scalar(0, 0, 255), 1); 
                //可以存储nextPts点,形成时间序列信息
                //进一步分析prevPts, nextPts点变化来估计振动参数,如频率、振幅等。这通常涉及到信号处理技术,如傅里叶变换等。
            }  
        } 
        // 更新前一帧的跟踪点  
        prevPts = nextPts;  
        std::vector<cv::Point2f>().swap(nextPts); // 清空nextPts以准备下一帧使用  
        // 更新前一帧的灰度图  
        prevGray = gray.clone();  

        // 显示结果  
        cv::imshow("Frame", frame);  
        char c = (char)cv::waitKey(25);  
        if (c == 27) break; // 按ESC退出  
    }  
    cap.release();  
    cv::destroyAllWindows();  
    return 0;  
}
2.2 程序编译及输出

        本文是采用win系统下,opencv采用MinGW编译的静态库(C/C++开发,win下OpenCV+MinGW编译环境搭建_opencv mingw-CSDN博客),建立makefile:

#/bin/sh
#win32
CX= g++ -DWIN32 
#linux
#CX= g++ -Dlinux 

BIN 		:= ./
TARGET      := Video_vibrometer.exe
FLAGS		:= -std=c++11 -static
SRCDIR 		:= ./
#INCLUDES
INCLUDEDIR 	:= -I"../../opencv_MinGW/include" -I"./"
#-I"$(SRCDIR)"
staticDir   := ../../opencv_MinGW/x64/mingw/staticlib/
#LIBDIR		:= $(staticDir)/libopencv_world460.a\
#			   $(staticDir)/libade.a \
#			   $(staticDir)/libIlmImf.a \
#			   $(staticDir)/libquirc.a \
#			   $(staticDir)/libzlib.a \
#			   $(wildcard $(staticDir)/liblib*.a) \
#			   -lgdi32 -lComDlg32 -lOleAut32 -lOle32 -luuid 
#opencv_world放弃前,然后是opencv依赖的第三方库,后面的库是MinGW编译工具的库

LIBDIR 	    := -L $(staticDir) -lopencv_world460 -lade -lIlmImf -lquirc -lzlib \
				-llibjpeg-turbo -llibopenjp2 -llibpng -llibprotobuf -llibtiff -llibwebp \
				-lgdi32 -lComDlg32 -lOleAut32 -lOle32 -luuid 
source		:= $(wildcard $(SRCDIR)/*.cpp) 

$(TARGET) :
	$(CX) $(FLAGS) $(INCLUDEDIR) $(source)  -o $(BIN)/$(TARGET) $(LIBDIR)

clean:
	rm  $(BIN)/$(TARGET)

编译如下:

程序运行输出如下,本测试没有指定视频图像,采用笔记本的摄像头抓取视频:

        PS:读者可以调整参数、图像光影效果等验证测试。

2.3 读取视频文件方式补充

PS:如果读取视频,有些格式(如mp4)需要视频动态库支持,记得把相关的视频动态库拷贝进来。

mingw:

 vc:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1991142.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于深度学习的地磁活动、扰动预测模型

注&#xff1a;包括SYM-H Index和Storm Intensity index A transformer-based framework for predicting geomagnetic indices with uncertainty quantification Journal of Intelligent Information Systems 18 November 2023 A transformer-based framework for predicting…

IP地址怎样实现安全的HTTPS访问?

IP实现HTTPS访问是一个涉及证书申请、服务器配置及网络安全的过程。以下是实现IP实现HTTPS访问的详细步骤&#xff1a; 公网IP地址的重要性&#xff1a;要实现HTTPS访问&#xff0c;必须拥有一个公网IP地址&#xff0c;这是从互联网直接访问网站的基础条件。 管理权限的必要性&…

高效批量提取PPT幻灯片中图片的方法

处理包含大量图片的PPT&#xff08;PowerPoint&#xff09;幻灯片已成为许多专业人士的日常任务之一。然而&#xff0c;手动从每张幻灯片中逐一提取图片不仅耗时耗力&#xff0c;还容易出错。为了提升工作效率&#xff0c;减少重复劳动&#xff0c;探索并实现一种高效批量提取P…

“网络信息安全”你真的了解吗?(非常详细)零基础入门到精通,收藏这一篇就够了

全面了解网络信息安全 01 导语&#xff1a; 在数字化浪潮中&#xff0c;我们每个人的生活都越来越依赖于网络。银行账户、个人隐私、企业机密——几乎所有的敏感信息都在网络上流转。随之而来的是不断升级的网络攻击和诈骗手段。本文将深入探讨网络信息安全的意义、挑战、防…

Candance Allegro 入门教程笔记:Cadence Allegro 17.4安装教程

文章目录 一、安装Cadence Allegro 17.4 安装包二、安装Candance Allegro Manager三、安装007号 补丁四、用阿狸狗破戒大师 破戒Candance Allegro 17.4软件 Cadence Allegro QQ交流学习裙&#xff1a;173416628 凡亿教育的Candance Allegro 17.4基础教程 小哥Cadence Allegro …

SSM伊犁旅游攻略网站—计算机毕业设计源码15961

目 录 摘要 1 绪论 1.1 开发背景 1.2开发意义 1.3ssm框架 1.4论文结构与章节安排 2 2 伊犁旅游攻略网站系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3数据删除流程 2.3 系统功能分析 2.3.1功能性分析 2.3.2非功能性分析…

48天笔试训练错题——day43

目录 选择题 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 编程题 1. 求和 选择题 1. synflood 是 syn 泛洪攻击。有一个恶意主机&#xff0c;伪造大量的 IP 地址&#xff0c;然后给服务器发送 SYN 请求&#xff0c;但是不进行第三次握手的回复&#xff0c;这样就会消耗服务器…

DITA发布MS Word样式定制

- 1 - 概述 上一期我们介绍了摩拿科技针对DITA发布PDF样式定制。 发布PDF通常能够满足大部分手册内容查看的需求&#xff0c;但是有时候公司的销售和服务部门的同事或者客户想要一个能修改的文件&#xff0c;这样可以做二次加工并生成自己想要的输出。这时候MS Word就能胜任…

SpringBoot中使用过滤器filter

过滤器Filter 在 Java 中&#xff0c;Filter&#xff08;过滤器&#xff09;是一种用于对请求进行预处理和后处理的机制。 工作原理&#xff1a; 当一个请求到达服务器时&#xff0c;会先经过一系列配置好的过滤器。过滤器可以检查请求的参数、头信息、请求体等内容&#xf…

buuctf CrackRTF (补)

另一种做题方式。 前言&#xff1a;学习笔记。 例题学习&#xff0c;涨大知识。 深入刨析&#xff0c;学习。 常规什么的这次就不写了&#xff0c;这篇wp主要是用于学习&#xff0c;以及分析。 以资料&#xff0c;代码理解&#xff0c;编程思维、编程手法等为主。 重在分析学…

php常见代码执行函数和常见系统命令执行函数。

PHP中常见代码执行函数&#xff1a; array_map() eval() assert() preg_replace() call_user_func() $a($b)动态函数 PHP中常见系统命令执行函数&#xff1a; system() exec() shell_exec() passthru() popen() 反引号"" 命令执行危险函数之assert函数…

成都云飞浩容文化传媒有限公司正规吗怎么样?

在数字经济的浪潮中&#xff0c;电商行业如日中天&#xff0c;成为推动经济增长的重要引擎。在这片蓝海中&#xff0c;如何脱颖而出&#xff0c;实现品牌与销量的双重飞跃&#xff1f;成都云飞浩容文化传媒有限公司&#xff0c;作为电商服务领域的佼佼者&#xff0c;正以专业的…

Echarts图表官网打开太慢怎么办?echarts.apache.org

1.ping官网&#xff0c;获取ip 使用 WIN R 输入cmd 进入命令控制台&#xff0c;ping 官网地址&#xff1a;echarts.apache.org 获取到的IP是 151.101.2.132 2.给hosts文件添加内容 使用文本编辑工具或编译器 打开 C:\Windows\System32\drivers\etc\hosts 文件&#xff0c;在最…

Linux基础知识之管理用户密码

往期系列内容回顾&#xff1a; Linux基础知识之Shell命令行及终端中的快捷键 Linux基础知识之man手册页_man 手册页-CSDN博客 Linux基础知识之Linux文件系统权限-CSDN博客 Linux基础知识之使用 Shell 扩展匹配文件名-CSDN博客 shadow 密码和密码策略 用户密码是Linux用户…

文件目录。

1、转换函数fileno和fdopen 一、文件目录 打开目录&#xff1a;opendir 读取目录&#xff1a;readdir&#xff1a;返回值是info&#xff08;目录中的一项内容&#xff09;&#xff0c;type表示类型是目录。 关闭目录&#xff1a;closedir 输出的是所有文件&#xff0c;包括隐…

[工具]-gitee+pycharm-配置

安装git ​ 查看git是否安装设置成功&#xff1a; ​ git config user.name ​ git config user.email ​ 码云账号设置邮箱 pycharm设置gitee 打开 PyCharm&#xff0c;在 Settings - Plugins 里面&#xff0c;搜索 Gitee 插件&#xff0c;安装后重启 PyCharm。 pychar…

Java设计模式(原型模式)

定义 使用原型实例指定待创建对象的类型&#xff0c;并且通过复制这个原型来创建新的对象。 角色 Prototype&#xff08;抽象原型角色&#xff09; ConcretePrototype&#xff08;具体原型角色&#xff09; Client&#xff08;客户端角色 优点 简化对象的创建过程&#xff0c…

Java网络编程、TCP、UDP、Socket通信---初识版

标题 InetAddress----IP地址端口号协议&#xff08;UDP/TCP&#xff09;JAVA操作-UDP一发一收模式多发多收 JAVA操作-TCP一发一收多发多收 实现群聊功能BS架构线程池优化 InetAddress----IP地址 端口号 协议&#xff08;UDP/TCP&#xff09; JAVA操作-UDP 一发一收模式 多发多收…

用Java手写jvm之模拟数组相关操作

写在前面 本文看下如何模拟数组相关的操作&#xff0c;主要是实现数组相关的指令&#xff0c;关于数组相关的指令可以参考这篇文章。 1&#xff1a;正文 简单起见这里我们仅仅实现int基础数据类型的一维数组。 newarray指令对应的类 package com.dahuyou.tryy.too.simulat…

猫咪不爱喝水又挑食,终于找到适合的补水罐

我已经被她搞疯掉了,养了快两年,特别不爱喝水。喂的是干粮&#xff0c;干粮本身就水少&#xff0c;加上她不爱喝水&#xff0c;我都怀疑它一天有没喝够20ml没有&#xff0c;太可怕了&#xff0c;只能拿针管喂。我看过很多科普,换过每天勤换水,水碗离猫粮很远,水碗不会太小不存在…