OpenCV实战——二值特征描述符

news2024/12/24 8:16:43

OpenCV实战——二值特征描述符

    • 0. 前言
    • 1. ORB 和 BRISK 二值描述符
      • 1. ORB 特征描述符
      • 1.2 ORB 与 BRISK 算法
    • 2. FREAK 二值描述符
    • 3. 二值描述符采样模式
    • 4. 完整代码
    • 相关链接

0. 前言

在《特征描述符》一节中,我们学习了如何使用从图像强度梯度中提取的描述符来描述关键点,这些描述符可以是 64128 或更多维的浮点向量。这使得使用这些描述符的算法计算代价较高,为了减少与这些描述符相关的内存和计算负载,引入了二值描述符,使它们易于计算的同时保持对场景和视角变化的鲁棒性。本节,我们将学习一些常见的二值描述符,包括 ORB (Oriented FAST and Rotated BRIEF)和 BRISK (Binary Robust Invariant Scalable Keypoints) 描述符。

1. ORB 和 BRISK 二值描述符

1. ORB 特征描述符

由于在 OpenCV 检测器和描述符模块顶层定义了通用接口,使用 ORB 等二值描述符与使用 SURF 和 SIFT 等描述符并没有什么不同。

(1) 首先,定义关键点向量:

std::vector<cv::KeyPoint> keypoints1;
std::vector<cv::KeyPoint> keypoints2;

(2) 创建 cv::Mat 结构存储描述符:

cv::Mat descriptors1;
cv::Mat descriptors2;

(3) 创建指向 ORB 检测器的指针:

cv::Ptr<cv::Feature2D> feature = cv::ORB::create(60);

(4) 检测并计算每个图像的关键点和描述符:

feature->detectAndCompute(image1, cv::noArray(), keypoints1, descriptors1);
feature->detectAndCompute(image2, cv::noArray(), keypoints2, descriptors2);

(5) 创建匹配器,并匹配两个图像描述符:

// 构建检测器
cv::BFMatcher matcher(cv::NORM_HAMMING);
// 匹配两张图像描述符
std::vector<cv::DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);

在匹配器中使用汉明范数 (cv::NORM_HAMMING 标志),通过计算对应位置值不同的位数来测量两个二值描述符之间的距离。在多数处理器上,通过使用异或运算和位计数可以高效地实现此操作。
匹配的结果如下图所示:

二值特征描述符匹配结果
使用另一种流行的二元特征检测器/描述符 BRISK 可以得到类似的结果,只需调用 cv::BRISK(40) 创建 cv::DescriptorExtractor 实例,cv::BRISK() 的第一个参数是一个用于控制检测点数量的阈值。

1.2 ORB 与 BRISK 算法

ORB 算法在多个尺度上检测定向特征点,基于这个结果,ORB 描述符通过使用强度比较来提取每个关键点的表示。ORB 的构建基于 BRIEF (Binary Robust Invariant Scalable Keypoints) 描述符,通过选择关键点周围定义的邻域内的一对随机点创建二值描述符,然后比较两个像素点的强度值,如果第一个点的强度更高,则将值 1 分配给相应的描述符位值,否则,赋值为 0。对多个随机点对重复以上比较过程可以得到由多个二进制位组成的描述符;通常,使用 128512 位。
ORB 使用以上方案,接下来要决定使用哪组点对来构建描述符,即使点对是随机选择的,一旦它们被选中,就必须执行二值测试来构建所有关键点的描述符,以确保结果的一致性。为了使描述符更加独特,它们必须具有可比较性。此外,由于每个关键点方向的确定性,当强度模式分布相对于该方向被归一化时(即当点坐标相对于该关键点方向给出时),会在强度模式分布中引入一些偏差。根据这些考虑和实验验证,ORB 确定了一组具有高方差和最小相关性的 256 个点对。换言之,所选的二值测试在各种关键点上有相等机会为 01,即尽可能彼此独立的测试。
除了控制特征检测过程的参数外,cv::ORB 构造函数还包括两个与其描述符相关的参数。第一个参数用于指定在其中选择点对的图像块大小(默认值为 31x31);第二个参数用于指定使用三元组或四元组点而非默认的点对执行测试。
BRISK 的描述符与 ORB 非常相似,但其强度比较方法具有以下两个主要差异。首先,BRISK并不是从邻域的 31x31 点中随机选择点,而是从具有等距位置的一组同心圆(由 60 个点组成)中选择点;其次,每个样本点的强度是一个高斯平滑值,其 σ 值与到中心关键点的距离成正比,从这些点中,BRISK 选择 512 个点对。

