文章目录
1.引入SIFT
在前面我们学习了一些角点检测技术,比如Harris 等。它们具有旋转不变特性,即使图片发生了旋转,我们也能找到同样的角点。很明显即使图像发生旋转之后角点还是角点。那如果我们对图像进行缩放
呢?角点可能就不再是角点了。以下图为例,在一副小图中使用一个小的窗口可以检测到一个角点,但是如果图像被放大,再使用同样的窗口就检测不到角点了。
所以在2004 年,D.Lowe 提出了一个新的算法:尺度不变特征变换(SIFT),这个算法可以帮助我们提取图像中的关键点并计算它们的描述符。
2.opencv中的SIFT
代码速记:
- cv2.xfeatures2d.SIFT_create()
- sift.detect()
- sift.compute()
- sift.detectAndCompute()
- cv2.drawKeypoints()
实战:
def sift(self):
#【1】读取图像,转为灰度图像
img=self.img
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#【2】创建sift对象,检测关键点,计算描述符
sift = cv2.xfeatures2d.SIFT_create()
#方法一:分别计算
kp = sift.detect(gray, None)#在图像中找到关键点。
#如果想在图像中的一个区域搜索的话,可以创建一个掩模图像作为参数使用。
#返回的关键点是一个带有很多不同属性的特殊结构体,这些属性中包含它的坐标(x,y),有意义的邻域大小,确定其方向的角度等。
kp, des = sift.compute(gray, kp)
#方法二:一步到位
kp, des = sift.detectAndCompute(gray, None)#kp 是一个关键点列表。des 是一个Numpy 数组,其大小是关键点数目乘以128。
#【3】绘制关键点
img = cv2.drawKeypoints(gray, kp, img)#在关键点的部位绘制一个小圆圈
#img=cv2.drawKeypoints(gray,kp,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
#绘制代表关键点大小的圆圈甚至可以绘制除关键点的方向
#展示结果
plt.subplot(121), plt.imshow(gray,'gray'), plt.title('raw'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(img,'gray'), plt.title('keypoints'), plt.xticks([]), plt.yticks([])
plt.show()
3.引入SURF
SIFT 算法可以进行关键点检测和描述。但是这种算法的执行速度比较慢,人们需要速度更快
的算法。在2006 年Bay,H.,Tuytelaars,T. 和Van Gool,L 共同提出了SURF(加速稳健特征)算法。跟它的名字一样,这是个算法是加速版的SIFT。
4.opencv中的SURF
代码速记:
- cv2.xfeatures2d.SURF_create()
- surf.detectAndCompute()
- surf.getHessianThreshold()
- surf.setHessianThreshold()
- cv2.drawKeypoints()
实战:
def surf(self):
img = cv2.imread('../images/white_point.jpg',0)#读入灰度图像
surf = cv2.xfeatures2d.SURF_create(400)#创建surf对象
print(surf.getHessianThreshold())
#【1】当HessianThreshold为400时
kp, des = surf.detectAndCompute(img, None)
img2 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
print(len(kp))#285个关键点
#【2】增大HessianThreshold
surf.setHessianThreshold(20000)
kp, des = surf.detectAndCompute(img, None)
img3 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
print(len(kp))#151
#【3】u-surf:所有的关键点的朝向都是一致的。它比前面的快很多
print(surf.getUpright())#Check upright flag, if it False, set it to True
surf.setUpright(True)
kp = surf.detect(img, None)
img4 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
#【4】改描述符64维为128维
print(surf.descriptorSize())#64
print(surf.getExtended())#如果结果是64维,就代表这个bool值为false
surf.setExtended(True)
kp, des = surf.detectAndCompute(img, None)
print(surf.descriptorSize())
#展示结果
plt.subplot(221), plt.imshow(img,'gray'), plt.title('raw'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(img2,'gray'), plt.title('keypoints1'), plt.xticks([]), plt.yticks([])
plt.subplot(223), plt.imshow(img3, 'gray'), plt.title('keypoints2'), plt.xticks([]), plt.yticks([])
plt.subplot(224), plt.imshow(img4, 'gray'), plt.title('keypoints3'), plt.xticks([]), plt.yticks([])
plt.show()
5.引入FAST算法
我们前面学习了几个特征检测器
,它们大多数效果都很好。但是从实时处理
的角度来看,这些算法都不够快
。一个最好例子就是SLAM(同步定位与地
图构建),移动机器人,它们的计算资源非常有限。为了解决这个问题,Edward_Rosten 和Tom_Drummond 在2006 年提出里FAST 算法。
6.opencv中的FAST算法
代码速记:
- cv2.FastFeatureDetector_create()
- fast.detect()
- cv2.drawKeypoints()
- fast.setNonmaxSuppression(0)
实战:
def fast(self):
img = cv2.imread('../images/blox.jpg', 0)
#【1】用默认值初始化fast对象
fast = cv2.FastFeatureDetector_create()
#【2】检测并绘制关键点
kp = fast.detect(img, None)
img2 = cv2.drawKeypoints(img, kp, None, color=(255, 0, 0))
#【3】打印所有默认参数
print("Threshold: ", fast.getThreshold())
print("nonmaxSuppression: ", fast.getNonmaxSuppression())
print("neighborhood: ", fast.getType())
print("Total Keypoints with nonmaxSuppression: ", len(kp))
#【4】不使用非最大值抑制
#使用极大值抑制的方法可以解决检测到的特征点相连的问题
fast.setNonmaxSuppression(0)
kp = fast.detect(img, None)
print("Total Keypoints without nonmaxSuppression: ", len(kp))
img3 = cv2.drawKeypoints(img, kp, None, color=(255, 0, 0))
#展示结果
plt.subplot(131), plt.imshow(img, 'gray'), plt.title('raw'), plt.xticks([]), plt.yticks([])
plt.subplot(132), plt.imshow(img3,'gray'), plt.title('more'), plt.xticks([]), plt.yticks([])
plt.subplot(133), plt.imshow(img2,'gray'), plt.title('less'), plt.xticks([]), plt.yticks([])
plt.show()
Threshold: 10
nonmaxSuppression: True
neighborhood: 2
Total Keypoints with nonmaxSuppression: 431
Total Keypoints without nonmaxSuppression: 1575
7.引入BRIEF
- 我们知道SIFT 算法使用的是128 维的描述符。由于它是使用的浮点数,所以要使用512 个字节。同样SURF 算法最少使用256 个字节(64 为维描述符)。创建一个包含上千个特征的向量需要消耗大量的内存,在嵌入式等资源有限的设备上这样是合适的。匹配时还会消耗更多的内存和时间。
- 但是在实际的匹配过程中如此多的维度是没有必要的。我们可以使用PCA,LDA 等方法来进行降维。甚至可以使用LSH(局部敏感哈希)将SIFT 浮点数的描述符转换成二进制字符串。对这些字符串再使用汉明距离进行匹配。汉明距离的计算只需要进行XOR 位运算以及位计数,这种计算很适合在现代的CPU 上进行。但我们还是要先找到描述符才能使用哈希,这不能解决最初的
内存消耗
问题。 - BRIEF 应运而生。它不去计算描述符而是直接找到一个二进制字符串。BRIEF 是一种特征描述符,它不提供查找特征的方法。所以我们不得不使用其他特征检测器,比如SIFT 和SURF 等。原始文献推荐使用CenSurE 特征检测器,这种算法很快。而且BRIEF 算法对CenSurE关键点的描述效果要比SURF 关键点的描述更好。
- 简单来说BRIEF 是一种
对特征点描述符计算和匹配
的快速方法。这种算法可以实现很高的识别率,除非出现平面内的大旋转。
8.opencv中的BRIEF
代码速记:
- cv2.xfeatures2d.StarDetector_create()
- cv2.xfeatures2d.BriefDescriptorExtractor_create()
- star.detect()
- brief.compute()
实战:
下面的代码使用了CenSurE 特征检测器和BRIEF 描述符。(在OpenCV中CenSurE 检测器被叫做STAR 检测器)。
def brief(self):
img = cv2.imread('../data/blox.jpg', 0)
#【1】初始化FAST检测器
star = cv2.xfeatures2d.StarDetector_create()
#【2】初始化BRIEF提取器
brief = cv2.xfeatures2d.BriefDescriptorExtractor_create()
#【3】用star找到关键点
kp = star.detect(img, None)
#【4】用BRIEF计算描述符
kp, des = brief.compute(img, kp)
#函数brief:getInt(′bytes′) 会以字节格式给出nd 的大小,默认值为32。
print("brief.descriptorSize: ",brief.descriptorSize())
brief.descriptorSize: 32
9.引入ORB算法
- 在
计算开支,匹配效率
以及更主要的是专利问题方面ORB 算法是是SIFT 和SURF 算法的一个很好的替代品。SIFT 和SURF 算法是有专利保护的,如果你要使用它们,就可能要花钱。但是ORB 不需要。 - ORB 基本是FAST 关键点检测和BRIEF 关键点描述器的结合体,并通过很多修改增强了性能。
10.opencv中的ORB算法
代码速记:
- cv2.ORB_create()
- orb.detect()
- orb.compute()
- cv2.drawKeypoints()
实战:
def orb(self):
img = cv2.imread('../images/blox.jpg', 0)
#【1】初始化ORB 特征检测器
orb = cv2.ORB_create()
#【2】用ORB找到关键点
kp = orb.detect(img, None)
#【3】用ORB计算描述符
kp, des = orb.compute(img, kp)
#【4】只画出关键点位置。不考虑大小、方向。
img2 = cv2.drawKeypoints(img, kp, None, color=(0, 255, 0), flags=0)
#展示结果
plt.subplot(121), plt.imshow(img, 'gray'), plt.title('raw'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(img2,'gray'), plt.title('ret'), plt.xticks([]), plt.yticks([])
plt.show()
11.特征检测+特征描述算法总结
算法 | 特征检测 | 计算描述符 | 特点 |
---|---|---|---|
Harris | √ | × | 旋转不变 |
Shi-Tomasi | √ | × | 对Harris的修改,更适合跟踪 |
SubPix | √× | × | 需要以Harris角点为基础。精度更高,适用几何测量 |
ChessboardCorners | √ | × | 找到棋盘角点。找全的话会有连线。适用摄像机标定。 |
SIFT | √ | √ | 尺度不变 |
SURF | √ | √ | 比SIFT更快 |
FAST | √ | × | 检测关键点更快,适用实时处理。 |
BRIEF | × | √ | 描述符数据更小。 |
ORB | √ | √ | 不要钱。FAST和BRIEF结合。 |