discuz 手机网站/百度一下你就知道下载安装
在计算机视觉领域,从图像中提取和匹配特征的能力对于对象识别、图像拼接和相机定位等任务至关重要。实现这一目标的一种流行方法是
ORB(Oriented FAST and Rotated Brief)特征检测器和描述符。ORB 由 Ethan Rublee
等人开发,结合了两种现有技术的优势——FAST(加速分段测试特征)和Brief(二进制鲁棒独立基本特征)——为特征提取和匹配提供了强大而高效的解决方案。
在本文中,我们将深入研究 ORB 的内部工作原理,探讨它如何充当特征检测器和描述符、其关键组件以及与其他特征提取方法相比的优势。
- FAST特征检测器:
加速分割测试的特征(Feature from Accelerated Segment
Test,FAST)算法是通过分析16个像素的圆形邻域来实现的。FAST算法把邻域内每个像素标记为比特定阈值更亮或更暗,该阈值是相对于圆心定义的。如果邻域包含若干标记为更亮或更暗的一系列连续像素,那么这个邻域就被视为角点。
FAST是一种角点检测算法,可以有效识别图像中的角点或关键点。通过利用简单的强度阈值方案和最小化计算,它的设计速度比传统的角点检测器更快。FAST 检查候选像素周围的一圈像素,如果有足够数量的连续像素比候选像素更亮或更暗,则将其分类为角点。
- BRIEF
另外,二值鲁棒独立基本特征(Binary Robust Independent Elementary
Feature,BRIEF)并非特征检测算法,而是一个描述符。我们来更深入地研究一下描述符的概念,然后再来研究BRIEF。
在前面用SIFT和SURF分析图像时,整个过程的核心是调用
detectAndCompute函数。此函数执行两个不同的步骤——检测和计算,它们返回2个不同的结果(耦合到一个元组中)。
检测结果是一组关键点,计算结果是这些关键点的一组描述符。这意味着OpenCV的cv2.SIFT和cv2.SURF类都实现了检测和描述算法。请记住,原始的SIFT和SURF不是特征检测算法。
OpenCV的cv2.SIFT实现了DoG特征检测和SIFT描述,而OpenCV的cv2.SURF实现了快速Hessian特征检测和SURF描述。
关键点描述符是图像的一种表示,充当特征匹配的通道,因为你
可以比较两幅图像的关键点描述符并发现它们的共性。BRIEF是目前最快的描述符之一。BRIEF背后的理论相当复杂,但是可以这样说,BRIEF采用一系列优化,使其成为特征匹配的一个非常好的选择。
蛮力匹配
蛮力匹配器是一个描述符匹配器,它比较两组关键点描述符并生成匹配列表。之所以称为蛮力匹配,是因为在该算法中几乎不涉及优化。对于第一个集合中的每个关键点描述符,匹配器将之与第二个集合中的每个关键点描述符进行比较。每次比较产生一个距离值,并基于最小距离选择最佳匹配。
概括地说,在计算中,“蛮力”一词是指将所有可能组合(例如,破解已知长度密码的所有可能的字符组合)的穷举按优先级排序的方法。相反,优先考虑速度的算法可能会跳过一些可能性,并试图走一条捷径来找到看似最合理的解决方案。
OpenCV提供了一个cv2.BFMatcher类,支持几种蛮力特征匹配的方法。
- ORB算法原理
ORB算法将FAST特征点的检测方法和BRIEF特征描述子结合起来,并在它们的基础上做了改进与优化。
首先,它利用FAST特征点检测的方法来检测特征点,然后利用Harris角点的度量方法,从FAST特征点中挑选出Harris角点响应值最大的N个特征点。其中Harris角点的响应函数定义为:
R=detM−k(trace(M))2
在现在生活中,我们从不同的距离,不同的方向、角度、不同的光照条件下观察一个物体时,物体的大小、形状,明暗都会有所不同。但是我们仍然可以判断它是一个物体。理想的特征描述子应该具备这些性质,即在大小、方向、明暗不同的图像中,同一特征点应具有足够相似的描述子,称之为描述子的可复现性。
但是ORB并没有解决尺度不一致的问题,在OpenCV的ORB实现中采用了图像金字塔来改善这方面的性能,我们通过构建高斯金字塔,然后在每一层金字塔图像上检测角点,来实现尺度不变性。ORB主要解决了BRIEF描述子不具备旋转不变性的问题,ORB论文种提出了一种利用灰度质心法来解决这个问题,灰度质心法假设角点的灰度与质心之间存在一个偏移,这个向量可以用于表示一个方向。对于任意一个特征点p来说,我们定义p的邻域像素的矩为:
其中I(x,y)为点(x,y)处的灰度值,q 为质心,i,j=0,1。那么我们可以得到图像的质心为:
那么特征点与质心的夹角定义为FAST特征点的方向:
为了提高算法的旋转不变性,需要确保 x 和 y 在半径为r 的圆形区域内,即x,y∈[−r,r],r 等于邻域半径。
特征点的描述
ORB选择了BRIEF作为特征描述方法,但是我们知道BRIEF不具备旋转不变性,所以我们要给BRIEF加上旋转不变性,把这种方法称为"Steer BRIEF"。 对于任何一个特征点来说,它的BRIEF描述子是一个长度为n的二值码串,这个二值码串是由特征点邻域n个点对生成的,我们现在讲这2n个点(xi,yi),i=1,2,…,2n组成一个矩阵S:
Calonder建议为每个块的旋转和投影集合分别计算BRIEF描述子,但代价昂贵。ORB中采用了一个更有效的方法:使用邻域方向θ和对应的转矩阵Rθ,构建S 的一个校正版本Sθ:
其中:
而θ 即我们为特征点求得的主方向。
即我们把坐标轴旋转]theta,计算以主方向为坐标系的匹配点对,如下图:
实际上,我们可以把角度离散化,即把360度分为12份,每一份是30度,然后我们对这个12个角度分别求得一个Sθ,这样我们就创建了一个查找表,对于每一个θ,我们只需要查表即可快速得到它的点的集合Sθ。
解决描述子的区分性
BRIEF令人惊喜的特性之一是:对于n维的二值串的每个特征位,所有特征点在该位上的值都满足一个均值接近于0.5,而方差很大的高斯分布。方差越大,说明区分性越强,那么不同特征点的描述子就表现出来越大差异性,对匹配来说不容易误配。但是当我们把BRIEF沿着特征点的方向调整为Steered BRIEF时,均值就漂移到一个更加分散式的模式。可以理解为有方向性的角点关键点对二值串则展现了一个更加均衡的表现。而且论文中提到经过PCA对各个特征向量进行分析,得知Steered BRIEF的方差很小,判别性小,各个成分之间相关性较大。
为了减少Steered BRIEF方差的亏损,并减少二进制码串之间的相关性,ORB使用了一种学习的方法来选择一个较小的点对集合。方法如下:
首先建立一个大约300k关键点的测试集,这些关键点来自于PASCAL2006集中的图像。
对于这300k个关键点中的每一个特征点,考虑它的31×31的邻域,我们将在这个邻域内找一些点对,不同于BRIEF中要先对这个Patch内的点做平滑,再用以Patch中心为原点的高斯分布选择点对的方法。
ORB为了去除某些噪声点的干扰,选择了一个5×5大小的区域的平均灰度来代替原来一个单点的灰度,这里5×5区域内图像平均灰度的计算可以用积分图的方法。我们知道31×31的Patch里共有N=(31−5+1)×(31−5+1)个这种窗口,那么我们要N个子窗口中选择2个子窗口的话,共有C2N种方法。所以对于300k中每一个特征点,我们都可以从它的31×31大小的邻域中提取一个很长的二进制串,长度为M=C2N,表示为:
那么当300k个关键点全部进行上面的特征提取之后,我们就得到了一个300k×M的矩阵,矩阵中的每个元素值为0或者1.
对该矩阵的每个列向量,也就是每个点对在300k个特征点上的测试结果,计算其均值。把所有的列向量按均值进行重新排序。排好后,组成了一个向量T,T的每一个元素都是一个列向量。进行贪婪搜索,从T中把排在第一的那个列放到R中,T中就没有这个点对的测试结果了,然后把T中的排在下一个的列与R中的所有元素比较,计算它们的相关性,如果相关超过了某一事先设定好的阈值,就扔了它,否则就把它方到R里面。
重复上面的步骤,直到R中有256个列向量位置。
如果把T全部找完也没有找到256个,那么我们可以把相关的阈值调高一些,再尝试一遍。这样,我们就得到了256个点对。上面这个过程我们称它为rBRIEF。
OpenCV实现
ORB中有很多参数可以设置,在OpenCV中它可以通过ORB来创建一个ORB检测器。
cv2.ORB_create([,nfeatues[,scaleFactor[,nlevels[,edgeThreshold[,firstLevel[,WTA_K[,[scoreType,[patchSize,fastThreshold]]]]]]]]])
参数说明:
- nfeatures :最多提取的特征点的数量;
- scaleFactor : 金字塔图像之间的尺度参数,类似于SIFT中的k;
- nlevels: 高斯金字塔的层数;
- edgeThreshold :边缘阈值,这个值主要是根据后面的patchSize来定的,靠近边缘edgeThreshold以内的像素是不检测特征点的。
- firstLevel-:看过SIFT都知道,我们可以指定第一层的索引值,这里默认为0。
- WET_K : 用于产生BIREF描述子的点对的个数,一般为2个,也可以设置为3个或4个,那么这时候描述子之间的距离计算就不能用汉明距离了,而是应该用一个变种。OpenCV中,如果设置WET_K = 2,则选用点对就只有2个点,匹配的时候距离参数选择NORM_HAMMING,如果WET_K设置为3或4,则BIREF描述子会选择3个或4个点,那么后面匹配的时候应该选择的距离参数为NORM_HAMMING2。
- scoreType :用于对特征点进行排序的算法,你可以选择HARRIS_SCORE,也可以选择FAST_SCORE,但是它也只是比前者快一点点而已。
- patchSize :用于计算BIREF描述子的特征点邻域大小。
示例:使用ORB描述符进行Brute-Force匹配:
示例代码:
import cv2def orb_test():# 加载图片 灰色img1 = cv2.imread('images\\quexiao\\2.png')gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)img2 = cv2.imread('images\\quexiao\\2-1.png')gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)image1 = gray1.copy()image2 = gray2.copy()'''1.使用ORB算法检测特征点、描述符'''orb = cv2.ORB_create(128)keypoints1, descriptors1 = orb.detectAndCompute(image1, None)keypoints2, descriptors2 = orb.detectAndCompute(image2, None)# 在图像上绘制关键点image1 = cv2.drawKeypoints(image=image1, keypoints=keypoints1, outImage=image1, color=(255, 0, 255),flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)image2 = cv2.drawKeypoints(image=image2, keypoints=keypoints2, outImage=image2, color=(255, 0, 255),flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)# 显示图像cv2.imshow('orb_keypoints1', image1)cv2.imshow('orb_keypoints2', image2)cv2.waitKey(20)'''2、匹配'''# 使用汉明距离,创建BF匹配器,并进行匹配() 新版本不支持# matcher = cv2.BFMatcher_create(cv2.HAMMING_NORM_TYPE, crossCheck=True)matcher = cv2.BFMatcher_create(cv2.NORM_HAMMING, crossCheck=True)matchePoints = matcher.match(descriptors1, descriptors2)print(type(matchePoints), len(matchePoints), matchePoints[0])# 按照距离从小到大排序,选取最优匹配的sorted(matchePoints, key=lambda x: x.distance)# 绘制最优匹配点outImg = NoneoutImg = cv2.drawMatches(img1, keypoints1, img2, keypoints2, matchePoints[:10], outImg, matchColor=(0, 255, 0),flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT)cv2.imshow('matche', outImg)cv2.waitKey(0)cv2.destroyAllWindows()cv2.waitKey(0)cv2.destroyAllWindows()if __name__ == '__main__':orb_test()
实验原图:
2.png
2-1.png
相关文章:

