在Java中使用OpenCV比较两张图片

15

我正在尝试使用OpenCV库比较两张图片(确定它们是否相似)。我配置了Java包装器并找到了几个教程(主要是C / C ++),我正在尝试将其改写为Java。我正在使用特征检测方法。

问题在于我当前的算法不能产生任何合理的结果(它声称两个相似的图像没有共同之处,并在其他两个完全不同的图像之间找到匹配项)。是否有人能建议我如何使用openCV匹配器来产生一些合理的结果?

这是我用于图像比较的代码

private static void compareImages(String path1, String path2) {
    System.out.println(path1 + "-" + path2);

    FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
    DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);

    DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);

    // first image
    Mat img1 = Imgcodecs.imread(path1, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
    Mat descriptors1 = new Mat();
    MatOfKeyPoint keypoints1 = new MatOfKeyPoint();

    detector.detect(img1, keypoints1);
    descriptor.compute(img1, keypoints1, descriptors1);

    // second image
    Mat img2 = Imgcodecs.imread(path2, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
    Mat descriptors2 = new Mat();
    MatOfKeyPoint keypoints2 = new MatOfKeyPoint();

    detector.detect(img2, keypoints2);
    descriptor.compute(img2, keypoints2, descriptors2);

    // match these two keypoints sets
    MatOfDMatch matches = new MatOfDMatch();
    matcher.match(descriptors1, descriptors2, matches);

    for (DMatch m : matches.toArray()) {
      // how to use these values to detect the similarity? They seem to be way off
      // all of these values are in range 50-80 which seems wrong to me
      System.out.println(m.distance);
    }
  }

不幸的是,像SURF和SIFT这样的算法在Java包装器中不可用,因此我正在使用ORB。我几乎没有计算机视觉方面的经验,我只是尝试让这个简单的比较算法工作以产生一些合理的结果。我会很高兴得到任何帮助!

编辑:我的用例是对从不同角度拍摄的图像运行此算法。我更新了代码以更好地格式化。

要比较的示例图像:

输入图像描述 输入图像描述


可能会有用:https://dev59.com/vG_Xa4cB1Zd3GeqP6vHZ - GPPK
链接中的算法似乎与我这里的完全相同... 仍然产生非常糟糕的结果。我只想加载两个图像并生成某种值,指示它们的相似性。 - Smajl
只是一点提示:我试过使用cv::Stitcher类拼接两个图像,该类内部使用xfeatures2d::SURF,但拼接失败了。我认为这意味着通过SURF识别图像相似度很困难。 - sturkmen
2个回答

5

我的两分意见:

  1. 在Java中可以使用 SURF 和 SIFT:openCV DescriptorExtractor 参考文献。三年前,我尝试了 FREAK 实现,并发现当 openCV 将二进制描述符传递到 Java 时,发生了一些变化。可能 ORB 也面临同样的问题。你是否将来自 c 或 c++ 的描述符数据与 Java 端的描述符数据进行了比较?

  2. 暴力匹配器会为查询图像中的每个要素找到训练图像中最佳匹配的要素。即使它看起来完全不同。你必须筛选出匹配项并删除错误的匹配项。存在几种策略,其中一种简单的策略是只选择最佳 20% 的匹配项(但这并不能删除所有异常值)。Progressive Sample Consensus 在我的设置中表现得非常好。

  3. 使用特征比较图像相似性有其缺陷。由于图片大小和内容不同,特征数量和质量也会不同,这使得全局比较图片变得困难(如果你想知道两幅图像哪一个与参考图像更相似)。你可以通过 Calib3d.findHomography(obj, scene, CV_RANSAC); 估计从一个图像到另一个图像的转换,并使用重叠区域的标准化像素差异。

感谢您的答复。关于SURF和SIFT - 它们列在可用算法的枚举中,但是如果您尝试使用它们,您会得到“不支持”的异常。我必须使用一些旧版本的OpenCV来访问它们。如果您能提供比我更好的示例Java代码,因为我尝试的每种评估图像相似性的策略都产生了非常糟糕的结果,我会非常高兴的。现在,我真的陷入了困境 :/ - Smajl

0
此SO问题所述,最简单和直接的方法是比较直方图。如果您的算法只需要针对特定数据集工作,请尝试使用不同的颜色通道来查看图像在哪些地方具有最相似性。
直方图方法可能看起来不切实际,但考虑到您的图像颜色相似性,我认为这可能会有所帮助。
在Photoshop中比较两个图像的直方图后:

histogram comparison


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接