我如何使用 Flann 匹配之间的关系来确定合理的单应性?
How do I use the relationships between Flann matches to determine a sensible homography?
我有一张全景图,以及在该全景图中看到的建筑物的较小图像。我想做的是识别那个较小图像中的建筑物是否在那个全景图像中,以及 2 个图像如何排列。
对于第一个示例,我使用的是全景图像的裁剪版本,因此像素是相同的。
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import math
# Load images
cwImage = cv2.imread('cw1.jpg',0)
panImage = cv2.imread('pan1.jpg',0)
# Prepare for SURF image analysis
surf = cv2.xfeatures2d.SURF_create(4000)
# Find keypoints and point descriptors for both images
cwKeypoints, cwDescriptors = surf.detectAndCompute(cwImage, None)
panKeypoints, panDescriptors = surf.detectAndCompute(panImage, None)
然后我使用 OpenCV 的 FlannBasedMatcher 找到两个图像之间的良好匹配:
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)
# Find matches between the descriptors
matches = flann.knnMatch(cwDescriptors, panDescriptors, k=2)
good = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good.append(m)
所以你可以看到,在这个例子中,它完美地匹配了图像之间的点。然后我找到单应性,并应用透视扭曲:
cwPoints = np.float32([cwKeypoints[m.queryIdx].pt for m in good
]).reshape(-1, 1, 2)
panPoints = np.float32([panKeypoints[m.trainIdx].pt for m in good
]).reshape(-1, 1, 2)
h, status = cv2.findHomography(cwPoints, panPoints)
warpImage = cv2.warpPerspective(cwImage, h, (panImage.shape[1], panImage.shape[0]))
结果是它完美地将较小的图像放在较大的图像中。
现在,我想在较小图像不是较大图像的像素完美版本的情况下执行此操作。
对于新的较小图像,关键点如下所示:
你可以看到,在某些情况下,它匹配正确,而在某些情况下,它不匹配。
如果我用这些匹配项调用 findHomography
,它将考虑所有这些数据点并得出一个无意义的扭曲视角,因为它基于正确的匹配项和不正确的匹配项比赛。
我正在寻找的是在检测良好匹配和调用 findHomography
之间缺少的步骤,我可以在其中查看匹配之间的关系,并因此确定哪些匹配是正确的。
我想知道 OpenCV 中是否有一个函数我应该在这一步中查看,或者这是否是我需要自己解决的问题,如果是的话我应该怎么做那个?
去年(2017.11.11)写了一篇关于在场景中寻找对象的博客。也许有帮助。这里是link。 https://zhuanlan.zhihu.com/p/30936804
环境:OpenCV 3.3 + Python 3.5
找到匹配项:
在场景中找到的对象:
代码:
#!/usr/bin/python3
# 2017.11.11 01:44:37 CST
# 2017.11.12 00:09:14 CST
"""
使用Sift特征点检测和匹配查找场景中特定物体。
"""
import cv2
import numpy as np
MIN_MATCH_COUNT = 4
imgname1 = "box.png"
imgname2 = "box_in_scene.png"
## (1) prepare data
img1 = cv2.imread(imgname1)
img2 = cv2.imread(imgname2)
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
## (2) Create SIFT object
sift = cv2.xfeatures2d.SIFT_create()
## (3) Create flann matcher
matcher = cv2.FlannBasedMatcher(dict(algorithm = 1, trees = 5), {})
## (4) Detect keypoints and compute keypointer descriptors
kpts1, descs1 = sift.detectAndCompute(gray1,None)
kpts2, descs2 = sift.detectAndCompute(gray2,None)
## (5) knnMatch to get Top2
matches = matcher.knnMatch(descs1, descs2, 2)
# Sort by their distance.
matches = sorted(matches, key = lambda x:x[0].distance)
## (6) Ratio test, to get good matches.
good = [m1 for (m1, m2) in matches if m1.distance < 0.7 * m2.distance]
canvas = img2.copy()
## (7) find homography matrix
## 当有足够的健壮匹配点对(至少4个)时
if len(good)>MIN_MATCH_COUNT:
## 从匹配中提取出对应点对
## (queryIndex for the small object, trainIndex for the scene )
src_pts = np.float32([ kpts1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
dst_pts = np.float32([ kpts2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
## find homography matrix in cv2.RANSAC using good match points
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
## 掩模,用作绘制计算单应性矩阵时用到的点对
#matchesMask2 = mask.ravel().tolist()
## 计算图1的畸变,也就是在图2中的对应的位置。
h,w = img1.shape[:2]
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(canvas,[np.int32(dst)],True,(0,255,0),3, cv2.LINE_AA)
else:
print( "Not enough matches are found - {}/{}".format(len(good),MIN_MATCH_COUNT))
## (8) drawMatches
matched = cv2.drawMatches(img1,kpts1,canvas,kpts2,good,None)#,**draw_params)
## (9) Crop the matched region from scene
h,w = img1.shape[:2]
pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
dst = cv2.perspectiveTransform(pts,M)
perspectiveM = cv2.getPerspectiveTransform(np.float32(dst),pts)
found = cv2.warpPerspective(img2,perspectiveM,(w,h))
## (10) save and display
cv2.imwrite("matched.png", matched)
cv2.imwrite("found.png", found)
cv2.imshow("matched", matched);
cv2.imshow("found", found);
cv2.waitKey();cv2.destroyAllWindows()
我有一张全景图,以及在该全景图中看到的建筑物的较小图像。我想做的是识别那个较小图像中的建筑物是否在那个全景图像中,以及 2 个图像如何排列。
对于第一个示例,我使用的是全景图像的裁剪版本,因此像素是相同的。
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import math
# Load images
cwImage = cv2.imread('cw1.jpg',0)
panImage = cv2.imread('pan1.jpg',0)
# Prepare for SURF image analysis
surf = cv2.xfeatures2d.SURF_create(4000)
# Find keypoints and point descriptors for both images
cwKeypoints, cwDescriptors = surf.detectAndCompute(cwImage, None)
panKeypoints, panDescriptors = surf.detectAndCompute(panImage, None)
然后我使用 OpenCV 的 FlannBasedMatcher 找到两个图像之间的良好匹配:
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)
# Find matches between the descriptors
matches = flann.knnMatch(cwDescriptors, panDescriptors, k=2)
good = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good.append(m)
所以你可以看到,在这个例子中,它完美地匹配了图像之间的点。然后我找到单应性,并应用透视扭曲:
cwPoints = np.float32([cwKeypoints[m.queryIdx].pt for m in good
]).reshape(-1, 1, 2)
panPoints = np.float32([panKeypoints[m.trainIdx].pt for m in good
]).reshape(-1, 1, 2)
h, status = cv2.findHomography(cwPoints, panPoints)
warpImage = cv2.warpPerspective(cwImage, h, (panImage.shape[1], panImage.shape[0]))
结果是它完美地将较小的图像放在较大的图像中。
现在,我想在较小图像不是较大图像的像素完美版本的情况下执行此操作。
对于新的较小图像,关键点如下所示:
你可以看到,在某些情况下,它匹配正确,而在某些情况下,它不匹配。
如果我用这些匹配项调用 findHomography
,它将考虑所有这些数据点并得出一个无意义的扭曲视角,因为它基于正确的匹配项和不正确的匹配项比赛。
我正在寻找的是在检测良好匹配和调用 findHomography
之间缺少的步骤,我可以在其中查看匹配之间的关系,并因此确定哪些匹配是正确的。
我想知道 OpenCV 中是否有一个函数我应该在这一步中查看,或者这是否是我需要自己解决的问题,如果是的话我应该怎么做那个?
去年(2017.11.11)写了一篇关于在场景中寻找对象的博客。也许有帮助。这里是link。 https://zhuanlan.zhihu.com/p/30936804
环境:OpenCV 3.3 + Python 3.5
找到匹配项:
在场景中找到的对象:
代码:
#!/usr/bin/python3
# 2017.11.11 01:44:37 CST
# 2017.11.12 00:09:14 CST
"""
使用Sift特征点检测和匹配查找场景中特定物体。
"""
import cv2
import numpy as np
MIN_MATCH_COUNT = 4
imgname1 = "box.png"
imgname2 = "box_in_scene.png"
## (1) prepare data
img1 = cv2.imread(imgname1)
img2 = cv2.imread(imgname2)
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
## (2) Create SIFT object
sift = cv2.xfeatures2d.SIFT_create()
## (3) Create flann matcher
matcher = cv2.FlannBasedMatcher(dict(algorithm = 1, trees = 5), {})
## (4) Detect keypoints and compute keypointer descriptors
kpts1, descs1 = sift.detectAndCompute(gray1,None)
kpts2, descs2 = sift.detectAndCompute(gray2,None)
## (5) knnMatch to get Top2
matches = matcher.knnMatch(descs1, descs2, 2)
# Sort by their distance.
matches = sorted(matches, key = lambda x:x[0].distance)
## (6) Ratio test, to get good matches.
good = [m1 for (m1, m2) in matches if m1.distance < 0.7 * m2.distance]
canvas = img2.copy()
## (7) find homography matrix
## 当有足够的健壮匹配点对(至少4个)时
if len(good)>MIN_MATCH_COUNT:
## 从匹配中提取出对应点对
## (queryIndex for the small object, trainIndex for the scene )
src_pts = np.float32([ kpts1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
dst_pts = np.float32([ kpts2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
## find homography matrix in cv2.RANSAC using good match points
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
## 掩模,用作绘制计算单应性矩阵时用到的点对
#matchesMask2 = mask.ravel().tolist()
## 计算图1的畸变,也就是在图2中的对应的位置。
h,w = img1.shape[:2]
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(canvas,[np.int32(dst)],True,(0,255,0),3, cv2.LINE_AA)
else:
print( "Not enough matches are found - {}/{}".format(len(good),MIN_MATCH_COUNT))
## (8) drawMatches
matched = cv2.drawMatches(img1,kpts1,canvas,kpts2,good,None)#,**draw_params)
## (9) Crop the matched region from scene
h,w = img1.shape[:2]
pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
dst = cv2.perspectiveTransform(pts,M)
perspectiveM = cv2.getPerspectiveTransform(np.float32(dst),pts)
found = cv2.warpPerspective(img2,perspectiveM,(w,h))
## (10) save and display
cv2.imwrite("matched.png", matched)
cv2.imwrite("found.png", found)
cv2.imshow("matched", matched);
cv2.imshow("found", found);
cv2.waitKey();cv2.destroyAllWindows()