opencv 进阶16-基于FAST特征和BRIEF描述符的ORB(图像匹配)
在计算机视觉领域,从图像中提取和匹配特征的能力对于对象识别、图像拼接和相机定位等任务至关重要。实现这一目标的一种流行方法是 ORB(Oriented FAST and Rotated Brief)特征检测器和描述符。ORB 由 Ethan Rublee 等人开发,结合了…...

Unity 类Scene窗口相机控制
类Scene窗口相机控制 🍔效果 🍔效果 传送门👈...

juc基础(三)
目录 一、读写锁 1、读写锁介绍 2、ReentrantReadWriteLock 3、例子 4、小结 二、阻塞队列 1、BlockingQueue 简介 2、BlockingQueue 核心方法 3、案例 4、常见的 BlockingQueue (1)ArrayBlockingQueue(常用) (2)Li…...

c语言函数指针和指针函数的区别,以及回调函数的使用。
函数指针是什么,函数指针本质也是指针,不过是指向函数的指针,存储的是函数的地址。 指针函数是什么,指针函数其实就是返回值是指针的函数,本质是函数。 函数指针是如何定义的呢,如下 void (*pfun)(int a,int b) 这…...

什么是服务端渲染?前后端分离的优点和缺点?
一.概念 服务端渲染简单点就是服务端直接返回给客户端一个完整的页面,也就是一个完整的html页面,这个页面上已经有数据了。说到这里你可能会觉得后端怎么写页面啊,而且服务端返回页面不是加载更慢吗?错了,因为我们现在…...

