匹配图像并使用 SURF 确定最佳匹配

Matching image and determine best match using SURF

我一直在尝试使用 EMGU Example SURFFeature 来确定图像是否在图像集合中。但是我在理解如何确定是否找到匹配项时遇到了问题。

.........原图......................Scene_1(匹配)......................Scene_2(不匹配)

..................... ......................

我一直在查看文档并花了数小时寻找可能的解决方案,以了解如何确定图像是否相同。 正如您在下面的图片中看到的,两者都找到了匹配项。

很明显,我要查找的匹配项(连接线)更多,但我如何在代码中检查这一点?

问:如何筛选出好的匹配项?

我的目标是能够将输入图像(从网络摄像头捕获)与数据库中的图像集合进行比较。但在我可以将所有图像保存到数据库之前,我需要知道我可以将输入与哪些值进行比较。 (例如将对象关键点保存在数据库中)

这是我的示例代码(匹配部分):

private void match_test()
{
    long matchTime;
    using (Mat modelImage = CvInvoke.Imread(@"images\input.jpg", LoadImageType.Grayscale))
    using (Mat observedImage = CvInvoke.Imread(@"images.jpg", LoadImageType.Grayscale))
    {
        Mat result = DrawMatches.Draw(modelImage, observedImage, out matchTime);
        //ImageViewer.Show(result, String.Format("Matched using {0} in {1} milliseconds", CudaInvoke.HasCuda ? "GPU" : "CPU", matchTime));
        ib_output.Image = result;
        label7.Text = String.Format("Matched using {0} in {1} milliseconds", CudaInvoke.HasCuda ? "GPU" : "CPU", matchTime);
     }
}

public static void FindMatch(Mat modelImage, Mat observedImage, out long matchTime, out VectorOfKeyPoint modelKeyPoints, out VectorOfKeyPoint observedKeyPoints, VectorOfVectorOfDMatch matches, out Mat mask, out Mat homography)
{
    int k = 2;
    double uniquenessThreshold = 0.9;
    double hessianThresh = 800;

    Stopwatch watch;
    homography = null;

    modelKeyPoints = new VectorOfKeyPoint();
    observedKeyPoints = new VectorOfKeyPoint();

    using (UMat uModelImage = modelImage.ToUMat(AccessType.Read))
    using (UMat uObservedImage = observedImage.ToUMat(AccessType.Read))
    {
        SURF surfCPU = new SURF(hessianThresh);
        //extract features from the object image
        UMat modelDescriptors = new UMat();
        surfCPU.DetectAndCompute(uModelImage, null, modelKeyPoints, modelDescriptors, false);

        watch = Stopwatch.StartNew();

        // extract features from the observed image
        UMat observedDescriptors = new UMat();
        surfCPU.DetectAndCompute(uObservedImage, null, observedKeyPoints, observedDescriptors, false);

        //Match the two SURF descriptors
        BFMatcher matcher = new BFMatcher(DistanceType.L2);
        matcher.Add(modelDescriptors);

        matcher.KnnMatch(observedDescriptors, matches, k, null);

        mask = new Mat(matches.Size, 1, DepthType.Cv8U, 1);
        mask.SetTo(new MCvScalar(255));

        Features2DToolbox.VoteForUniqueness(matches, uniquenessThreshold, mask);
        int nonZeroCount = CvInvoke.CountNonZero(mask);

        if (nonZeroCount >= 4)
        {
            nonZeroCount = Features2DToolbox.VoteForSizeAndOrientation(modelKeyPoints, observedKeyPoints,
               matches, mask, 1.5, 20);

            if (nonZeroCount >= 4)
                homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(modelKeyPoints,
                   observedKeyPoints, matches, mask, 2);
        }

        watch.Stop();
    }

    matchTime = watch.ElapsedMilliseconds;
}

我真的觉得我离解决方案不远了..希望有人能帮助我

Features2DToolbox.GetHomographyMatrixFromMatchedFeatures 退出时,mask 矩阵 is updated to have zeros 其中匹配是异常值(即,在计算的单应性下不对应)。因此,在 mask 上再次调用 CountNonZero 应该会给出匹配质量的指示。

我看到您想要将匹配项分类为 "good" 或 "bad" 而不是仅仅将多个匹配项与单个图像进行比较;从您问题中的示例来看,合理的阈值可能是输入图像中找到的关键点的 1/4。你可能也想要一个绝对最小值,因为如果没有一定数量的证据,你就不能真正认为某件事是好的匹配。因此,例如

bool FindMatch(...) {
    bool goodMatch = false;
    // ...
    homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(...);
    int nInliers = CvInvoke.CountNonZero(mask);
    goodMatch = nInliers >= 10 && nInliers >= observedKeyPoints.size()/4;
    // ...
    return goodMatch;
}

在没有达到计算 homography 的分支上,当然 goodMatch 只是在初始化时保持 false。数字 10 和 1/4 有点随意,将取决于您的应用程序。

(警告:以上内容完全来自阅读文档;我还没有真正尝试过。)