第十六节、特征描述符BRIEF(附源码)
我们已经知道SIFT算法采用128维的特征描述子,由于描述子用的是浮点数,所以它将会占用512字节的空间。类似的SUFR算法,一般采用64维的描述子,它将占用256字节的空间。如果一幅图像中有1000个特征点,那么SIFT或SURF特征描述子将占用大量的内存空间,对于那些资源紧张的应用,尤其是嵌入式的应用,这样的特征描述子显然是不可行的。而且,越占有越大的空间,意味着越长的匹配时间。
但是实际上SIFT或SURF的特征描述子中,并不是所有维都在匹配中有着实质性的作用。我们可以用PCA、LDA等特征降维的方法来压缩特征描述子的维度。还有一些算法,例如局部敏感哈希(Locality-Sensitive Hashing, LSH),将SIFT的特征描述子转换为一个二值的码串,然后这个码串用汉明距离进行特征点之间的匹配。这种方法将大大提高特征之间的匹配,因为汉明距离的计算可以用异或操作然后计算二进制位数来实现,在现代计算机结构中很方便。下面我们来提取一种二值码串的特征描述子。
一 BRIEF简述
BRIEF(Binary Robust Independent Elementary Features)应运而生,它提供了一种计算二值化的捷径,并不需要计算一个类似于SIFT的特征描述子。它需要先平滑图像,然后在特征点周围选择一个Patch,在这个Patch内通过一种选定的方法来挑选出来个点对。然后对于每一个点对,我们比较这两个点的亮度值,如果,则对应在二值串中的值为1,否则为0,。所有个点对,都进行比较之间,我们就生成了一个长的二进制串。
对于的选择,我们可以设置为128,256或者512,这三个参数在OpenCV中都有提供,但是OpenCV中默认的参数是256,这种情况下,经过大量实验数据测试,不匹配的特征点的描述子的汉明距离在128左右,匹配点对描述子的汉明距离则远小于128。一旦维数选定了,我们就可以用汉明距离来匹配这些描述子了。
我们总结一下特征描述子的建立过程:
- 利用Harris或者FAST等方法检测特征点;
- 选定建立特征描述子的区域(特征点的一个正方形邻域);
- 对该邻域用窗口尺寸为9的的高斯核卷积,以消除一些噪声。因为该特征描述子随机性强,对噪声较为敏感;
- 以一定的随机化算法生成点对,若点的亮度,则返回1,否则返回0;
- 重复第三步若干次(如256次),得到一个256位的二进制码串,即该特征点的描述子;
值得注意的是,对于BRIEF,它仅仅是一种特征描述符,它不提供提取特征点的方法。所以,如果你必须使一种特征点定位的方法,如FAST、SIFT、SURF等。这里,我们将使用CenSurE方法来提取关键点,对BRIEF来说,CenSurE的表现比SURF特征点稍好一些。
总体来说,BRIEF是一个效率很高的提取特征描述子的方法,我们总结一下该特征描述子的优缺点:
首先,它抛弃了传统的利用图像局部邻域的灰度直方图或梯度直方图提取特征方法,改用检测随机响应,大大加快了描述子的建立速度;生成的二进制特征描述子便于高速匹配(计算汉明距离只需要通过异或操作加上统计二进制编码中"1"的个数,这些通过底层运算可以实现),且便于在硬件上实现。其次,该特征描述子的缺点很明显就是旋转不变形较差,需要通过新的方法来改进。
通过实验,作者进行结果比较:
- 在旋转程度较小的图像中,使用BRIEF特征描述子的匹配质量非常高,测试的大多数情况都超过了SURF,但是在旋转大于30°后,BRIEF特征描述子的匹配率快速降到0左右;
- BRIEF的耗时非常短,在相同情况下计算512个特征点的描述子是,SURF耗时335ms,BRIEF仅8.18ms;匹配SURF描述子需要28.3ms,BRIEF仅需要2.19ms,在要求不太高的情形下,BRIEF描述子更容易做到实时;
BRIEF的优点主要在于速度,缺点也很明显:
- 不具有旋转不变形;
- 对噪声敏感
- 不具有尺度不变性
因此为了解决前两个缺点,并且综合考虑速度和性能,提出了ORB算法,该算法将基于FAST关键点检测的技术和BRIEF特征描述子技术相结合。
二 点对的选择
设我们在特征点的邻域块大小为内选择个点对,Colonder的实验中测试了5种采样方法。
- 在图像块内平均采样;
- 和都符合的 高斯分布;
- 符合的高斯分布,而符合的高斯分布;
- 在空间量化极坐标下的离散位置随机采样;
- 把固定为(0,0),在周围平均采样;
下面是5种采样方法的结果示意图:
三 OpenCV实现
我们使用OpenCV演示一下特征点提取、BRIEF特征描述子提取、以及特征点匹配的过程:
# -*- coding: utf-8 -*- """ Created on Mon Sep 10 09:59:22 2018 @author: zy """ ''' 使用BRIEF特征描述符 ''' import cv2 import numpy as np def brief_test(): #加载图片 灰色 img1 = cv2.imread('./image/match1.jpg') img1 = cv2.resize(img1,dsize=(600,400)) gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY) img2 = cv2.imread('./image/match2.jpg') img2 = cv2.resize(img2,dsize=(600,400)) gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY) image1 = gray1.copy() image2 = gray2.copy() image1 = cv2.medianBlur(image1,5) image2 = cv2.medianBlur(image2,5) ''' 1.使用SURF算法检测关键点 ''' #创建一个SURF对象 阈值越高,能识别的特征就越少,因此可以采用试探法来得到最优检测。 surf = cv2.xfeatures2d.SURF_create(3000) keypoints1 = surf.detect(image1) keypoints2 = surf.detect(image2) #在图像上绘制关键点 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('sift_keypoints1',image1) cv2.imshow('sift_keypoints2',image2) cv2.waitKey(20) ''' 2.计算特征描述符 ''' brief = cv2.xfeatures2d.BriefDescriptorExtractor_create(32) keypoints1, descriptors1 = brief.compute(image1, keypoints1) keypoints2, descriptors2 = brief.compute(image2, keypoints2) print('descriptors1:',len(descriptors1),'descriptors2',len(descriptors2)) ''' 3.匹配 汉明距离匹配特征点 ''' matcher = cv2.BFMatcher_create(cv2.HAMMING_NORM_TYPE) matchePoints = matcher.match(descriptors1,descriptors2) print(type(matchePoints),len(matchePoints),matchePoints[0]) #提取强匹配特征点 minMatch = 1 maxMatch = 0 for i in range(len(matchePoints)): if minMatch > matchePoints[i].distance: minMatch = matchePoints[i].distance if maxMatch < matchePoints[i].distance: maxMatch = matchePoints[i].distance print('最佳匹配值是:',minMatch) print('最差匹配值是:',maxMatch) #获取排雷在前边的几个最优匹配结果 goodMatchePoints = [] for i in range(len(matchePoints)): if matchePoints[i].distance < minMatch + (maxMatch-minMatch)/3: goodMatchePoints.append(matchePoints[i]) #绘制最优匹配点 outImg = None outImg = cv2.drawMatches(img1,keypoints1,img2,keypoints2,goodMatchePoints,outImg,matchColor=(0,255,0),flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT) cv2.imshow('matche',outImg) cv2.waitKey(0) cv2.destroyAllWindows() if __name__ == '__main__': brief_test()
由于BRIEF描述子对噪声比较敏感,因此我们对图片进行了中值滤波处理,虽然消除了部分误匹配点,但是从上图中可以看到匹配的效果并不是很好。在实际应用上,我们应该选取两个近似一致并且噪声点较少的图像,这样才能取得较高的匹配质量。
四 自己实现
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了