我正在尝试在使用OpenCV检测到的两个图像之间匹配SIFT特征:
sift = cv2.xfeatures2d.SIFT_create()
kp, desc = sift.detectAndCompute(img, None)
这两张图片似乎都包含许多特征,每个特征大约15,000个,用绿色的圆点表示。
但在匹配它们之后,我只保留了87个,其中一些是异常值。
我在想我是不是做错了什么。我匹配这两张图片的代码是:
def match(this_filename, this_desc, this_kp, othr_filename, othr_desc, othr_kp):
E_RANSAC_PROB = 0.999
F_RANSAC_PROB = 0.999
E_PROJ_ERROR = 15.0
F_PROJ_ERROR = 15.0
LOWE_RATIO = 0.9
# FLANN Matcher
# FLANN_INDEX_KDTREE = 1 # 1? https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_matcher/py_matcher.html#basics-of-brute-force-matcher
# index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
# search_params = dict(checks=50) # or pass empty dictionary
# flann = cv2.FlannBasedMatcher(index_params, search_params)
# matcherij = flann.knnMatch(this_desc, othr_desc, k=2)
# matcherji = flann.knnMatch(othr_desc, this_desc, k=2)
# BF Matcher
this_matches = {}
othr_matches = {}
bf = cv2.BFMatcher()
matcherij = bf.knnMatch(this_desc, othr_desc, k=2)
matcherji = bf.knnMatch(othr_desc, this_desc, k=2)
matchesij = []
matchesji = []
for i,(m,n) in enumerate(matcherij):
if m.distance < LOWE_RATIO*n.distance:
matchesij.append((m.queryIdx, m.trainIdx))
for i,(m,n) in enumerate(matcherji):
if m.distance < LOWE_RATIO*n.distance:
matchesji.append((m.trainIdx, m.queryIdx))
# Make sure matches are symmetric
symmetric = set(matchesij).intersection(set(matchesji))
symmetric = list(symmetric)
this_matches[othr_filename] = [ (a, b) for (a, b) in symmetric ]
othr_matches[this_filename] = [ (b, a) for (a, b) in symmetric ]
src = np.array([ this_kp[index[0]].pt for index in this_matches[othr_filename] ])
dst = np.array([ othr_kp[index[1]].pt for index in this_matches[othr_filename] ])
if len(this_matches[othr_filename]) == 0:
print("no symmetric matches")
return 0
# retain inliers that fit x.F.xT == 0
F, inliers = cv2.findFundamentalMat(src, dst, cv2.FM_RANSAC, F_PROJ_ERROR, F_RANSAC_PROB)
if F is None or inliers is None:
print("no F matrix estimated")
return 0
inliers = inliers.ravel()
this_matches[othr_filename] = [ this_matches[othr_filename][x] for x in range(len(inliers)) if inliers[x] ]
othr_matches[this_filename] = [ othr_matches[this_filename][x] for x in range(len(inliers)) if inliers[x] ]
return this_matches, othr_matches, inliers.sum()
以下是两张原始图片:https://www.dropbox.com/s/pvi247be2ds0noc/images.zip?dl=0
发布于 2020-10-10 11:41:10
高分辨率在图像处理中并不总是一件好事,所以我只是遵循本教程tutorial并添加了median 。如下所示,结果并没有那么糟糕。
im1 = cv.imread('IMG_1596.png')
gry1 = cv.cvtColor(im1, cv.COLOR_BGR2GRAY)
gry1 = cv.medianBlur(gry1, ksize = 5)
im2 = cv.imread('IMG_1598.png')
gry2 = cv.cvtColor(im2, cv.COLOR_BGR2GRAY)
gry2 = cv.medianBlur(gry2, ksize = 5)
# Initiate ORB detector
orb = cv.ORB_create()
# find the keypoints and descriptors with ORB
kp1, des1 = orb.detectAndCompute(gry1,None)
kp2, des2 = orb.detectAndCompute(gry2,None)
# create BFMatcher object
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True)
# Match descriptors.
matches = bf.match(des1,des2)
# Sort them in the order of their distance.
matches = sorted(matches, key = lambda x:x.distance)
im3 = cv.drawMatches(im1,kp1,im2,kp2,matches,None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv.imwrite("ORB_RESULTS.png", im3)
len(matches)
>>> 121
# Initiate SIFT detector
sift = cv.SIFT_create()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(gry1,None)
kp2, des2 = sift.detectAndCompute(gry2,None)
# BFMatcher with default params
bf = cv.BFMatcher()
matches = bf.knnMatch(des1,des2,k=2)
# Apply ratio test
good = []
for m,n in matches:
if m.distance < 0.75*n.distance:
good.append([m])
# cv.drawMatchesKnn expects list of lists as matches.
im3 = cv.drawMatchesKnn(im1,kp1,im2,kp2,good,None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv.imwrite("SIFT_RESULTS.png", im3)
len(good)
>>> 183
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
FLANN_INDEX_LSH = 6
index_params= dict(algorithm = FLANN_INDEX_LSH,
table_number = 6, # 12
key_size = 12, # 20
multi_probe_level = 1) #2
# Initiate SIFT with FLANN parameters detector
sift = cv.SIFT_create()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(gry1,None)
kp2, des2 = sift.detectAndCompute(gry2,None)
# FLANN parameters
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict()
flann = cv.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)
# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in range(len(matches))]
# ratio test as per Lowe's paper
for i,(m,n) in enumerate(matches):
if m.distance < 0.7*n.distance:
matchesMask[i]=[1,0]
draw_params = dict(matchColor = (0,255,0),
singlePointColor = (255,0,0),
matchesMask = matchesMask,
flags = cv.DrawMatchesFlags_DEFAULT)
im3 = cv.drawMatchesKnn(im1,kp1,im2,kp2,matches,None,**draw_params)
cv.imwrite("SIFT_w_FLANN_RESULTS.png", im3)
发布于 2020-10-10 10:47:46
我不明白为什么在代码中过滤掉它们的距离大于0.9 (LOWE_RATIO
)的匹配。这些点已经匹配了。通过过滤掉这些点,您可以将匹配的特征从大约15000减少到839,然后inlier检测器仅将其中的87个识别为inlier。
此外,使用下面的代码使用ORB (面向快速和旋转简要),我有500个关键点和158个有意义的匹配,我相信它可以成为SIFT的一个很好的替代方案:
import cv2
from matplotlib import pyplot as plt
img1 = cv2.imread('IMG_1598.png', cv2.COLOR_BGR2GRAY) # queryImage
img2 = cv2.imread('IMG_1596.png', cv2.COLOR_BGR2GRAY) # trainImage
# Initiate detector
orb = cv2.ORB_create()
# find the keypoints and descriptors
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
# create BFMatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# Match descriptors.
matches = bf.match(des1, des2)
# Sort them in the order of their distance.
matches = sorted(matches, key=lambda x: x.distance)
# Draw first 10 matches.
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, flags=2)
plt.imshow(img3)
plt.show()
plt.savefig('foo.png')
匹配结果是这样的:
https://stackoverflow.com/questions/64246583
复制相似问题