Aim:联合使用特征提取和calib3d模块中的findHomography在复杂图像中查找已知对象。
原理
cv2.findHomography() : 在目标图像中准确找到查询对象。
先将两幅图像的特征点传给函数cv2.findHomography() ,函数会找到对象的透视图变换。再使用cv2.perspectiveTransform() 找到对象。至少4个正确点才能找到变换!
为了避免匹配过程出现错误,算法使用RANSAC和LEAST_MEDIAN。好的匹配所提供的正确估计称为inliers,剩下称为outliers。
cv2.findHomography() 返回一个掩模,掩模确定inlier点和outlier点。
代码演示
先在图像中找到SIFT特征点,再使用比值测试找到最佳匹配。
#coding=utf-8
import cv2
import numpy as np
from matplotlib import pyplot as plt
MIN_MATCH_COUNT=10 #只有存在10个以上匹配时才去查找目标,否则报警。
"""匹配足够时,提取两幅图中匹配点的坐标。把坐标传入到函数
计算透视变换。找到3×3的变换矩阵后就可以使用它将查询图像的
四个顶点变换到目标图像去,再绘制出来。"""
img1=cv2.imread('./image2/mario.jpg',0)
img2=cv2.imread('./image2/coin.jpg',0)
sift=cv2.SIFT()
kp1,des1=sift.detectAndCompute(img1,None) #找到关键点和SIFT描述符
kp2,des2=sift.detectAndCompute(img2,None)
FLANN_INDEX_KDTREE=0
index_params=dict(algorithm=FLANN_INDEX_KDTREE,trees=5)
search_params=dict(checks=50)
flann=cv2.FlannBasedMatcher(index_params,search_params)
matches=flann.knnMatch(des1,des2,k=2)
good=[]
for m,n in matches:
if m.distance < 0.7*n.distance:
good.append(m)
if len(good)>MIN_MATCH_COUNT:
src_pts=np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1,1,2)
dst_pts=np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1,1,2)
#获取关键点坐标
M,mask=cv2.findHomography(src_pts,dst_pts,cv2.RANSAC,5.0)
"""上面函数第三个参数用来计算单应性矩阵,有下列几种方法:
0 使用所有点,为常规方法。
CV_RANSAC 基于RANSAC的鲁棒方法
CV_LMEDS 最小中值稳健法
第四个参数取值范围1-10,是个阈值,是原图像的点经过变换后点与目标图像上对应点的误差。
超过误差就是outliers,返回值的M是变换矩阵。"""
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,M)
#使用得到的变换矩阵对原图的四个角变换,获得在目标图像上对应的坐标
cv2.polylines(img2,[np.int32(dst)],True,255,10,cv2.LINE_AA)
else:
print("not enough matches are found - %d%d" % (len(good),MIN_MATCH_COUNT))
matchesMask=None
#最后绘制inliers(成功找到目标对象)或者匹配的关键点(如果失败)
draw_params=dict(matchColor=(0,255,0),
singlePointColor=None,
matchesMask=matchesMask,#只绘出inliers
flags=2)
img3=cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)
plt.imshow(img3)
plt.show()```