#python #opencv #feature-detection
#python #opencv #обнаружение функций
Вопрос:
Я пытаюсь сопоставить функции SIFT между двумя изображениями, которые я обнаружил с помощью OpenCV:
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
Комментарии:
1. Я не уверен, какова ваша конечная цель, но вы можете рассмотреть возможность использования нейронной сети или, по крайней мере, алгоритма хеширования восприятия для измерения сходства между этими изображениями, поскольку эти методы (особенно нейронная сеть) более надежны, чем более старые методы SIFT / SURF keypoint
2. Это для структуры из движения. Это довольно типичный шаг, и мой код работает для изображений с низким разрешением. Итак, я не понимаю, что происходит с этими изображениями.
Ответ №1:
Высокое разрешение не всегда хорошо при обработке изображений, поэтому я просто следовал этому учебному руководству и добавил медианный фильтр. Результаты, как показано ниже, были не такими уж плохими
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)
Ответ №2:
Я не понимаю, почему в коде вы отфильтровываете совпадения, что их расстояния больше 0.9 ( LOWE_RATIO
) . Точки уже сопоставлены. Отфильтровывая эти точки, вы уменьшаете совпадающие объекты примерно с 15000 до 839, а затем детектор вкладок распознает только 87 из них как вкладные.
Кроме того, используя приведенный ниже код, в котором используется 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')