您的位置:首页 > 编程语言 > Python开发

OpenCV+Python图像处理基础(二)—— Harris角点、SIFT特征点、特征匹配

2019-08-19 17:20 4447 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/weixin_41874898/article/details/99740997

文章目录

本文知识点参考唐宇迪老师视频教程。
参考博客网址:
https://www.cnblogs.com/my-love-is-python/p/10411263.html
https://blog.csdn.net/tengfei461807914/article/details/78009887
https://www.cnblogs.com/ronny/p/4009425.html

1 Harris角点

角点检测:主要是检测一些边角突出来的点,对于A和B这样的面上的点而言,一个卷积框在上面移动,框中的基本像素点不发生变化, 对于像C和D边界点,只有x或者y轴方向上的平移,像素框内的像素会发生偏移,而对于E和F这样的角点而言,不管是像x轴或者向y轴平移,像素框内的像素都会发生偏移, 就好比图中的绿色方框一样

角点检测的基本原理,使用一个卷积框,在图上每一点进行平移操作,对于当前位置,在向上或者向下,向左或者向右平移一个像素点后的,两个图像像素点之间的差异,即w表示的是加权值,可以全部都是1,也可以使用高斯卷积,以此对中心点的像素改变做加权
数学解释如下:

设图像I(x,y)表示图像在(x,y)点的像素信息,窗口在点(x,y)处移动(Δx,Δy)后计算到的所有差异总和记为 c(x,y;Δx,Δy)


可以将图中的c(x,y;Δx,Δy)=AΔx2 + 2CΔxΔY + BΔY2看成是一个椭圆的方程,(此处的椭圆不是标准椭圆,可以进行标准化,即放平椭圆,此时椭圆的长轴短轴分别对应矩阵特征值)矩阵的特征值就是它的长轴和短轴长度。记为λ1和λ2。椭圆面积的大小就是变化的大小,也就是椭圆a、b轴变化的大小。
方向导数Ix和Iy可以使用cv2.Sobel()函数得到

可以根据这些特征值判断一个区域是否是角点,这里使用打分函数,来判断是否是角点

detM=λ1λ2=AC−B2 traceM=λ2+λ2=A+C

  • α值一般取0.04到0.06
  • 当λ1和λ2都小时,R也小,近似于0,此区域平坦。
  • 其中一个远大于另外一个时,R小于0,此区域为边缘
  • 都很大的时候,R也很大,判断为角点。

注意:在一个角点附近可能存在多个角点,因此我们需要对角点做一个极大值抑制操作

dst = cv2.cornerHarris(img, blockSize, ksize, k)

  • img: 数据类型为 float32 的输入图像(灰度图像)
  • blockSize: 角点检测中指定区域的大小(角点移动的卷积框)
  • ksize: Sobel求导中使用的窗口大小(表示后续进行梯度计算的sobel算子的大小)
  • k: 表示角点响应R值的α值,取值范围为[0,04,0.06],一般取0.04
  • dst为返回的角点响应r值

补充:亚像素级精确度的角点,使用cv2.cornerSubPix()函数,
参考网址:https://blog.csdn.net/tengfei461807914/article/details/78009887

import cv2
import numpy as np

img
7ff7
= cv2.imread('timg.jpg')
print ('img.shape:',img.shape)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)  # 注意是np.float32不是np.float
dst = cv2.cornerHarris(gray, 2, 3, 0.04)  # dst里面是r值
print ('dst.shape:',dst.shape)
print(dst)

img[dst>0.01*dst.max()]=[0,0,255]  # 注意是对img进行修改
cv2.imshow('dst',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2 SIFT特征点

SIFT,即尺度不变特征变换(Scale-invariant feature
transform,SIFT),是用于图像处理领域的一种描述。这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子。

SIFT特征点 特点
1.SIFT特征是图像的局部特征,其对旋转、尺度缩放、亮度变化保持不变性,对视角变化、仿射变换、噪声也保持一定程度的稳定性;
2. 区分性(Distinctiveness)好,信息量丰富,适用于在海量特征数据库中进行快速、准确的匹配;
3. 多量性,即使少数的几个物体也可以产生大量的SIFT特征向量;
4.高速性,经优化的SIFT匹配算法甚至可以达到实时的要求;
5.可扩展性,可以很方便的与其他形式的特征向量进行联合。

在一定的范围内,无论物体是大还是小,人眼都可以分辨出来,然而计算机要有相同的能力却很难,所以要让机器能够对物体在不同尺度下有一个统一的认知,就需要考虑图像在不同的尺度下都存在的特点。 尺度空间的获取通常使用高斯模糊来实现。(大小、模糊)

第一步:先对图像进行高斯模糊,获得5-6张的模糊后的图片,高斯方程为G(x, y, σ) = 1/(2pi*σ^2) * e-(x2+y2)/2σ2,σ越大,高斯模糊的程度就越高不同σ的高斯函数决定了对图像的平滑程度,越大的σ值对应的图像越模糊。


第二步:构造多分辨金字塔,多分辨金字塔的构造直接使用降采样不需要模糊的操作,这里可以使用平均降采样

第三步:构造高斯差分金字塔, 图中的每组5张图片为原始图片经过不同σ高斯参数模糊后获得的图。将5张图进行上下的相减操作,获得右边的差分图

下面这个式子表示的是高斯差分金字塔,即不同的高斯项进行相减,最后*I(x, y)表示差分金字塔的大小值。实际上就是做了不同高斯模糊的图像相减。

第四步:DoG空间极值检测,对获得的高斯差分金字塔,寻找尺度空间的极值点,每个像素点要和其图像域(同一尺度空间)和尺度域(相邻的尺度空间)的所有相邻点进行比较,当其大于(或者小于)所有相邻点时,该点就是极值点。如下图所示,中间的检测点要和其所在图像的3×3邻域8个像素点,以及其相邻的上下两层的3×3领域18个像素点,共26个像素点进行比较。

第五步:如果是极值点,即为关键点,这里我们对关键点做一个精确的定位。
这些候选关键点是DOG空间的局部极值点,而且这些极值点均为离散的点,精确定位极值点的一种方法是,对尺度空间DoG函数进行曲线拟合,计算其极值点,从而实现关键点的精确定位。该图使用简化的泰勒展开式,求解0这一点的近似值。

第六步:消除边界响应
使用harris角点检测的原理, 求出H(x, y) 即构造的梯度变化矩阵,求解λ1和λ2, 如果λ1>>λ2则表示为边界点,进行去除

第七步:使用sobel算子,每个特征点得到三个信息,获得位置, 计算梯度的大小,以及梯度的方向。
每个特征点可以得到三个信息(x,y,σ,θ),即位置、尺度和方向。具有多个方向的关键点可以被复制成多份,然后将方向值分别赋给复制后的特征点,一个特征点就产生了多个坐标、尺度相等,但是方向不同的特征点。
下图计算特征点的主方向:

第八步:在完成关键点的梯度计算后,使用直方图统计邻域内像素的梯度和方向,把直方图中出现次数最多的作为主方向,如果次方向的次数大于主方向的0.8,那么次方向也是辅助方向

第九步:为了保证特征矢量的旋转不变性,要以特征点为中心,在附近邻域内将坐标轴旋转θ角度,即将坐标轴旋转为特征点的主方向。

第十步:旋转之后的主方向为中心取8x8的窗口,求每个像素的梯度幅值和方向,箭头方向代表梯度方向,长度代表梯度幅值,然后利用高斯窗口对其进行加权运算,最后在每个4x4的小块上绘制8个方向的梯度直方图,计算每个梯度方向的累加值,即可形成一个种子点,即每个特征的由4个种子点组成,每个种子点有8个方向的向量信息。如下一图:
论文中建议对每个关键点使用4x4共16个种子点来描述,这样一个关键点就会产生128维的SIFT特征向量。如下二图:


  1. sift = cv2.xfeatures2d.SIFT_create() 实例化

参数说明:sift为实例化的sift函数

  1. kp = sift.detect(gray, None) 找出图像中的关键点

参数说明: kp表示生成的关键点,gray表示输入的灰度图,

  1. ret = cv2.drawKeypoints(gray, kp, img) 在图中画出关键点

参数说明:gray表示输入图片, kp表示关键点,img表示输出的图片

  1. kp, dst = sift.compute(kp) 计算关键点对应的sift特征向量

参数说明:kp表示输入的关键点,dst表示输出的sift特征向量,通常是128维的

注意:
SIFT工具包在opencv3.4.3版本以上就进入了专利保护阶段,免费无法用,所以需要将opencv的版本降低,选择3.4.1.15这个版本。另外还需要装opencv-contrib-python这个模块,提供了一些额外的扩展包,这个里面有SIFT这些包。
pip install opencv-python==3.4.1.15

pip install opencv-contrib-python==3.4.1.15

import cv2
import numpy as np

img = cv2.imread('test_1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# cv2.__version__ #3.4.1.15 pip install opencv-python==3.4.1.15 pip install opencv-contrib-python==3.4.1.15
sift = cv2.xfeatures2d.SIFT_create()
kp = sift.detect(gray, None)  # 通常灰度图传进来,kp封装好的关键点。

ret= cv2.drawKeypoints(gray, kp, img)  #画完图要显示
cv2.imshow('drawKeypoints', img)
# cv2.imshow('drawKeypoints', ret)和上面效果一样,ret等于img
cv2.waitKey(0)
cv2.destroyAllWindows()
kp, des = sift.compute(gray, kp)
print (np.array(kp).shape)

3 特征匹配

输入两张图片,将特征点配对连接起来

import cv2

# 图片读取转换
imgA = cv2.imread("right_01.png")
imgB = cv2.imread("left_01.png")
imgA_gray = cv2.cvtColor(imgA, cv2.COLOR_BGR2GRAY)
imgB_gray = cv2.cvtColor(imgB, cv2.COLOR_BGR2GRAY)

# 构造sift,求解出特征点和sift特征向量
sift = cv2.xfeatures2d.SIFT_create()
kpsA, dstA = sift.detectAndCompute(imgA_gray, None)
kpsB, dstB = sift.detectAndCompute(imgB_gray, None)

# 画出特征点
ret = cv2.drawKeypoints(imgA, kpsA, None)
cv2.imshow("a", ret)
cv2.waitKey(0)

"""1对1匹配"""
# 构造BFMatcher()蛮力匹配,找到sift特征向量距离最近对应的组
bf = cv2.BFMatcher(crossCheck=True)
# crossCheck 表示两个特征点要互相匹,例如A中的第i个特征点与B中的第j个特征点最近的,
# 并且B中的第j个特征点到A中的第i个特征点也是
matches = bf.match(dstA, dstB)

# 对匹配的结果按照距离进行排序操作
matches = sorted(matches, key=lambda x: x.distance)

# 使用cv2.drawMacthes画连线图操作
ret_match = cv2.drawMatches(imgA, kpsA, imgB, kpsB, matches[0: 10], None, flags=2)
cv2.imshow("ret_match", ret_match)
cv2.waitKey(0)

"""k对最佳匹配(1对k)"""
bf = cv2.BFMatcher()  # 此时就不能要:crossCheck=True这一句
matches = bf.knnMatch(dstA, dstB, k=2)  # 1个点对应2个距离最短的特征点
good = []
for m in matches:
if m[0].distance < 0.75 * m[1].distance:
good.append([m[0]])  # 这个地方要加1个中括号,相当于[m[0], m[1]]变成[m[0]]
ret_match = cv2.drawMatchesKnn(imgA, kpsA, imgB, kpsB, good[0:10], None, flags=2)  # 此处画图也是不一样的:cv2.drawMatchesKnn
cv2.imshow("ret_match", ret_match)
cv2.waitKey(0)

# 如果需要快速完成操作,使用cv2.FlannBasedMatcher(),数层面的优化

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: