简体   繁体   English

OpenCV功能匹配多个图像

[英]OpenCV feature matching for multiple images

How can I optimise the SIFT feature matching for many pictures using FLANN? 如何使用FLANN优化许多图片的SIFT功能匹配?

I have a working example taken from the Python OpenCV docs. 我有一个从Python OpenCV文档中获取的工作示例。 However this is comparing one image with another and it's slow. 然而,这是将一个图像与另一个图像进行比较而且速度很慢。 I need it to search for features matching in a series of images (a few thousands) and I need it to be faster. 我需要它来搜索一系列图像(几千个)中匹配的特征,我需要它更快。

My current idea: 我目前的想法:

  1. Run through all the images and save the features. 浏览所有图像并保存功能。 How? 怎么样?
  2. Compare an image from a camera with this above base, and find the correct one. 将相机的图像与上面的基础进行比较,找到正确的图像。 How? 怎么样?
  3. Give me the result, matching image or something. 给我结果,匹配图像或其他东西。

http://docs.opencv.org/trunk/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.html 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()

UPDATE UPDATE

After trying out many things I might have come closer to the solution now. 在尝试了很多东西后,我现在可能已经接近解决方案了。 I hope it's possible to build the index and then search in it like this: 我希望有可能构建索引,然后在其中搜索如下:

flann_params = dict(algorithm=1, trees=4)
flann = cv2.flann_Index(npArray, flann_params)
idx, dist = flann.knnSearch(queryDes, 1, params={})

However I still haven't managed to build an accepted npArray to the flann_Index parameter. 但是我仍然没有设法为flann_Index参数构建一个接受的npArray。

loop through all images as image:
  npArray.append(sift.detectAndCompute(image, None))
npArray = np.array(npArray)

I never solved this in Python, however I switched environment to C++ where you get more OpenCV examples and don't have to use a wrapper with less documentation. 我从来没有在Python中解决这个问题,但是我将环境转换为C ++,你可以获得更多的OpenCV示例,而不必使用包含较少文档的包装器。

An example on the issue I had with matching in multiple files can be found here: https://github.com/Itseez/opencv/blob/2.4/samples/cpp/matching_to_many_images.cpp 关于我在多个文件中匹配的问题的示例可以在这里找到: https//github.com/Itseez/opencv/blob/2.4/samples/cpp/matching_to_many_images.cpp

Here are several pieces of my advice: 以下是我的一些建议:

  1. You should reduce the amount of point data by using proper techniques. 您应该使用适当的技术减少点数据的数量。
  2. Calculate the reference image repeatedly is a waste. 反复计算参考图像是一种浪费。 You should persistent all calculated reference. 你应该坚持所有计算参考。
  3. Do not put the calculate on a mobile device. 不要将计算放在移动设备上。 You'd better upload the calculated reference of a captured image to a powerful server and do the searching there. 您最好将计算出的捕获图像的参考上传到功能强大的服务器并在那里进行搜索。

This is a very interesting topic. 这是一个非常有趣的话题。 My ears are opening too. 我的耳朵也开了。

