为什么RANSAC无法使用我的代码? [英] Why is RANSAC not working for my code?

查看:297
本文介绍了为什么RANSAC无法使用我的代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在2张图像之间找到基本矩阵,然后使用RANSAC对其进行转换.我首先使用SIFT来检测关键点,然后应用RANSAC:

I am trying to find fundamental matrix between 2 images and then transform them using RANSAC. I first use SIFT to detect keypoints and then apply RANSAC:

img1 = cv2.imread("im0.png", 0) # queryImage
img2 = cv2.imread("im1.png", 0)  # trainImage

    # Initiate SIFT detector
sift = sift = cv2.xfeatures2d.SIFT_create()

    # find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

src = np.float32([points.pt for points in kp1]).reshape(-1, 1, 2)
dst = np.float32([points.pt for points in kp2]).reshape(-1, 1, 2)

H, masked = cv2.findHomography(src, dst, cv2.RANSAC, 5.0)

但是,当我尝试执行此操作时,只会显示以下错误:

However, when I try to execute this, I just get an error shown below:

Traceback (most recent call last):
File "sift2.py", line 29, in <module>
M, mask = cv2.findHomography(src, dst, cv2.RANSAC, 5.0)
cv2.error: /tmp/opencv3-20161119-29160-138ov36/modules/calib3d/src/fundam.cpp:349: error: (-215) src.checkVector(2) == dst.checkVector(2) in function findHomography

当我按照此链接中的教程进行操作时: http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.html ,该代码可以正常运行.

Whereas when I follow the tutorial in this link: http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.html , the code runs without errors.

感谢您的帮助!

推荐答案

您没有注意或不了解他们在解释什么.我建议您阅读完整教程.您从未将SIFT在第二张图片中找到的关键点与SIFT在第二张图片中找到的关键点匹配.

You're not paying attention or are not understanding what they're explaining. I recommend you read the full tutorials. You never matched the keypoints found by SIFT in one image to keypoints found by SIFT in the second image.

import cv2
import numpy as np
#import matplotlib.pyplot as plt

#explicit is better than implicit cv2.IMREAD_GRAYSCALE is better than 0
img1 = cv2.imread("img0.png", cv2.IMREAD_GRAYSCALE) # queryImage
img2 = cv2.imread("img1.png", cv2.IMREAD_GRAYSCALE)  # trainImage
#CV doesn't hold hands, do the checks.
if (img1 is None) or (img2 is None):
    raise IOError("No files {0} and {1} found".format("img0.png", "img1.png"))

# Initiate SIFT detector
sift = cv2.xfeatures2d.SIFT_create() 

kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

确保像检查图像一样对SIFT进行检查.特别是如果您打算以此编写应用程序,因为在较早的cv版本中,它是cv2.SIFT().

Make sure you do the checks for SIFT just like you should for images. Especially if you plan on writing an app out of this because in older cv versions it's cv2.SIFT().

现在,问题的症结在于SIFT只能找到整洁的关键点及其描述符.它们不会自动与第二张图片进行比较.我们需要自己做.在本教程中,对SIFT的真正作用进行了很好的解释.如有疑问,请抽奖!或打印. SIFT实际发出的内容应该很明显.在脚本开头取消注释matplotlib导入.

Now the crux of your problem is that SIFT just finds neat keypoints and their descriptors. They're not automagically compared to the second image. We need to do that ourselves. What SIFT really does is neatly explained in this tutorial. When in doubt draw! Or print. It's should be fairly obvious what SIFT actually gives out like this. Uncomment matplotlib import at the start of the script.

tmp1 = cv2.drawKeypoints(img1, kp1)
tmp2 = cv2.drawKeypoints(img2, kp2)
plt.imshow(tmp1)
plt.show()
plt.imshow(tmp2)
plt.show()

这是实际比较图像的部分.它遍历关键点,并根据一些距离计算比较最近的k(2)个邻居的描述符.在技​​术细节上有些含糊,但在本教程中进行了巧妙地解释一个>.这是您的示例中没有的部分.

This is the part that actually compares the images. It goes through the keypoints and compares the descriptors of the nearest k (2) neighbours based on some distance calculation. It's a bit vague on the technical details but neatly explained in this tutorial. This is the part you don't have in your example.

index_params = dict(algorithm = 0, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)

matches = flann.knnMatch(des1, des2, k=2)
matches = np.asarray(matches)

现在,我们可以在两个图像中创建点列表并计算透视变换.同样,简历不容忍,没有至少4点就找不到透视图-进行检查,使自己比CV更好地犯错.未来的自我将心存感激.匹配项以元组[(a,aa), (b,bb)...]的列表形式返回,我们只需要单个字母(关键点),将列表转换为numpy数组并使用切片比像在其示例中那样使用for循环要快(我猜,如有疑问,请进行测试.)

Now we can create the lists of points in both image and calculate the perspective transformation. Again, CV doesn't babysit, perspective can't be found without at least 4 points - make the checks and raise yourself nicer errors than CV does. Future self will be thankful. Matches are returned as a list of tuples [(a,aa), (b,bb)...] and we only want the single letters (the keypoints), it's faster to cast the list to numpy array and use slicing than it is using for loops like in their examples (I'm guessing, when in doubt - test).

if len(matches[:,0]) >= 4:
    src = np.float32([ kp1[m.queryIdx].pt for m in matches[:,0] ]).reshape(-1,1,2)
    dst = np.float32([ kp2[m.trainIdx].pt for m in matches[:,0] ]).reshape(-1,1,2)

    H, masked = cv2.findHomography(src, dst, cv2.RANSAC, 5.0)
else:
    raise AssertionError("Can't find enough keypoints.")

这对于我在OpenCv 2.4.9中的示例图像很有效,我希望它可以直接转移到CV3,但是我无法检查.对于他们的谷物图像示例,我得到:

This works for me for their example images in OpenCv 2.4.9, I hope it's directly transferable to CV3 but I have no way of checking. For their example cereal image I get:

>>> H
array([[  4.71257834e-01,  -1.93882419e-01,   1.18225742e+02],
       [  2.47062711e-02,   3.79364095e-01,   1.60925457e+02],
       [ -1.21517456e-04,  -4.95488261e-04,   1.00000000e+00]])

这似乎是有道理的.

他们做的和我们做的完全一样,只是更加明确.要查看会发生什么情况,您需要密切注意已发布链接中的以下几行:

They do the exact same thing like we do, they're just bit more explicit about it. To see what happens you need to pay close attention to the following lines in your posted link:

  • 第244-255行定义了可用算法的名称
  • 281-284行选择检测器,描述符和匹配器算法
  • 第289-291行实例化检测器,描述符和匹配器算法
  • 在第315行找到第一个图像关键点
  • 在第316行上计算第一图像关键点描述符
  • 在第328行找到第二个图像关键点
  • 在第329行上计算第二个图像关键点描述符
  • 在行330上,第一图像关键点和第二图像关键点和描述符已匹配
  • 然后完成一些透视变换

我们做的完全相同->首先,找到关键点并计算它们的描述符,然后将它们匹配.他们找到关键点,然后计算描述符(两行),但是在python中,ALG.detectAndCompute方法已经返回了关键点和描述符,因此不需要像它们那样进行单独的调用.在第一个循环迭代中i=0时检查一下,这意味着i*4+n = n您具有:

We do exactly the same thing -> first we find keypoints and calculate their descriptors and then we match them. They find keypoints and then calculate descriptors (2 lines) but in python the ALG.detectAndCompute method already returns the keypoints and descriptors so there's no need to have separate invocations like they do. Check it out, in the first loop iteration when i=0 which means that i*4+n = n you have:

 static const char* ddms[] =
 {
    "ORBX_BF", "ORB", "ORB", "BruteForce-Hamming",
    // 0         1      2          3
    //shortened for brevity
      0
    //4
    ....

这意味着

const char* name = ddms[i*4];               // --> ORBX_BF
const char* detector_name = ddms[i*4+1];    // --> ORB
const char* descriptor_name = ddms[i*4+2];  // --> ORB
const char* matcher_name = ddms[i*4+3];     // --> BruteForce_Hamming

..... // shortened

Ptr<FeatureDetector> detector = FeatureDetector::create(detector_name);
Ptr<DescriptorExtractor> descriptor = DescriptorExtractor::create(descriptor_name);
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(matcher_name);

在python中对应于

which corresponds in python to

orb = cv2.ORB_create()
detector = orb.detect    # the pythonic way would be to just call 
descriptor = orb.compute # orb.detectAndCompute
matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

因此,他们执行了与我相同的所有步骤,也就是本例,只是他们使用了ORB检测器和描述符计算器以及BrutedForceMatcher和标准化Hamming作为距离度量.请参见 ORB教程

So they did all the same steps as I did, that is the example did, except they used the ORB detector and descriptor calculator and BruteForceMatcher with normed Hamming as the distance measure. See ORB tutorial and BFMatcher tutorial.

我只是将SIFT检测器和描述符计算器与FlannBasedMatcher一起使用,这是唯一的区别.其他所有步骤都相同.

I just used the SIFT detector and descriptor calculator with FlannBasedMatcher, that is the only difference. All the other steps are the same.

这篇关于为什么RANSAC无法使用我的代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