2. FREAK 二值描述符

除了以上二值描述符外,在 OpenCV 中也实现了其他二值描述符,接下来,我们将介绍另一个描述符 FREAK
FREAK (Fast Retina Keypoint) 也是一个二值描述符,但它没有关联的检测器,可以应用于检测到的任何一组关键点,例如 SIFTSURFORB。与 BRISK 一样,FREAK 描述符也基于同心圆上定义的采样模式。但其设计思想借鉴了人眼的工作原理,在视网膜上,神经细胞的密度程度随着到中央凹距离的增加而降低。因此,FREAK 构建了一个由 43 个点组成的采样模式,其中点的密度在中心点附近较多,为了获得其强度,每个点都用高斯核滤波,高斯核的大小也随着到中心的距离而增加。
为了确定成对比较的数量,通过遵循类似于 ORB 的策略进行了实验验证。通过分析数千个关键点,保留了方差最大和相关性最低的二值测试,得到最佳比较数量为 512 对。
FREAK 还引入了级联执行描述符比较的想法。也就是说,首先执行表示粗粒度信息的前 128 位(对应于在外围对较大高斯核进行的测试),只有当比较的描述符通过这个初始步骤时,才会执行剩余的测试。
使用 ORB 检测到的关键点,通过创建 cv::DescriptorExtractor 实例来提取 FREAK 描述符:

feature = cv::xfeatures2d::FREAK::create();

匹配结果如下所示:

FREAK 二值特征描述符匹配结果

3. 二值描述符采样模式

下图说明了本节中介绍的三个二值描述符的采样模式:

采样模式
第一个采样模式表示 ORB 描述符,其在正方形网格上随机选择点对,每对由一条线连接的点代表一个可能的测试来比较两个像素强度,上图中只展示了八个这样的点对,ORB 默认使用 256 对;第二个表示 BRISK 采样模式,点在显示的圆圈上均匀采样(为清楚起见,我们在图中只标示了第一个圆圈上的点);第三个表示 FREAK 的对数极坐标采样网格,BRISK 的点分布均匀,而 FREAK 靠近中心的点密度更高,例如,在 BRISK 中,可能在外圆上找到 20 个点,而在 FREAK 中,外圆可能仅包含 6 个点。

4. 完整代码

完整代码 binaryDescriptors.cpp 如下所示:

#include <iostream>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/xfeatures2d.hpp>

int main() {
    // 图像匹配
    // 1. 读取图像
    cv::Mat image1 = cv::imread("1.png", cv::IMREAD_GRAYSCALE);
    cv::Mat image2 = cv::imread("2.png", cv::IMREAD_GRAYSCALE);
    // 2. 定义关键点向量和描述符
    std::vector<cv::KeyPoint> keypoints1;
    std::vector<cv::KeyPoint> keypoints2;
    cv::Mat descriptors1;
    cv::Mat descriptors2;
    // 3. 定义特征检测器/描述符
    cv::Ptr<cv::Feature2D> feature = cv::ORB::create(60);
    // cv::Ptr<cv::Feature2D> feature = cv::BRISK::create(80);
    // 4. 关键点检测及描述符
    feature->detectAndCompute(image1, cv::noArray(), keypoints1, descriptors1);
    feature->detectAndCompute(image2, cv::noArray(), keypoints2, descriptors2);
    // 绘制特征点
    cv::Mat featureImage;
    cv::drawKeypoints(image1,keypoints1,featureImage,cv::Scalar(255,255,255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
    cv::namedWindow("ORB");
    cv::imshow("ORB",featureImage);
    std::cout << "Number of ORB keypoints (image 1): " << keypoints1.size() << std::endl; 
    std::cout << "Number of ORB keypoints (image 2): " << keypoints2.size() << std::endl;
    // FREAK
    // feature = cv::xfeatures2d::FREAK::create();
	// feature->compute(image1, keypoints1, descriptors1);
	// feature->compute(image1, keypoints2, descriptors2);
    // 构建检测器
    cv::BFMatcher matcher(cv::NORM_HAMMING);
    // 匹配两张图像描述符
    std::vector<cv::DMatch> matches;
    matcher.match(descriptors1, descriptors2, matches);
    // 绘制匹配
    cv::Mat imageMatches;
    cv::drawMatches(image1, keypoints1,         // 第一张图像及其关键点
                    image2, keypoints2,         // 第二张图像及其关键点
                    matches,                    // 匹配
                    imageMatches,               // 生成结果
                    cv::Scalar(255, 255, 255),  // 线颜色
                    cv::Scalar(255, 255, 255),  // 点颜色
                    std::vector<char>(),        // 掩码
                    cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS | cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
    cv::namedWindow("ORB Matches");
    cv::imshow("ORB Matches", imageMatches);
    // cv::namedWindow("FREAK Matches");
    // cv::imshow("FREAK Matches", imageMatches);
    std::cout << "Number of matches: " << matches.size() << std::endl; 
    cv::waitKey();
    return 0;
}

相关链接

OpenCV实战(1)——OpenCV与图像处理基础
OpenCV实战(2)——OpenCV核心数据结构
OpenCV实战(3)——图像感兴趣区域
OpenCV实战(4)——像素操作
OpenCV实战(5)——图像运算详解
OpenCV实战(6)——OpenCV策略设计模式
OpenCV实战(7)——OpenCV色彩空间转换
OpenCV实战(8)——直方图详解
OpenCV实战(9)——基于反向投影直方图检测图像内容
OpenCV实战(10)——积分图像详解
OpenCV实战(11)——形态学变换详解
OpenCV实战(12)——图像滤波详解
OpenCV实战(13)——高通滤波器及其应用
OpenCV实战(14)——图像线条提取
OpenCV实战(15)——轮廓检测详解
OpenCV实战(16)——角点检测详解
OpenCV实战(17)——FAST特征点检测
OpenCV实战(18)——特征匹配

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

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

相关文章

ChatGPT使用学习(一):chatgpt_academic安装到测试详细教程(一文包会)

ChatGPT 1.简介及功能2.前置准备3.开始使用 1.简介及功能 Chargpt academic是一种基于OpenAI GPT模型的语言生成模型&#xff0c;它是专门为学术研究者和学生设计的。它使用预训练模型来生成与学术论文、文章和文献相关的文本&#xff0c;可以用于自然语言处理、机器翻译、文本…

SpringBoot整合Redis,一篇带你入门使用Redis

本文介绍如何将Redis整合到SpringBoot项目中&#xff0c;以及如何配置、封装和使用 文章目录 前言环境搭建项目结构添加依赖 Module封装RedisConfig配置封装常见操作为ServiceRedisServiceRedisLockUtil 测试 前言 参考链接&#xff1a; 英文官网链接中文官网链接Redis githu…

vue项目使用RSA加解密

vue项目使用RSA加解密 1.安装2.在utils下创建rsa.js3.在main.js中引入4.页面调用5.遇到的问题 1.安装 使用一下命令安装jsencrypt插件 npm install jsencrypt --save-dev npm i encryptlong -S注意&#xff1a; &#xff08;1&#xff09;上述插件不支持在小程序中使用&#…

python大数据作业-客户价值分析-实训头歌

一、实验目的与要求 1、掌握使用numpy和pandas库处理数据的基本方法。 2、掌握使用RFM分析模型对客户信息进行特征提取的基本方法。 3、掌握对特征数据进行标准化处理的基本方法。 4、掌握使用Sklearn库对K-Means聚类算法的实现及其评价方法。 5、掌握使用matplotlib结合panda…

【2】YOLOv8原理解析:重新定义实时目标检测的速度和精度

文章目录 0.前言1.YOLOv51.1 YOLOv5网络回顾1.2 YOLOv5网络结构图 2.YOLOv82.1 YOLOv8概述2.2 YOLOv8整体结构图2.3 YOLOv8yaml 文件与 YOLOv5yaml 文件对比2.3.1 参数部分2.3.2 主干部分2.3.3 Neck部分2.3.4 Head部分 2.4 正负样本分配策略2.4.1 静态分配策略和动态分配策略有…

机器学习实战:Python基于SVD奇异值分解进行矩阵分解(八)

文章目录 1 前言1.1 奇异值分解1.2 奇异值分解的应用 2 简单计算SVD2.1 NumPy 计算 SVD2.2 scikit-learn 计算截断 SVD2.3 scikit-learn 计算随机 SVD 3 demo数据演示3.1 导入函数3.2 导入数据3.3 计算SVD 4 讨论 1 前言 1.1 奇异值分解 奇异值分解&#xff08;Singular Valu…

【李老师云计算】实验二:Spark集群的搭建与求解最大值

索引 前言1. Spark部署1.1 下载Spark1.2 解压Spark1.3 修改环境变量1.4 修改主机Spark配置文件1.4.1 slaves.template文件配置1.4.2 spark-env.sh.template文件配置 1.5 分享主机Spark到从机1.6 启动Spark集群(★重启后的操作)1.7 通过jps查看是否启动成功1.8 通过网页查看是否…

Vue+Echarts 项目演练(上)整体页面结构的构建

项目分辨率响应式创建 项目顶部信息条创建 页面主体创建 接项目搭建与初始化之后继续对项目进行部署工作 项目展示&#xff1a; 技术栈&#xff1a; 1. vue3.0vue-router4.0axios 2. flex 布局 3. LESS 4. rem 屏幕适配 5. echarts5.0 项目分辨率响应式创建 对插件…

centos 8 配置LVS+ keepalived 高可用

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的绽放&#xff0…

3105—IIS部署

一、部署子站点 1—父站点web.config配置 新增并设定location段落 <configuration><location path"." allowOverride"false" inheritInChildApplications"false"><system.webServer><handlers><add name"aspNe…

【Matlab】基于紧格式动态线性化的无模型自适应控制

例题来源&#xff1a;侯忠生教授的《无模型自适应控制&#xff1a;理论与应用》&#xff08;2013年科学出版社&#xff09;。 对应书本 4.2 单输入单输出系统(SISO)紧格式动态线性化(CFDL)的无模型自适应控制(MFAC) 例题4.1 题目要求 matlab代码 clc; clear all;%% 期望轨迹…

neo4j jdk安装版本搭配

jdk下载版本为jdk11 neo4j 为neo4j-community-4.3.15 可使用 非常流畅 没有毛病&#xff01;&#xff01;&#xff01; 这里直接给出结论&#xff0c;对于想知道这两个版本为什么适配的小伙伴可以继续往下看 出现这个界面后在网页打开browser 输入账号和密码后就可以登录了&…

【架构设计】什么是CAP理论?

1、理论 CAP理论是指计算机分布式系统的三个核心特性&#xff1a;一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;和分区容错性&#xff08;Partition Tolerance&#xff09;。 在CAP理论中&#xff0c;一致性指的是多个节点上的数据…

Vector - CAPL - CANoe硬件配置函数 - 01

CAN ACK自应答 在测试CAN&CANFD通信或者网络管理的时候&#xff0c;我们经常遇到使用报文&#xff08;网络管理报文或者通信报文&#xff09;唤醒被测件这个测试点&#xff0c;如果测试比较多的情况下&#xff0c;我们就会发现&#xff0c;如果CANoe没有接被测件或者被测件…

Python标准数据类型-Number(数字)

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1 &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;零基础入门篇 &#x1f4ac;个人格言&#xff1a;不断的翻越一座又一座的高山…

《Java集合》ConcurrentSkipListMap

目录 数据结构findPredecessordoGetdoRemovedoPut新值插入底层创建新值的索引连接索引 数据结构 java源码中对ConcurrentSkipListMap的描述如下&#xff1a; 图中&#xff0c;第0层为具体的数据&#xff0c;第1层的每一个node都有两个子node&#xff0c;一个指向同层的右边&am…

kong(3):动态负载均衡实现

nginx下负载均衡配置 upstream tulingmall-product-upstream {server 192.168.65.190:8866 weight100;server 192.168.65.190:8867 weight100; } server {listen 80;location /pms/ {proxy_pass http://tulingmall-product-upstream;} } 通过 Kong Admin API 进行上述的负载均…

srm采购管理系统有那些功能

srm采购管理系统&#xff0c;是通过系统的手段对采购过程进行管理和控制&#xff0c;实现降低成本、提高效益、提高企业核心竞争力的目的。那么 srm采购管理系统有哪些功能呢&#xff1f; 计划管理 srm采购管理系统提供了各种物料需求计划的功能&#xff0c;以帮助企业制定并控…

前端项目实战:网易云静态页面——导航栏

文章目录 一、实现目标二、顶部实现&#xff08;背景为黑色部分&#xff09;1. 内容布局2. 左边部分网易云logo左边的列表列表元素高亮指向每个列表元素的小红色三角“下载客户端”后的hot标志 3. 右边部分登陆创作者中心搜索 三、底部实现&#xff08;背景为红色部分&#xff…

Echarts 项目演练(上)整体页面结构的构建

项目分辨率响应式创建 项目顶部信息条创建 页面主体创建 接项目搭建与初始化之后继续对项目进行部署工作 项目展示&#xff1a; 技术栈&#xff1a; 1. vue3.0vue-router4.0axios 2. flex 布局 3. LESS 4. rem 屏幕适配 5. echarts5.0 项目分辨率响应式创建 对插件…