【Java】优化重复冗余代码的8种方式
文章目录 前言1. 抽取公用方法2. 抽工具类3. 反射4.泛型5. 继承与多态6.使用设计模式7.自定义注解(或者说AOP面向切面)8.函数式接口和Lambda表达式 前言 日常开发中,我们经常会遇到一些重复代码。大家都知道重复代码不好,它主要有这些缺点:可…...

rabbitmq卸载重新安装3.8版本
卸载之前的版本的rabbitmq 卸载rabbitmq 卸载前先停止rabbitmq服务 /usr/lib/rabbitmq/bin/rabbitmqctl stop查看rabbitmq安装的相关列表 yum list | grep rabbitmq卸载rabbitmq相关内容 yum -y remove rabbitmq-server.noarch 卸载erlang 查看erlang安装的相关列表 …...

MyBatis分页思想和特殊字符
目录 一、MyBatis分页思想 1.1 使用场景 1.2 代码演示 二、MyBatis特殊字符 2.1代码演示 一、MyBatis分页思想 1.1 使用场景 Mybatis分页应用场景: MyBatis是一个Java持久层框架,它提供了一种将SQL查询和结果映射到Java对象的简单方式。分页是MyBa…...

设计模式大白话——命令模式
命令模式 一、概述二、经典举例三、代码示例(Go)四、总结 一、概述 顾名思义,命令模式其实和现实生活中直接下命令的动作类似,怎么理解这个命令是理解命令模式的关键!!!直接说结论是很不负责…...

