OpenCV功能匹配多个图像

时间:2014-03-08 17:00:10

标签: python opencv sift flann

如何使用FLANN优化许多图片的SIFT功能匹配?

我有一个从Python OpenCV文档中获取的工作示例。然而,这是将一个图像与另一个图像进行比较而且速度很慢。我需要它来搜索一系列图像中匹配的特征(几千个),我需要它更快。

我目前的想法:

  1. 浏览所有图像并保存功能。怎么样?
  2. 将来自相机的图像与上面的基础进行比较,找到正确的图像。怎么样?
  3. 给我结果,匹配图像或其他东西。
  4. http://docs.opencv.org/trunk/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.html

    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 个答案:

答案 0 :(得分:4)

我从来没有在Python中解决这个问题,但是我将环境转换为C ++,你可以获得更多的OpenCV示例,而不必使用包含较少文档的包装器。

有关我在多个文件中进行匹配的问题的示例,请访问:https://github.com/Itseez/opencv/blob/2.4/samples/cpp/matching_to_many_images.cpp

答案 1 :(得分:3)

以下是我的一些建议:

  1. 您应该使用适当的技术减少点数据的数量。
  2. 反复计算参考图像是一种浪费。你应该坚持所有计算参考。
  3. 请勿将计算结果放在移动设备上。您最好将计算出的捕获图像的参考上传到功能强大的服务器并在那里进行搜索。
  4. 这是一个非常有趣的话题。我的耳朵也开了。

答案 2 :(得分:3)

随着@ stanleyxu2005的回复,我想添加一些关于如何进行整个匹配的提示,因为我目前正在处理这样的事情。

  1. 我强烈建议创建一些包装cv :: Mat的自定义类,但也存储各种其他必要的数据。在我的情况下,我有一个ImageContainer存储原始图像(我将用于最终拼接),处理过的(灰度,未失真等),它的关键点和那些描述符。通过这样做,您可以在组织良好的井中访问所有匹配相关的信息。您可以在其中实现关键点提取和描述符生成,也可以在类外执行,只将结果存储在该容器中。
  2. 将所有图像容器存储在某种结构中(矢量通常是一个不错的选择),以便于访问。
  3. 我还创建了一个名为ImageMultiMatchContainer的类,它存储指向给定查询图像的指针(所有图像都是查询图像),一个带有指向所有列车图像的指针的矢量(对于图像集的单个查询图像,所有其他都是列车与它匹配的图像)以及每个匹配的匹配向量的向量。在这里我偶然发现了存储问题 - 首先你必须跳过图像与自身的匹配,因为它没有意义,其次你有两次比较两个图像的问题,因此如果你有很多图像就会产生相当大的开销。第二个问题是由于我们遍历所有图像(查询图像)并将它们与集合中的其余图像(火车图像)进行比较。在某些时候,我们有图像X(查询)与图像Y(火车)匹配,但后来我们也有图像Y(现在查询)与图像X(现在火车)匹配。正如你所看到的,这也是毫无意义的,因为它基本上匹配了同一对图像两次。这可以通过创建一个类(MatchContainer)来解决(目前正在进行此操作),该类存储指向匹配对中的两个图像中的每一个的指针以及匹配向量。您将其存储在一个中心位置(在我的情况下,这是我的匹配器类),并将每个图像存储为查询图像,您可以检查列车图像的匹配图像列表。如果它为空,则创建一个新的MatchContainer并将其添加到MatchContainers的其余部分。如果不是那么你查看它并查看当前查询图像是否不存在(比较指针是一个快速操作)。如果是,那么你只需将指针传递给MatchContainer的矢量项,该矢量项存储这两个图像的匹配项。如果不是这样的话,你就好像它是空的并创建一个新的MatchContainer等.MatchingContainers应该存储在一个访问时间很短的数据结构中,因为你会看到它们很多,并且从头到尾迭代费用也是如此很多时间。我正在考虑使用地图,但也许某种树也可以提供一些优势。
  4. 单应性估计是一个非常棘手的部分。在这里,我建议您查看捆绑块调整。我看到OpenCV中的stitcher类有一个BundleBase类,但还没有测试它,看看它里面有什么。
  5. 一般建议是在OpenCV中查看拼接过程并阅读源代码。拼接管道是一组直接的过程,您只需要了解如何实现单个步骤。