OpenCV 多图像特征匹配
我该如何使用FLANN来优化多个图片的SIFT特征匹配呢?
我有一个从Python OpenCV文档中得到的示例代码。不过这个代码是用来比较一张图片和另一张图片的,速度比较慢。我需要它能在几千张图片中快速找到特征匹配。
我现在的想法是:
- 遍历所有图片并保存它们的特征。怎么做呢?
- 用相机拍的一张图片去和之前保存的特征进行比较,找到匹配的那一张。怎么做呢?
- 给我结果,匹配的图片或者其他什么东西。
import sys # For debugging only import numpy as np import cv2 from matplotlib import pyplot as plt MIN_MATCH_COUNT = 10 img1 = cv2.imread('image.jpg',0) # queryImage img2 = cv2.imread('target.jpg',0) # trainImage # Initiate SIFT detector sift = cv2.SIFT() # find the keypoints and descriptors with SIFT kp1, des1 = sift.detectAndCompute(img1,None) 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) # store all the good matches as per Lowe's ratio test. good = [] for m,n in matches: if m.distance 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) 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) img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA) else: print "Not enough matches are found - %d/%d" % (len(good),MIN_MATCH_COUNT) matchesMask = None draw_params = dict(matchColor = (0,255,0), # draw matches in green color singlePointColor = None, matchesMask = matchesMask, # draw only inliers flags = 2) img3 = cv2.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params) plt.imshow(img3, 'gray'),plt.show()
更新
经过尝试很多方法后,我可能离解决方案更近了一步。我希望能先建立一个索引,然后像这样在里面搜索:
flann_params = dict(algorithm=1, trees=4) flann = cv2.flann_Index(npArray, flann_params) idx, dist = flann.knnSearch(queryDes, 1, params={})
不过我还是没能成功构建一个被flann_Index参数接受的npArray。
loop through all images as image: npArray.append(sift.detectAndCompute(image, None)) npArray = np.array(npArray)
3 个回答
4
这里有几点建议:
- 你应该用合适的方法来减少数据点的数量。
- 反复计算参考图像是浪费时间。你应该保存所有已经计算好的参考。
- 不要在手机上进行计算。最好把捕捉到的图像的计算结果上传到一个强大的服务器上去进行搜索。
这是一个非常有趣的话题。我也在认真听呢。
6
在@stanleyxu2005的回复基础上,我想分享一些关于如何进行匹配的小技巧,因为我现在正在做这方面的工作。
- 我强烈建议创建一个自定义类,封装cv::Mat,并且存储一些其他重要的数据。在我的案例中,我有一个叫做ImageContainer的类,它存储了原始图像(我会用来进行最终拼接)、处理后的图像(灰度化、去畸变等)、关键点和这些关键点的描述符。这样做可以让你以一种相对有序的方式访问所有与匹配相关的信息。你可以在这个类里面实现关键点提取和描述符生成,或者在类外完成这些操作,然后把结果存储在这个容器里。
- 把所有的图像容器存储在某种结构中(通常使用vector会比较好),这样可以方便访问。
- 我还创建了一个叫做ImageMultiMatchContainer的类,它存储一个指向给定查询图像的指针(所有图像都是查询图像),一个指向所有与之匹配的训练图像的指针向量(对于一张查询图像,其他的都是训练图像),以及每个匹配的匹配向量。在这里我遇到了一个存储问题:首先,你必须跳过与自身匹配的图像,因为这没有意义;其次,你会遇到比较两张图像两次的问题,这样会产生相当大的开销,尤其是当你有很多图像时。第二个问题是因为我们要遍历所有图像(查询图像),并将它们与集合中的其他图像(训练图像)进行比较。比如,我们有图像X(查询)与图像Y(训练)匹配,但后来我们又有图像Y(现在是查询)与图像X(现在是训练)匹配。显然,这样做是没有意义的,因为实际上是重复匹配同一对图像。这个问题可以通过创建一个类(MatchContainer)来解决,它存储匹配对中每张图像的指针以及匹配向量。你把这个存储在一个中心位置(在我的案例中是我的匹配器类),对于每张图像作为查询图像,你检查训练图像的匹配图像列表。如果列表为空,就创建一个新的MatchContainer并添加到其他MatchContainers中。如果不为空,就查看当前查询图像是否已经存在(比较指针是一个快速的操作)。如果存在,就直接使用那个MatchContainer中存储的匹配信息。如果不存在,就像它是空的一样,创建一个新的MatchContainer等等。MatchContainers应该存储在一个访问时间较短的数据结构中,因为你会频繁查看它们,从头到尾遍历会耗费太多时间。我在考虑使用map,但也许某种树结构也能提供一些优势。
- 单应性估计是一个非常棘手的部分。在这里我建议你看看束块调整。我看到OpenCV中的拼接类有一个BundleBase类,但还没有测试过里面的内容。
一般来说,建议你查看OpenCV中的拼接过程,并阅读源代码。拼接流程是一系列直接的处理步骤,你只需要看看如何具体实现每一个步骤。
6
我之前在Python中没有解决过这个问题,不过我换到了C++环境,在这里你能找到更多OpenCV的例子,而且不需要使用文档较少的封装库。
关于我在多个文件中匹配时遇到的问题,可以在这里找到一个例子: https://github.com/Itseez/opencv/blob/2.4/samples/cpp/matching_to_many_images.cpp