[线程/C++(11)]线程池
文章目录 一、C实现线程池1. 头文件2. 测试部分 二、C11实现线程池1. 头文件2. 测试部分 一、C实现线程池 1. 头文件 #define _CRT_SECURE_NO_WARNINGS #pragma once #include<iostream> #include<string.h> #include<string> #include<pthread.h> #…...

VR防地质灾害安全教育:增强自然灾害知识,提高自我保护意识
VR防地质灾害安全教育系统是一种虚拟仿真技术,可以通过虚拟现实技术模拟地震、泥石流、滑坡等地质灾害的发生和应对过程,帮助人们提高应对突发自然灾害的能力。这种系统的优势在于可以增强自然灾害知识,提高自我保护意识,锻炼人们…...

Mybatis多对多查询案例!
在MyBatis中执行多对多查询需要使用两个主要表和一个连接表(通常称为关联表)来演示。在这个示例中,我们将使用一个示例数据库模型,其中有三个表:students、courses 和 student_courses,它们之间建立了多对多…...

Android OpenCV(七十五): 看看刚”转正“的条形码识别
前言 2021年,我们写过一篇《OpenCV 条码识别 Android 平台实践》,当时的条形码识别模块位于 opencv_contrib 仓库,但是 OpenCV 4.8.0 版本开始, 条形码识别模块已移动到 OpenCV 主仓库,至此我们无需自行编译即可轻松地调用条形码识别能力。 Bar code detector and decoder…...

数据结构——布隆计算器
文章目录 1.什么是布隆过滤器?2.布隆过滤器的原理介绍3.布隆过滤器使用场景4.通过 Java 编程手动实现布隆过滤器5.利用Google开源的 Guava中自带的布隆过滤器6.Redis 中的布隆过滤器6.1介绍6.2使用Docker安装6.3常用命令一览6.4实际使用 1.什么是布隆过滤器…...

金融学复习博迪(第6-9章)
第6章 投资项目分析 学习目的:解释资本预算;资本预算基本法则 资本预算过程包含三个基本要素: 一提出针对投资项目的建议 一对这些建议进行评价 一决定接受和拒绝哪些建议 6.1项目分析的特性 资本预算的过程中的基本单位是单个的投资项目。投…...

解决idea登录github copilot报错问题
试了好多方案都没用,但是这个有用, 打开idea-help-edit custonm vm options 然后在这个文件里面输入 -Dcopilot.agent.disabledtrue再打开 https://github.com/settings/copilot 把这个设置成allow,然后重新尝试登录copilot就行就行 解决方…...

什么是Flex布局?请列举一些Flex布局的常用属性。
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ Flex布局(Flexible Box Layout)⭐ Flex布局的常用属性⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之…...

React + TypeScript + antd 常见开发场景
时间戳转格式 // 获取当前时间戳(示例) const timestamp Date.now(); // 或者使用特定的时间戳值// 创建一个新的Date对象,并传入时间戳 const date new Date(timestamp);// 获取年、月、日的值 const year date.getFullYear(); const mon…...

前端基础踩坑记录
前言:在做vue项目时,有时代码没有报错,但运行时却各种问题,没有报错排查起来就很费劲,本人感悟:写前端,需要好的眼神!!!谨以此博客记录下自己的踩坑点。 一、…...

k8s删除pod镜像没响应marking for deletion pod TaintManagerEviction
使用命令强制删除 Pod的状态为"Marking for deletion"表示该Pod正在被标记为待删除状态,但实际上并没有被删除。这可能是因为以下原因之一: 删除操作被阻塞:可能是由于某些资源或容器正在使用该Pod,导致删除操作被阻塞…...

Nginx 使用 lua-nginx-module 来获取post请求中的request和response信息
如果想要在nginx中打印出 http request 的所有 header,需要在编译nginx时开启 1、安装编译所需的依赖 apt-get install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev2、创建下载路径 mkdir -p /opt/download3、下载所需的文件 # 不要下载…...

【Opencv】三维重建之cv::recoverPose()函数(1)
官网链接 从估计的本质矩阵和两幅图像中的对应点恢复相机之间的旋转和平移,使用光束法则进行检验。返回通过检验的内点数目。 #include <opencv2/calib3d.hpp>int cv::recoverPose ( InputArray E, InputArray points1, InputArray points2, InputArray …...

Perl兼容正则表达式函数-PHP8知识详解
在php8中有两类正则表达式函数,一类是perl兼容正则表达式函数,另一类是posix扩展正则表达式函数。二者区别不大,我们推荐使用Perl兼容正则表达式函数。 1、使用正则表达式对字符串进行匹配 用正则表达式对目标字符串进行匹配是正则表达式的主…...

Python处理空值NaN
fork_address_tempread_excel_column_to_list(./eqp_info.xls,Sheet1,车辆地址)for i in fork_address_temp:print(type(i))fork_address[0 if address nan else address for address in fork_address_temp]fork_address结果 <class float><class float><class…...

软件机器人助力交通运输局数据录入,实现高效管理
随着科技的迅速发展,许多传统的行业正在寻求通过科技创新优化工作流程、提升效率。在这样的大背景下,交通运输部门也开始注重引入科技手段改善工作流程。博为小帮软件机器人正逐步改变着交通运输局的工作方式。 软件机器人:交通管理的利器 博…...

时序分解 | MATLAB实现基于SGMD辛几何模态分解的信号分解分量可视化
时序分解 | MATLAB实现基于SGMD辛几何模态分解的信号分解分量可视化 目录 时序分解 | MATLAB实现基于SGMD辛几何模态分解的信号分解分量可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 SGMD分解算法(辛几何模态分解),分解结果可视…...

FinalShell报错:Swap file “.docker-compose.yml.swp“ already exists
FinalShell中编辑docker-compose.yml文件,保存时报错:Swap file ".docker-compose.yml.swp" already exists;报错信息截图如下: 问题原因:有人正在编辑docker-compose.yml文件或者上次编辑没有保存ÿ…...

卷积过程详细讲解
1:单通道卷积 以单通道卷积为例,输入为(1,5,5),分别表示1个通道,宽为5,高为5。假设卷积核大小为3x3,padding0,stride1。 卷积过程如下: 相应的卷积核不断…...

代码随想录第五十六天
代码随想录第五十六天 Leetcode 583. 两个字符串的删除操作Leetcode 72. 编辑距离 Leetcode 583. 两个字符串的删除操作 题目链接: 两个字符串的删除操作 自己的思路:想到了,但是初始化初始错了!!!! 思路1:直接动规五…...

.NET 最便捷的Log4Net日志记录器
最便捷的Log4Net使用方法 LOG4NET 配置日志记录器开始引用nuget LOG4NET 配置日志记录器 Apache log4net 库是一个帮助程序员将日志语句输出到各种的工具 的输出目标。log4net是优秀的Apachelog4j™框架的移植 Microsoft.NET 运行时。我们保持了与原始log4j相似的框架 同时利…...