问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 39 人浏览分享

开启左侧

ORB特征提取与匹配介绍

[复制链接]
39 0
本帖最后由 石桥断雪 于 2025-9-25 16:13 编辑

第一章 ORB的算法原理
3.1简介
ORBOriented FAST and Rotated BRIEF) 由 Ethan Rublee 2011 年提出,是 SIFT SURF 的免费替代方案,适用于实时应用和嵌入式设备。ORB算法分为两部分,分别是特征点提取和特征点描述。ORB特征是将FAST特征点的检测方法与BRIEF特征描述子结合起来,并在它们原来的基础上做了改进与优化。其速度是SIFT100倍,是SURF10倍。总之,ORB 基本上是 FAST 关键点检测器和 BRIEF 描述符的融合,并进行了许多改进以增强性能。它首先使用 FAST 查找关键点,然后应用 Harris 角点测量来找到其中排名前 N 的点。它还使用金字塔来生成多尺度特征。

2.2FAST算法
3.2.1 提取FAST特征点
FAST Features from Accelerated Segments Test 的简称,首先理解什么是FAST角点。FAST角点即,若某像素与其周围邻域内足够多的像素点相差较大,则该像素可能是角点。在平坦的图上,周围的像素点应该和中心点的差距是比较小;在边缘上,周围的像素点应该一半差距比较大,一半基本上没有差距;而在角点上,应该时大多数的差距比较大,而少数的差距比较小。
image.jpg
1. 选定一个像素点pp的亮度记作lp
2. p为圆心,半径为3的圆上有1-16的像素点,记作p1-p16,亮度记作lp1-lp16
3. 确定一个阈值t,计算p1p5p9p13上下左右四个方向上的像素点与p的亮度差。如果绝对值有至少3个超过阈值t,则当做候选角点,否则,不认为是角点。这里提前淘汰的操作就是orb的加速策略,使得整个图像中搜索关键点的时间缩短了四倍。
4. p是候选角点的前提下,进行完整16点检测,若存在连续的12个点满足阈值条件,则判定pp为角点。
5. 对整个图像进行步骤1-4的角点检测。
6. FAST检测出的每个特征点进行NMS,去除小区域内多个重复的特征点。这里非极大值抑制(NMS)具体步骤为计算特征点出的FAST得分值,公式如下:
image.jpg
计算出的V值为16个点与中心差值的绝对值总和,也叫做响应值可以反映角点强度,值越大特征越显著。之后,以当前角点pp为中心建立邻域,比较邻域内所有角点的V值,仅保留最大值对应的角点,若只有单个特征点就直接保留。

3.2.2 Harris角点筛选
Harris角点筛选的‌目的是从FAST初筛结果中选择质量最高的特征点。为了进一步提高关键点的质量和稳定性,使检测出的关键点更具有代表性和鲁棒性,对FAST检测出的候选点计算Harris响应值R,并按R值排序所有候选点,最终保留前N个最优特征点。Harris的计算公式如下:
image.jpg
其中M是二阶矩矩阵:

image.jpg
在初步检测阶段,FAST算法快速扫描图像,计算各点V值,此时仅使用V值进行二值判断。之后在优化筛选阶段对FAST检测出的候选点计算Harris响应值R,来优化选择‌高质量特征点。

3.2.3Oriented FAST
Fast角点本不具有方向,由于特征点匹配需要,ORBFast角点进行了改进,改进后的 FAST 被称为 Oriented FAST,具有旋转和尺度的描述,用来解决尺度不变性和旋转不变性。
ORB通过金字塔来实现旋转不变性,包括对图像做不同尺度的高斯模糊,对图像做降采样(隔点采样),对每层金字塔做FAST特征点检测,将n幅不同比例的图像提取特征点总和作为这幅图像的oFAST特征点。
ORB通过确定一个特征点的方向来实现旋转不变性,ORB的论文中提出了一种利用灰度质心法来确定特征点的方向,通过计算一个矩来计算特征点以r为半径范围内的质心,特征点坐标到质心形成一个向量作为该特征点的方向,用于确保后续rBRIEF描述符具有旋转不变性
首先介绍灰度法:
1. 取关键点周围一个固定大小的图像块,对应的矩的元素表达为:
image.jpg
xy为坐标值,Ixy)为像素值

2. 计算图像块的质心位置,该图像的质心为。
image.jpg
3. 找到了质心,特征点与质心的夹角OC就可以计算(其中O是图像块中心),并定义为FAST特征点的方向。
image.jpg
有了特征点的方向,就实现了旋转不变性。

3.3BRIEF描述子
3.3.1 BRIEF描述子简介
BRIEF在2010年的一篇名为BRIEF:Binary Robust Independent Elementary Features的文章中提出,通过不使用传统区域灰度直方图描述特征点方法,加快了特征描述符建立的速度,同时降低了特征匹配的时间,是一种非常快速的算法。BRIEF算法通过比较特征点周围像素对的强度值来生成二进制描述符。在BRIEF中每个关键点由一个二元特征向量描述,该向量一般为128-512位的字符串,其中仅包含10

