opencv关键点检测
特征匹配主要是基于两种相似度较高的图片,通过opencv里面提供的特征匹配方法来进行特征点之间的匹配和映射
特征点由关键点和描述子两部分组成。例如:在一张图像中计算SIFT特征点时,是指提取SIFT关键点,并计算SIFT描述子两件事。
关键点是指特征点在图像里的位置,有些特征点还具有方向、大小等信息。描述子是指一个向量,描述该关键点周围像素的信息
按照外观相似特征应该有相似的描述子的原则设计
SIFT(尺度不变性)作为最经典的特征提取算法,充分考虑图像变换过程中出现的光照、尺度、旋转等变化。
但计算量较大,实时性不好。
FAST关键点(没有描述子)考虑适当降低精度和鲁棒性,以提升计算的速度,属于特别快的一种特征点。
ORB特征目前看来非常具有代表性的实时图像特征,它改进了FAST检测子不具有方向性的问题,并采用速度极快的二进制描述子BRIEF;
因此,ORB在保持特征子具有旋转、尺度不变性的同时,在速度方面也有了很大的提升
1.计算检测关键点并计算描述符
detectAndCompute(InputArray img,bool useProvidedKeypoints=false)
useProvidedKeypoints:决定当前是探测关键点还是计算描述符,为true时执行compute功能;为false时,执行detect功能,探测关键点
点击查看代码
import cv2
img_m=cv2.imread("data1/1.png",0)
sift=cv2.SIFT_create()
kp2,des2=sift.detectAndCompute(img_m,None,useProvidedKeypoints=False) #useProvidedKeypoints决定当前是探测关键点还是计算描述符,
# useProvidedKeypoints为true时,执行compute功能,计算描述符;为false时,执行detect功能,探测关键点
res_r=cv2.drawKeypoints(img_m,kp2,img_m,color=(0,255,0),flags=0)
cv2.imshow('picture2',res_r)
cv2.waitKey(0)
cv::match方法
match匹配的返回结果是DMatch类型。
DMatch数据结构包含三个非常重要的数据分别是queryIdx,trainIdx,distance;
queryIdx:某一特征点在本帧图像的索引
trainIdx:trainIdx是该特征点在另一张图像中相匹配的特征点的索引
distance:代表这一对匹配的特征点描述符的欧式距离,数值越小也就说明两个特征点越相近
matches=bf.match(des1,des2)
matches=sorted(matches,key=lambda x:x.distance)
通过对返回来的匹配数组,利用x.distance作为大小来进行排序,从而达到距离以小到大递增,则特征从大到小递减。
点击查看代码
import cv2
img_f=cv2.imread('data1/1.png')
img_m=cv2.imread('data1/2.png')
sift=cv2.SIFT_create()
kp1,des1=sift.detectAndCompute(img_f,None,useProvidedKeypoints=False)
kp2,des2=sift.detectAndCompute(img_m,None,useProvidedKeypoints=False)
res_l=cv2.drawKeypoints(img_f,kp1,img_f,color=(0,255,0),flags=0)
res_r=cv2.drawKeypoints(img_m,kp2,img_m,color=(0,255,0),flags=0)
bf=cv2.BFMatcher(crossCheck=True) # 用来比较a对b的路径是最短,同时检验b对a的路径是否也是最
matches=bf.match(des1,des2) # 暴力匹配
matches=sorted(matches,key=lambda x:x.distance) # 排序匹配得分,由小到大,通过两点的距离
img3=cv2.drawMatches(img_f,kp1,img_m,kp2,matches[:10],None,flags=2) #选取距离最小的
img3=cv2.pyrDown(img3) #因为匹配之后会通过金字塔膨胀图片,所以要通过金字塔压缩一次图片
cv2.imshow('picture',img3)
cv2.waitKey(0)
cv::knn_Match方法
knnMatch匹配的返回结果是一个元组,说明结果不能改变;
对元组内元素进行类型查询: 所以KnnMatch与match的返回值类型一样,只不过一组返回的2个DMatch类型
matches=bf.knnMatch(des1,des2,k=2)
good=[]
for m,n in matches:
if m.distance<0.75n.distance:
good.append([m])
当k=2时,knnMatch方法会返回每个查询特征点的两个最近邻匹配。每个匹配对象都包含两个最近邻的特征点,即有两个元素的列表。
例如,如果matches是[(m1,n1),(m2,n2),...,(mk,nk)],那么对于第i个查询特征点,它的两个最近邻匹配分别是(mi,ni)。以下是对
每个匹配对象中元素的解释:
m.distance:第一个最近邻的相似性度量值。距离值越小表示越相似
n.distance:第二个最近邻的相似性度量值。
所以判断如果m的距离小于n的距离0.75,则判断m点特征点较为匹配
点击查看代码
import cv2
img_f=cv2.imread('data1/1.png')
img_m=cv2.imread('data1/2.png')
sift=cv2.SIFT_create()
kp1,des1=sift.detectAndCompute(img_f,None,useProvidedKeypoints=False)
kp2,des2=sift.detectAndCompute(img_m,None,useProvidedKeypoints=False)
res_l=cv2.drawKeypoints(img_f,kp1,img_f,color=(0,255,0),flags=0)
res_r=cv2.drawKeypoints(img_m,kp2,img_m,color=(0,255,0),flags=0)
bf=cv2.BFMatcher()
matches=bf.knnMatch(des1,des2,k=3)
good=[]
for m,n,p in matches:
if m.distance<0.75*n.distance:
good.append([m])
img3=cv2.drawMatchesKnn(img_f,kp1,img_m,kp2,good,None,flags=2)
img3=cv2.pyrDown(img3)
cv2.imshow('pic1',img3)
cv2.waitKey(0)
快速近似最近邻匹配(FLANN)
点击查看代码
flann=cv2.FlannBasedMatcher(index_params,search_params)
index_params: 字典类型,在设置中用数字表示
search_params:字典类型,默认dict(checks=32,eps=0,sorted=True)
FLANN_INDEX_LINEAR 0 线性暴力搜索
FLANN_INDEX_DKTREE 1 随机kd树,平行搜索,默认trees=4
FLANN_INDEX_KMEANS 2 层次k均值树
FLANN_INDEX_COMPOSITE 3 随机kd数
FLANN的意思是快速最近邻搜索库,它包含一个对大数据集合和高位特诊实现最近邻搜索的算法集合,
而且这些算法是优化固偶读。
面对大数据集时,效果要比暴力搜索好。
FLANN要传递两个字典作为参数,第一个参数是使用的搜索算法;第二个参数是搜索次数,
次数越多,结果越精确,但是速度也越慢
点击查看代码
import cv2
img_f=cv2.imread('data1/1.png')
img_m=cv2.imread('data1/2.png')
sift=cv2.SIFT_create()
kp1,des1=sift.detectAndCompute(img_f,None,useProvidedKeypoints=False)
kp2,des2=sift.detectAndCompute(img_m,None,useProvidedKeypoints=False)
res_l=cv2.drawKeypoints(img_f,kp1,img_f,color=(0,255,0),flags=0)
res_r=cv2.drawKeypoints(img_m,kp2,img_m,color=(0,255,0),flags=0)
algorithm_prarm=dict(algorithm=2,tree=5) #FlannBaseMatcher的参数之一
check_param=dict(check=5) #FlannBasedMatcher的参数之一,设置匹配次数,次数越多越准确
bf=cv2.FlannBasedMatcher(algorithm_prarm,check_param)
matches=bf.match(des1,des2)
matches=sorted(matches,key=lambda x:x.distance)
img3=cv2.drawMatches(img_f,kp1,img_m,kp2,matches,None,flags=2)
img3=cv2.pyrDown(img3)
cv2.imshow('pic',img3)
cv2.waitKey(0)