为什么RANSAC不能为我的代码工作?

时间:2017-03-01 18:06:49

标签: python opencv sift ransac

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

package com.example.appdeveloper.appname;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.os.Environment;
import android.view.SurfaceView;
import java.io.File;
import java.io.FileOutputStream;


public class PhotoCapture {

    static Camera camera = null;
    static int pic_number = 0;

    public static void takeSnapShots(Context context, int face) {

        SurfaceView surface = new SurfaceView(context);
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        int cameraCount = Camera.getNumberOfCameras();

        for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
            Camera.getCameraInfo(camIdx, cameraInfo);
            if (cameraInfo.facing == face) {
                try {
                    camera = Camera.open(camIdx);
                    camera.setPreviewDisplay(surface.getHolder());
                    camera.startPreview();
                    camera.takePicture(null, null, jpegCallback);
                    camera.stopPreview();
                    camera.release();
                    camera = null;
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    break;
                }
            }
        }
    }

    private static Camera.PictureCallback jpegCallback = new Camera.PictureCallback() {

        public void onPictureTaken(byte[] data, Camera camera) {
            String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)+ File.separator+"picure"+(++pic_number)+".jpg";
            File pictureFile = new File(path);

            try {
                FileOutputStream outputStream = new FileOutputStream(pictureFile);
                Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
                Matrix mtx = new Matrix();
                mtx.setRotate(90);
                realImage = Bitmap.createBitmap(realImage, 0, 0, realImage.getWidth(), realImage.getHeight(), mtx, true);
                realImage.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
                outputStream.close();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            finally {
                camera.stopPreview();
                camera.release();
                camera = null;
            }
        }
    };
}

但是,当我尝试执行此操作时,我只会收到如下错误:

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)

当我按照此链接中的教程http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.html进行操作时,代码运行时没有错误。

感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

您没有注意或者没有理解他们正在解释的内容。我建议你阅读full tutorials。您从未将SIFT在一个图像中找到的关键点与SIFT在第二个图像中找到的关键点进行匹配。

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()

现在问题的关键在于SIFT只能找到整洁的关键点及其描述符。与第二张图像相比,它们不是自动的。我们需要自己做。 SIFT真正做的是在this tutorial中巧妙地解释了。如有疑问,请抽奖!或打印。 SIFT实际上发布的内容应该是相当明显的。在脚本开头取消注释matplotlib导入。

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

这是实际比较图像的部分。它通过关键点并基于一些距离计算比较最近的k(2)个邻居的描述符。它对技术细节有点模糊,但在this tutorial中得到了很好的解释。这是你的例子中没有的部分。

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)

现在我们可以在两个图像中创建点列表并计算透视变换。再说一次,CV没有保姆,在没有至少4分的情况下找不到视角 - 进行检查并提高自己比CV更好的错误。未来的自我将会感恩。匹配作为元组[(a,aa), (b,bb)...]的列表返回,我们只需要单个字母(关键点),将列表转换为numpy数组并使用切片比使用for循环更快例子(我猜测,当有疑问时 - 测试)。

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但我无法检查。对于他们的示例谷物图像我得到:

>>> 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]])

这似乎是合理的。

发布的评论的答案不适合另一条评论。

他们像我们一样完成同样的事情,他们对此更加明确。要查看会发生什么,您需要密切关注发布链接中的以下行:

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

我们做同样的事情 - &gt;首先,我们找到关键点并计算它们的描述符然后我们匹配它们。他们找到关键点,然后计算描述符(2行),但在python中,ALG.detectAndCompute方法已经返回关键点和描述符,因此不需要像他们那样进行单独的调用。在第一次循环迭代中查看它,i=0这意味着你有i*4+n = n

 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中对应

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检测器和描述符计算器以及带有标准汉明的BruteForceMatcher作为距离测量。请参阅ORB tutorialBFMatcher tutorial

我刚刚使用了SIFT检测器和描述符计算器与FlannBasedMatcher,这是唯一的区别。所有其他步骤都是一样的。