用 Java 中的 OpenCV 比较两个图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34762865/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Comparing two images with OpenCV in Java
提问by Smajl
I am trying to compare two images (determine whether they are similar or not) using the OpenCV library. I configured the java wrapper and found several tutorials (mostly in C/C++) that I am trying to rewrite into Java. I am using the feature detection approach.
我正在尝试使用 OpenCV 库比较两个图像(确定它们是否相似)。我配置了 java 包装器并找到了几个教程(主要是 C/C++),我试图将它们重写为 Java。我正在使用特征检测方法。
The problem is that the algorithm that I currently have does not produce any reasonable results (it claims that two similar images have nothing in common and finds matches between other two images that are completely different). Could someone suggest how should I use the openCV matcher to produce some reasonable results?
问题是我目前拥有的算法没有产生任何合理的结果(它声称两个相似的图像没有任何共同点,并在其他两个完全不同的图像之间找到匹配)。有人可以建议我应该如何使用 openCV 匹配器来产生一些合理的结果吗?
This is my code for the image comparison
这是我的图像比较代码
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);
}
}
Unfortunately, algorithms like SURF and SIFT are not available in the java wrapper so I am using ORB. I have little to no experience with computer vision, I am just trying to get this simple comparison algorithm work to produce some reasonable outcome. I would be glad for any help!
不幸的是,像 SURF 和 SIFT 这样的算法在 java 包装器中不可用,所以我使用的是 ORB。我对计算机视觉几乎没有经验,我只是想让这个简单的比较算法工作以产生一些合理的结果。我很乐意提供任何帮助!
EDIT: My use-case is running this algorithm against images taken from different angles. I updated my code to be better formatted.
编辑:我的用例是针对从不同角度拍摄的图像运行此算法。我更新了我的代码以更好地格式化。
Sample images to compare:
要比较的示例图像:
回答by Gilfoyle
Just my two cents:
只是我的两分钱:
There is access to SURF and SIFT in java: openCV DescriptorExtractor Reference. I tried the FREAK implementation three years back and found out, that there is some change happening to the binary descriptor when openCV passes them over to Java. It may be that ORB is subject to the same problem. Did you compare the data of the descriptors from c or c++ to the ones on the java side?
The brute force matcher finds the best matching feature from the train image for EVERY feature in the query image. Even if it looks completely different. You have to sift through the matches and drop bad ones. There exist several strategies, an easy one would be to just take the best 20% of the matches (but this will not drop ALL outlier). Progressive Sample Consensusperformed very well in my setup.
- Using Features to compare image similarity has it's pitfalls. Feature count and quality are varying with picture size and content, which makes it difficult to compare images globally (in case you wanna know which of two images is more similar to a reference than the other). You could estimate a transform from one image to the other with
Calib3d.findHomography(obj, scene, CV_RANSAC);
and use a normalized pixel difference of the overlapping areas.
在 java: openCV DescriptorExtractor Reference 中可以访问 SURF 和 SIFT 。三年前我尝试了 FREAK 实现,发现当 openCV 将二进制描述符传递给 Java 时,二进制描述符发生了一些变化。ORB 可能会遇到同样的问题。您是否将 c 或 c++ 中的描述符数据与 java 端的数据进行了比较?
蛮力匹配器从训练图像中为查询图像中的每个特征找到最佳匹配特征。即使它看起来完全不同。你必须筛选匹配并丢弃坏的。有几种策略,一个简单的方法是只选择最好的 20% 的匹配项(但这不会删除所有异常值)。Progressive Sample Consensus在我的设置中表现得非常好。
- 使用特征来比较图像相似性有其缺陷。特征数量和质量随图片大小和内容而变化,这使得全局比较图像变得困难(如果您想知道两个图像中哪一个比另一个更类似于参考)。您可以估计从一个图像到另一个图像的变换,
Calib3d.findHomography(obj, scene, CV_RANSAC);
并使用重叠区域的归一化像素差异。
回答by olympia
As stated in this SO Question, the easiest and most straightforward way is to compare histograms. If your algorithm only needs to work for a specific dataset, try using different color channels to see where images in your set share most similarity.
正如这个 SO Question中所述,最简单和最直接的方法是比较直方图。如果您的算法只需要针对特定数据集工作,请尝试使用不同的颜色通道来查看您的集合中哪些图像最相似。
The histogram approach might seem impractical, but given the color similarity of your images I believe this could be of some use.
直方图方法可能看起来不切实际,但考虑到图像的颜色相似性,我相信这可能会有用。
After comparing your two images' histograms in Photoshop:
在 Photoshop 中比较两个图像的直方图后: