【OpenCV-Python】——哈里斯/Shi-Tomas角检测&FAST/SIFT/ORB特征点检测&暴力/FLANN匹配器&对象查找
目录
前言:
1、角检测
1.1 哈里斯角检测
1.2 优化哈里斯角
1.3 Shi-Tomasi角检测
2、特征点检测
2.1 FAST特征点检测
2.2 SIFT特征检测
2.3 ORB特征检测
3、特征匹配
3.1 暴力匹配器
3.2 FLANN匹配器
4、对象查找
总结:
前言:
图像中的特征被定义为包含独特性和易识别性区域的部分,例如角点和边缘。通过识别并分类这些特征信息,能够显著提升图像匹配与检索的效果。
1、角检测
1.1 哈里斯角检测
cv2.conerHarris()函数根据哈里斯角检测器算法检测图像中的角:
dst=cv2.conerHarris(src,blocksize,ksize,k)
AI助手
src:8位单通道或浮点值图像
blocksize:邻域大小,越大检测出的角占的区域越大
ksize:使用Sobel算子的中孔参数
其中k被视为一个自由参数。在该模型中,Ksize与k共同决定了对检测灵敏度的影响。当其值较小时,能够捕获更多的角点;然而这可能会导致检测精度有所下降。
该numpy.ndarray对象具有与src相同的尺寸,在每个像素点上均对应一个数组元素。其数值值越大则表示该像素点成为角的可能性越大。从而记录了各像素点的角度信息。
import cv2
import numpy as np
img=cv2.imread('lifangti.png')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转换为灰度图
gray=np.float32(gray) #转换为浮点类型
dst=cv2.cornerHarris(gray,8,7,0.01) #执行角检测
#将检测结果中值大于“最大值0.02”对应的像素设置为红色
img[dst>0.02*dst.max()]=[0,0,255]
cv2.imshow('dst',img) #显示检测结果
cv2.waitKey(0)
cv2.destroyAllWindows()
AI助手

1.2 优化哈里斯角
在本研究中发现,在提取出的哈里斯角区域中存在一定数量的像素点,在某些场景下为了提高定位精度和准确性,我们采用OpenCV库中的cv2.cornerSubPix()函数进行进一步优化。
dst=cv2.cornerSubPix(src,corners,winsize,zeroZone,criteria)
src:8位单通道或浮点值图像
Corners:哈里斯角的质心坐标
Winsize:搜索窗口边长的一半
zeroZone:零值边长的一半
Criteria:优化查找的终止条件
Dst:返回的numpy.ndarray对象,存储优化后的角信息
AI助手
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('lifangti.png')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转换为灰度图
gray=np.float32(gray) #转换为浮点类型
dst=cv2.cornerHarris(gray,8,7,0.01) #执行角检测
r,dist=cv2.threshold(dst,0.01*dst.max(),255,0) #二值化阈值处理
dst=np.uint8(dst) #转换为整型
r,l,s,cxys=cv2.connectedComponentsWithStats(dst) #查找质点坐标
cif=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,100,0.01) #定义优化查找条件
corners=cv2.cornerSubPix(gray,np.float32(cxys),(5,5),(-1,-1),cif) #执行优化查找
res=np.hstack((cxys,corners)) #堆叠构造新数组,便于标注角
res=np.int0(res) #转换为整型
img[res[:,1],res[:,0]]=[0,0,255] #将哈里斯角对应像素设置为红色
img[res[:,3],res[:,2]]=[255,0,0] #将优化结果像素设置为蓝色
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #转换为RGB格式
plt.imshow(img)
plt.axis('off')
plt.show()
AI助手


1.3 Shi-Tomasi角检测
基于Shi-Tomasi角检测器的改进方法中提到的角检测技术,在OpenCV库中通过cv2.goodFeaturesToTrack()函数实现这一目标:该函数采用Shi-Tomasi角检测器来定位图像中的前N个最强的特征点。
dst=cv2.goodFeaturesToTrack(src,maxCorner,qualityLevel,minDistance)
dst是返回的结果,保存了检测到的角在原图像中的坐标
src是8位单通道或浮点值图像
maxCorner:返回的角的最大数量
qualityLevel:可接受角的最低质量
minDistance:返回的角之间的最小欧几里得距离
AI助手
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('six.png')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转换为灰度图
gray=np.float32(gray) #转换为浮点类型
corners=cv2.goodFeaturesToTrack(gray,7,0.1,100) #检测角,最多7个
corners=np.int0(corners) #转换为整型
for i in corners:
x,y=i.ravel()
cv2.circle(img,(x,y),4,(255,0,0),-1) #用蓝色圆点标出找到的点
img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #转换为RGB格式
plt.imshow(img)
plt.axis('off')
plt.show()
AI助手

2、特征点检测
特征点即图像中具有独特性的像素,在计算机视觉领域也可称为 Interest Points 或 Key Points。需要注意的是,在某些情况下角也是一种特殊的 Feature Point。
2.1 FAST特征点检测
该检测器主要通过分析16邻近像素的空间强度特征以及预设阈值和其他相关参数来确定该像素是否属于关键点区域。
通过调用cv2.FastFeatureDetector_create()函数来创建一个FAST对象,并随后通过该对象的detect()方法来进行关键点检测。最终得到一个关键点矩阵,在其中每一个关键点都包括了其角度、坐标、响应强度以及领域大小等信息。这些关键点中出现角特征的概率与响应强度相关:
import cv2
img=cv2.imread('lifangti.png') #打开图像,默认时BGR格式
fast=cv2.FastFeatureDetector_create() #创建FAST检测器
kp=fast.detect(img,None)#检测关键点,不使用掩模
img2=cv2.drawKeypoints(img,kp,None,color=(0,0,255))#绘制关键点
cv2.imshow('FAST points',img2)#显示绘制了关键点的图像
fast.setThreshold(20)#设置阈值,默认阈值10
kp=fast.detect(img, None)#检测关键点,不使用掩模
n=0
for p in kp:#输出关键点信息
print("第%s个关键点,坐标:"%(n+1),p.pt,'响应强度:',p.response,'领域大小:',p.size,'角度:',p.angle)
n+=1
img3=cv2.drawKeypoints(img,kp,None,color=(0,0,255))
cv2.imshow('Treshold20',img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
AI助手


2.2 SIFT特征检测
图像中的形状特征具有旋转不变性这一特性,在图像尺寸缩放过程中这些形状特征可能会发生改变。SIFT算法是一种基于尺度不变特性的特征提取方法,用于检测并提取在不同尺度下保持一致性的图像特征,并识别出关键点位置。
第一步操作是通过cv2.SIFT_create()函数创建一个SIFT对象;第二步是将该SIFT对象被用来执行关键点检测的过程。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('six.png')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转换为灰度图
sift=cv2.SIFT_create() #创建SIFT检测器,已申请专利要购买才可运行
kp=sift.detect(gray,None) #检测关键点
img2=cv2.drawKeypoints(img,kp,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) #绘制关键点
img2=cv2.cvtColor(img2,cv2.COLOR_BGR2RGB) #转换为RGB格式
plt.imshow(img2)
plt.axis('off')
plt.show()
AI助手
2.3 ORB特征检测
基于FAST特征检测器和BRIEF描述符进行优化后,在检测性能方面表现更优。同样地,在其他相关过程中也实现了类似的优化效果。
3、特征匹配
基于上述方法提取的关键点特征向量可用于图像间的特征匹配过程。当判断一张图片(称为图片A)是否包含另一张图片(称为图片B)作为子图像时,在这种情况下:图片A是一张作为训练集样本的图片;而图片B则是一张待检索的对象图片。具体而言,在图片A中被检测到的关键点处所获得的特征向量即为目标样本的关键点向量;而在 pictures B 中被检测到的关键 point 处所获得的 feature vector 即为 training sample 的 key point vector.
3.1 暴力匹配器
在本方法中采用描述符进行特征对比。具体操作如下:首先在查询描述符中选取一个关键点的描述符,并将其与训练描述符库中的所有关键点描述符逐一进行对比;每次对比后计算出一个距离值;其中最小的那个距离对应最佳匹配结果;最终返回一组最佳匹配结果。
通过先调用cv2.BFMatcher_create()函数来初始化BFMatcher对象,并在构造过程中指定相关参数配置其行为特性。随后执行该对象的match方法以获取每个关键点的最佳匹配结果。其中knnMatch方法能够返回预设数量的最佳匹配结果
①cv2.BFMatcher_create()函数
bf=cv2.BFMatcher_create(normType,crossCheck)
bf:返回的暴力匹配器对象。两个参数都是可选的:
normType:距离测量类型,默认是cv2.NORM_L2。通常SIFT、SURF等描述符使用cv2.NORM_L1或cv2.NORM_L2;ORB、BRISK或BRIEF等描述符使用cv2.NORM_HAMMING。
crossCheck:默认False,匹配器为每个查询描述符找到k个距离最近的匹配描述符。为True时,只返回满足交叉验证条件的匹配结果。
AI助手
②match()方法
ms=bf.match(des1,des2)
ms是返回的匹配结果,是一个DMatch对象列表。每个DMatch对象表示关键点的一个匹配结果,其distance属性表示距离,值越小匹配度越高。
des1是查询描述符
des2是训练描述符
AI助手
在获得结果后可利用cv2.drawMatches()或cv2.drawMatchesKnn()函数呈现匹配结果图像。
outImg=cv2.drawMatches(img1,keypoints1,img2,keypoints2,matches1to2,outImg,matchcolor,singlePointsColor,matchesMask,flags)
outImg=cv2.drawMatchesKnn(img1,keypoints1,img2,keypoints2,matches1to2,outImg,matchcolor,singlePointsColor,matchesMask,flags)
outImg是返回的绘制结果图像,图像中查询图像与训练图像中匹配的关键点和两点之间连线为彩色。
img1是查询图像;img2是训练图像。
keypoints是关键点。
matches 1to2是img1和img2的匹配结果。
后四个是可选参数,matchColor是关键点和连接线的颜色,默认随机;singlePointColor是单个关键点的颜色,默认随机;matchesMask是掩模,用于决定绘制哪些匹配结果,默认为空,表示绘制所有匹配结果;flags是标志,如cv2.DrawMatchFlags_DEFAULT等。
AI助手
示例代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img1=cv2.imread('cat.png',cv2.IMREAD_GRAYSCALE)
img2=cv2.imread('catface.png',cv2.IMREAD_GRAYSCALE)
orb=cv2.ORB_create() #创建ORB检测器
kp1,des1=orb.detectAndCompute(img1,None) #检测关键点和计算描述符
kp2,des2=orb.detectAndCompute(img2,None) #检测关键点和计算描述符
bf=cv2.BFMatcher_create(cv2.NORM_HAMMING,crossCheck=True) #创建匹配器,True
ms=bf.match(des1,des2) #执行特征匹配
ms=sorted(ms,key=lambda x:x.distance) #按距离排序
img3=cv2.drawMatches(img1,kp1,img2,kp2,ms[:20],None,flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) #绘制前20个匹配结果
plt.imshow(img3)
plt.axis('off')
plt.show()
AI助手

暴力匹配器对象的knnMatch方法可返回指定数量的最佳匹配结果:
ms=bf.knnMatch(des1,des2,k=n)
ms是返回的匹配结果列表,每个列表元素是一个子列表,包含了由参数k指定个数的DMatch对象;
des1查询描述符;des2训练描述符;k是返回的最佳匹配个数
AI助手
import cv2
import numpy as np
import matplotlib.pyplot as plt
img1=cv2.imread('cat.png',cv2.IMREAD_GRAYSCALE)
img2=cv2.imread('catface.png',cv2.IMREAD_GRAYSCALE)
orb=cv2.ORB_create() #创建ORB检测器
kp1,des1=orb.detectAndCompute(img1,None) #检测关键点和计算描述符
kp2,des2=orb.detectAndCompute(img2,None) #检测关键点和计算描述符
bf=cv2.BFMatcher_create(cv2.NORM_HAMMING,crossCheck=False) #创建匹配器,Flase
ms=bf.knnMatch(des1,des2,k=2) #执行特征匹配
#应用比例测试选择要使用的匹配结果
good=[]
for m,n in ms:
if m.distance<0.75*n.distance: #因为k=2,所以这里要比较两个匹配结果的距离
good.append(m)
img3=cv2.drawMatches(img1,kp1,img2,kp2,good[:20],None,flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) #绘制前20个匹配结果
plt.imshow(img3)
plt.axis('off')
plt.show()
AI助手

3.2 FLANN匹配器
该快速库专门用于实现近似最近邻搜索,在性能上显著优于其他常见类型的最近邻搜索算法。在构建这种匹配器时,建议使用两个字典类型参数:index_params和search_params。
index_params 是一种用于指定索引树算法类型及其数量的关键参数配置项,在实际应用中具有重要的指导意义。在特征点提取算法中,SIFT、SURF与ORB各有其独特的应用场景:SIFT算法基于梯度直方图匹配,而SURF则结合了Hessian矩阵特征值来提高匹配精度,ORB则采用了二进制描述符以减少计算开销,三者在具体实现时采用以下代码:
FLANN_INDEX_KDTREE=1
index_params=dict(algorithm=FLANN_INDEX_KDTREE,tree=5)
AI助手
ORB算法可用下面代码:
FLANN_INDEX_LSH=6
index_params=dict(algorithm=FLANN_INDEX_LSH,
table_number=6,
key_size=12,
multi_probe_level=1)
AI助手
②search_params 用于配置索引树的搜索深度,在设定较高的搜索深度时能够显著提升匹配准确性;一般建议设置在50左右以达到良好的平衡效果。
search_params=dict(checks=50)
AI助手
示例代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img1=cv2.imread('cat.png',cv2.IMREAD_GRAYSCALE)
img2=cv2.imread('catface.png',cv2.IMREAD_GRAYSCALE)
orb=cv2.ORB_create() #创建ORB检测器
kp1,des1=orb.detectAndCompute(img1,None) #检测关键点和计算描述符
kp2,des2=orb.detectAndCompute(img2,None) #检测关键点和计算描述符
#定义FLANN参数
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) #创建FLANN匹配器
matches=flann.match(des1,des2) #执行匹配操作
draw_params=dict(matchcolor=(0,255,0),#设置关键点和连接线为绿色
singlePointColor=(255,0,0),#设置单个点为红色
matchesMask=None,
flags=cv2.DrawMatchesFlags_DEFAULT)
img3=cv2.drawMatches(img1,kp1,img2,kp2,matches[:20],None,flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
plt.imshow(img3)
plt.axis('off')
plt.show()
AI助手

4、对象查找
在完成上述操作后, 可通过调用cv2.findHomography()函数来获取查询图像与训练图像之间的透视变换关系, 然后调用cv2.perspectiveTransform()函数来进行透视矩阵变换, 最终即可确定查询图像在训练图像中的位置.
①cv2.findHomography() 函数格式:
retv,mask=cv2.findHomography(srcPoints,dstPoints,method,ransacReproThreshold)
AI助手
retv表示返回的转换矩阵;mask则表示查询图像在训练图像中最佳匹配的结果掩膜。其中srcPoints与dstPoints分别代表查询图象与训练图象之间的匹配坐标。其中method用于计算透视转换矩阵的方法;ransacReproThreshold则表示最大允许重投影误差。
②cv2.perspectiveTransform() 函数格式:
dst=cv2.perspectiveTransform(src,m)
AI助手
dst代表输出结果数组,在尺寸和数据类型上与src保持一致。其中src表示输入图像为双通道或多通道(如2或3)的浮点数数组;而m则是一个由3×3或4×4元素组成的浮点数矩阵,并且该矩阵通常用于图像之间的几何变换操作(例如通过cv2.findHomography()函数计算得到)。
示例代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img1=cv2.imread('cat.png',cv2.IMREAD_GRAYSCALE)
img2=cv2.imread('catface.png',cv2.IMREAD_GRAYSCALE)
orb=cv2.ORB_create() #创建ORB检测器
kp1,des1=orb.detectAndCompute(img1,None) #检测关键点和计算描述符
kp2,des2=orb.detectAndCompute(img2,None) #检测关键点和计算描述符
bf=cv2.BFMatcher_create(cv2.NORM_HAMMING,crossCheck=True) #创建匹配器,True
ms=bf.match(des1,des2) #执行特征匹配
ms=sorted(ms,key=lambda x:x.distance) #按距离排序
matchesMask=None
if len(ms) > 10: #在有足够数量的匹配结果后,才计算查询图像在训练图像中的位置
querypts=np.float32([kp1[m.queryIdx].pt for m in ms]).reshape(-1,1,2)#计算查询图像匹配结果的坐标
trainpts=np.float32([kp2[m.trainIdx].pt for m in ms]).reshape(-1, 1, 2) # 计算训练图像匹配结果的坐标
retv,mask=cv2.findHomography(querypts,trainpts,cv2.RANSAC) #执行查询图像与训练图像的透视转换
matchesMask=mask.ravel().tolist() #计算最佳匹配结果的掩模,用于绘制匹配结果
h,w=img1.shape
pts=np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1, 1, 2)
dst=cv2.perspectiveTransform(pts,retv) #执行向量的透视矩阵转换,获得查询图像在训练图像中的位置
img2=cv2.polylines(img2,[np.int32(dst)],True,(255,255,255),5) #用白色矩形在训练图像中绘制出查询图像的范围
img3=cv2.drawMatches(img1,kp1,img2,kp2,ms,None,
matchColor=(0,255,0), #用绿色画出匹配结果
singlePointColor=None,
matchesMask=matchesMask, #绘制掩模内的匹配结果
flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
plt.imshow(img3)
plt.axis('off')
plt.show()
AI助手

仅当获得足够的匹配结果时,才能确定查询图像在其训练数据集中的定位。其中设定的阈值为10,在条件得到满足时,则基于特征匹配的结果实施透视变换。通过这一过程即可确定目标物体的位置信息,并利用绘图函数将该定位过程可视化。值得注意的是,在实际应用中,默认情况下仅会展示特征匹配的结果而不显示最终定位信息。
总结:
作为初学阶段的使用者可能存在诸多未完善之处或疏漏。经过更深入的学习后将逐步修正并删除。也欢迎各位朋友提出宝贵意见!下次学习人脸检测和识别!