3.3.2 BRIEF步骤
1. 为减少噪声干扰,先对图像采用了9x9的高斯算子进行滤波,但一个滤波并不够解决噪声敏感问题。ORB利用了积分图像来解决:在31x31的窗口中,产生一对随机点后,以随机点为中心,取5x5的子窗口,比较两个子窗口内的像素和的大小进行二进制编码,而非仅仅由两个随机点决定二进制编码。
2. 以特征点为中心,取SxS的邻域窗口。在窗口内随机选取一对(两个)点,比较二者像素的大小,进行如下二进制赋值。公式如下,p(x)p(y)分别是随机点x=(u1,v1),y=(u2,v2)的像素值。
image.jpg
3. 在窗口中随机选取N对随机点,重复步骤2的二进制赋值,然后比较每个点对的灰度值的大小。如果I(pi)> I(qi),则生成二进制串中的1,否则为0。所有的点对都进行比较,则生成长度为n的二进制串,通常n=256I(pi)表示特征点邻域内某个特定像素点pi的灰度强度值)。
而如何在点周围随机选取N对随机点,原始的BRIEF算法有五种方式:
1. 在图像块内平均采样
2. pq都符合(0,S2/25)的高斯分布
3. p符合(0,S2/25)的高斯分布,q符合(0,S2/100)的高斯分布
4. 在空间量化极坐标下的离散位置随机采样;
5. p固定为(0,0)q在周围平均采样。
image.jpg
ORB的作者采用了一种全新的方式,基于学习优化的带你对选择策略,称为rBRIEF
3.3.3rBRIEF(Rotated BRIEF)
rBRIEFBRIEF的改进版本,通过灰度质心法计算特征点主方向,并旋转采样坐标系实现旋转不变性。通过统计学习方法从300k个特征点训练集中学习最优的256个点对组合,选择具有最高方差和最低相关性的点对。从而找出所谓的全局最优点对序列。具体步骤为:
1. 首先建立300k个特征点测试集。对于测试集中的每个点,考虑其31x31邻域。
2. 300k特征点的每个31x31邻域内按M种方法取点对,比较点对大小,形成一个300kxM的二进制矩阵Q。矩阵的每一列代表300k个点按某种取法得到的二进制数。
3. Q矩阵的每一列求取平均值,按照平均值到0.5的距离大小重新对Q矩阵的列向量排序,形成矩阵T
4. T的第一列向量放到R中。
5. T的下一列向量和R中的所有列向量计算相关性,如果相关系数小于设定的阈值,则将T中的该列向量移至R
6. 按照步骤5的方式不断进行操作,直到R中的向量数量为256
这样就选取了这256种取点对的方法。这就是rBRIEF算法。


第二章 ORB的核心代码分析
4.1ORB特征提取
# 读取图片
i1 = cv2.imread('test.png', 0)
i2 = cv2.imread('test2.png', 0)

# 初始化ORB检测器
orb = cv2.ORB_create()

# 检测关键点和描述符
kp1, des1 = orb.detectAndCompute(i1, None)
kp2, des2 = orb.detectAndCompute(i2, None)


创建ORB特征检测器实例的函数以及默认参数如下:
cv2.ORB_create(nfeatures = 500, scaleFactor = 1.2,nlevels = 8, edgeThreshold = 31, firstLevel = 0, WTA_K = 2, scoreType = HARRIS_SCORE,patchSize = 31, fastThreshold = 20)
这些参数的含义为
1. nfeatures:保留的最大特征数(默认为500)
2. scaleFactor:金字塔缩放因子(默认1.2)
3. nlevels:金字塔层数(默认8)
4. edgeThreshold:边界阈值(默认31)
5. firstLevel:金字塔起始层(默认0)
6. WTA_K:产生描述符的采样点数(默认2)
7. scoreType:指定特征点排序的评分算法。这里ARRIS_SCORE基于Harris角点检测原理,通过计算角点响应函数(结合图像二阶矩矩阵)对特征点进行质量排序,保留响应值高的特征点。
8. patchSize:定义计算BRIEF描述子时使用的邻域窗口大小。默认值31表示以关键点为中心,取31×31像素的邻域区域生成二进制描述符。
以kp1, des1 = orb.detectAndCompute(i1, None)为例,i1是读取的图像,orb.detectAndCompute表示对输入图像i1执行特征检测与描述符计算,None表示不使用掩膜。返回的kp1是检测到的关键点列表,每个关键点包含:坐标(x,y),特征区域直径,特征方向(0-360),关键点强度,发现关键点的金字塔层级,对象IDdes1是关键点描述符矩阵。对图像i2处理的步骤相同,这样有了关键点和描述符,就可以进行下一步的特征匹配。





4.2 BFMatcher(暴力匹配)
BFMatcher暴力匹配又被称作交叉匹配,算法的思想简单而有效,步骤如下:
1. 取第一幅图像中的一个特征点
2. 与第二幅图像中的所有特征点进行匹配
3. 返回最佳匹配结果

BFMatcher 对象有两个方法,BFMatcher.match() BFMatcher.knnMatch()BFMatcher.match() 方法的代码如下:
import cv2
import numpy as np

# 读取图片
i1 = cv2.imread('test.png', 0)
i2 = cv2.imread('test2.png', 0)

# 初始化ORB检测器
orb = cv2.ORB_create()

# 检测关键点和描述符
kp1, des1 = orb.detectAndCompute(i1, None)
kp2, des2 = orb.detectAndCompute(i2, None)

# 使用BFMatcher进行匹配
if des1 is not None and des2 is not None:
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False)
    maches = bf.match(des1, des2)

    maches = sorted(maches, key=lambda x: x.distance)

    # 绘制匹配结果
    result = cv2.drawMatches(i1, kp1, i2, kp2, maches[: 100], i2, flags=2)
    cv2.imshow('ORB匹配结果', result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
else:
    print('未检测到特征点,无法进行匹配。')

cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False) 创建一个 BFMatcher 对象。它有两个可选参数。第一个参数是normType,即要使用的距离测试类型。这里对于二进制描述符的 ORBBRIEFBRISK算法等,需要使用 cv2.NORM_HAMMING,这样就会返回两个测试对象之间的汉明距离。第二个参数是布尔变量 crossCheck,默认值为False
crossCheck=True时,只有到 A 中的第 i 个特征点与 B 中的第 j 个特征点距离最近,并且 B 中的第 j 个特征点到 A 中的第 i 个特征点也是最近时才会返回最佳匹配(ij)。

maches = bf.match(des1, des2)会返回最佳匹配,返回值maches是一个 DMatch 对象列表,包括四个属性,描述符之间的距离distance,目标图像中描述符的索引trainIdx,查询图像中描述符的索引 queryIdx,目标图像的索引imgIdx  


接下来是knn方法,函数为BFMatcher.knnMatch(),代码方法如下:
import cv2
import numpy as np

# 读取图片
i1 = cv2.imread('test.png', 0)
i2 = cv2.imread('test2.png', 0)

# 初始化ORB检测器
orb = cv2.ORB_create()

# 检测关键点和描述符
kp1, des1 = orb.detectAndCompute(i1, None)
kp2, des2 = orb.detectAndCompute(i2, None)
# 使用BFMatcher进行匹配
if des1 is not None and des2 is not None:
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False)
    matches = bf.knnMatch(des1, des2, k=2)

    # Lowe's ratio test
    good = []
    for m, n in matches:
        if m.distance < 0.7 * n.distance:
            good.append(m)

    # 绘制匹配结果
    result = cv2.drawMatches(i1, kp1, i2, kp2, good, None, flags=2)
    cv2.imshow('ORB匹配结果', result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
else:
    print('未检测到特征点,无法进行匹配。')


matches = bf.knnMatch(des1, des2, k=2)返回对象也是一个 DMatch 对象列表,它会为每个关键点返回 k 个最佳匹配,在降序排列后取前k个。result = cv2.drawMatches(i1, kp1, i2, kp2, good, None, flags=2)是绘制匹配连线的函数,当k=2时,会为每个关键点绘制两条最佳匹配直线。
K近邻匹配(KNN Matching)是一种基于距离比率的特征点匹配方法,核心的思想为在图像中寻找K个和特征点最相似的点,这里的相似指的是描述符距离最小。随后进行比率测试(Ratio Test),将最佳匹配和次佳匹配的距离进行比较,如果小于阈值(代码中为0.7),就任务最佳匹配是可靠的匹配。Knn方法可以有效过滤错误匹配,在复杂场景下,算法的鲁棒性更高。

4.3 FLANN匹配
代码首先创建了一个 FlannBasedMatcher对象,配置FLANN匹配器参数使用了KDTREE算法。其中index_params是索引参数,algorithm=FLANN_INDEX_KDTREE表示使用 KDTREE 算法。search_params是搜索参数,check为搜索时遍历的节点数,值越大结果越精确但耗时越长。随后使用knnMatch方法在两组描述符des1des2之间找到每个描述符的 2 个最近邻(即k=2)。
最后通过Lowe's比率测试来保留好的匹配。Lowe's比率测试的核心逻辑是当最近邻距离显著小于次近邻距离时(即m.distance < ratio_thresh * n.distance),就认为是好的匹配。flann_match输入两个类型为NumPy数组的描述符desc1desc2,输出一个类型为列表的good_matches,每个对象包含匹配距离(distance)desc1的特征索引(queryIdx)desc2目标特征索引(trainIdx)
import cv2
img1 = cv2.imread('test.png', 0)
img2 = cv2.imread('test2.png', 0)
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
FLANN_INDEX_LSH = 6
index_params = dict(algorithm=FLANN_INDEX_LSH, table_number=6, key_size=12, multi_probe_level=1)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1, des2, k=2)
good = []
for m, n in matches:
    if m.distance < 0.7 * n.distance:
        good.append(m)
out = cv2.drawMatches(img1, kp1, img2, kp2, good, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv2.imshow('ORB + FLANN(LST)', out)
cv2.waitKey(0)
cv2.destroyAllWindows()
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

精彩推荐
热门资讯
    网友晒图
      图文推荐
        
        • 微信公众平台

        • 扫描访问手机版