Along with the reply of @stanleyxu2005 I'd like to add some tips as to how to do the whole matching itself since I'm currently working of such a thing. 随着@ stanleyxu2005的回复,我想添加一些关于如何进行整个匹配的提示,因为我目前正在处理这样的事情。

  1. I strongly recommend to create some custom class that wraps around the cv::Mat but also stores various other essential pieces of data. 我强烈建议创建一些包装cv :: Mat的自定义类,但也存储各种其他必要的数据。 In my case I have an ImageContainer store the original image (that I will use for the final stitching), the processed one (grayscaled, undistorted etc.), its keypoints and the descriptors for those. 在我的情况下,我有一个ImageContainer存储原始图像(我将用于最终拼接),处理过的(灰度,未失真等),它的关键点和那些描述符。 By doing so you can access all the matching-relevant information in a pretty well organized well. 通过这样做,您可以在组织良好的井中访问所有匹配相关的信息。 You can either implement the keypoint extraction and descriptor generation in it or do that outside the class and just store the results in that container. 您可以在其中实现关键点提取和描述符生成,也可以在类外执行,只将结果存储在该容器中。
  2. Store all image containers in some kind of a structure (vector is usually a good choice) for easy access. 将所有图像容器存储在某种结构中(矢量通常是一个不错的选择),以便于访问。
  3. I also created a class called ImageMultiMatchContainer, which stores a pointer to a given query image (all images are query images), a vector with pointers to all train images (for a single query image of the image set all others are train images) that were matched to it and also a vector of the match vectors for each of those matches. 我还创建了一个名为ImageMultiMatchContainer的类,它存储指向给定查询图像的指针(所有图像都是查询图像),一个带有指向所有火车图像的指针(对于图像集的单个查询图像,所有其他图像都是火车图像)与它匹配,并且还匹配每个匹配的匹配向量的向量。 Here I stumbled across a storage issue namely - first you have to skip matching of an image with itself because it is pointless and second you have the problem of comparing two images two times and thus generating a considerable overhead if you have a lot of images. 在这里我偶然发现了存储问题 - 首先你必须跳过图像与自身的匹配,因为它没有意义,其次你有两次比较两个图像的问题,因此如果你有很多图像就会产生相当大的开销。 The second problem is due to the fact that we iterate through all images (query images) and compare them to the rest in the set (train images). 第二个问题是由于我们遍历所有图像(查询图像)并将它们与集合中的其余图像(火车图像)进行比较。 At some point we have image X (query) matched with image Y (train), but later we also have image Y (now query) matched with image X (now train). 在某些时候,我们有图像X(查询)与图像Y(火车)匹配,但后来我们也有图像Y(现在查询)与图像X(现在火车)匹配。 As you can see this is also pointless since it's basically matching the same pair of images twice. 正如你所看到的,这也是毫无意义的,因为它基本上匹配了同一对图像两次。 This can be solved (currently working on this) by creating a class (MatchContainer) that stores a pointer to each of the two images in a matched pair and also the match vector. 这可以通过创建一个类(MatchContainer)来解决(目前正在进行此操作),该类存储指向匹配对中的两个图像中的每一个的指针以及匹配向量。 You store this in a central location (in my case this is my matcher class) and for each image as query image you check the list of matched images of the train image. 您将其存储在一个中心位置(在我的情况下,这是我的匹配器类),并将每个图像存储为查询图像,您可以检查列车图像的匹配图像列表。 If it's empty then you create a new MatchContainer and add it to the rest of the MatchContainers. 如果它为空,则创建一个新的MatchContainer并将其添加到MatchContainers的其余部分。 If it's not then you look in it and see if the current query image is not present there (comparing pointers is a fast operation). 如果不是那么你查看它并查看当前查询图像是否不存在(比较指针是一个快速操作)。 If it is then you just pass the pointer to that MatchContainer's vector item that stores the matches for those two images. 如果是,那么你只需将指针传递给MatchContainer的矢量项,该矢量项存储这两个图像的匹配项。 If that is not the case, you do as if it's empty and create a new MatchContainer etc. MatchingContainers should be stored in a data structure with a small access times since you will be looking at them a lot and iterating from start to end costs too much time. 如果不是这样的话,你就好像它是空的并创建一个新的MatchContainer等.MatchingContainers应该存储在一个访问时间很短的数据结构中,因为你会看到它们很多,并且从头到尾迭代费用也是如此很多时间。 I'm considering using a map but maybe a tree of some sort can offer some advantages as well. 我正在考虑使用地图,但也许某种树也可以提供一些优势。
  4. The homography estimation is a very tricky part. 单应性估计是一个非常棘手的部分。 Here I recommend you look at bundle block adjustment . 在这里,我建议您查看捆绑块调整 I saw that the stitcher class in OpenCV has a BundleBase-class but haven't tested it yet to see what's in it. 我看到OpenCV中的stitcher类有一个BundleBase类,但还没有测试它看看它里面有什么。

A general recommendation is to look at the stitching process in OpenCV and read the source code. 一般建议是在OpenCV中查看拼接过程并阅读源代码。 The stitching pipeline is a straight forward set of processes and you just have to see how exactly you can implement the single steps. 拼接管道是一组直接的过程,您只需要了解如何实现单个步骤。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM