[编辑] 我设计了一些用于图像比较的代码。匹配的部分仍然有点缺陷,我希望得到一些帮助。该项目可以在 - GitHub 找到.
我有这两张图片 Img1 和 Img2:
当我在 openCV 中使用以下命令时
Mat img1 = Highgui.imread("mnt/sdcard/IMG-20121228.jpg");
Mat img2 = Highgui.imread("mnt/sdcard/IMG-20121228-1.jpg");
try{
double l2_norm = Core.norm( img1, img2 );
tv.setText(l2_norm+"");
} catch(Exception e) {
//image is not a duplicate
}
我得到 l2_norm 的 double 值。对于重复的图像对,此 double 值会有所不同。但如果图像不同,则会引发异常。这是我识别重复图像的方式吗?或者有没有更好的方法?我已经广泛搜索并找不到一个真正令人信服的答案。我想要关于如何比较两个图像并根据图像获得 true
或 false
的 bool 值的代码和解释。
编辑
Scalar blah= Core.sumElems(img2);
Scalar blah1=Core.sumElems(img1);
if(blah.equals(blah1))
{
tv.setText("same image");
}
}
我试过这个,但 if
条件永远不会满足。我假设存在一些差异,但 Scalar
没有 compare
函数。我该怎么办?
编辑
try{
Scalar blah= Core.sumElems(img2);
Scalar blah1=Core.sumElems(img1);
String b=blah.toString();
String b1=blah1.toString();
System.out.println(b+" "+b1);
double comp=b.compareTo(b1);
tv.setText(""+comp);
}
这种方法又是有缺陷的。虽然它可以用于比较准确度不错的图像,但当图像大小不同时,它就会失败。
当图像尺寸不同并且我打印标量值时,我会得到:
[9768383.0, 1.0052889E7, 1.0381814E7, 0.0] [1.5897384E7, 1.6322252E7, 1.690251E7, 0.0]
与比较相同尺寸的图像相比,第二个和第三个数字之间的差异虽然不大,但相当大。然而,第一个数字的变化最大。
比较两张图片内容的最佳最快方法是什么?
[编辑]
我正在使用我找到的代码 here .
我不知道如何初始化 MatOfKeyPoint
变量 keypoints
和 logoKeypoints
。这是我的代码 fragment :
FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
//FeatureDetector detector = FeatureDetector.create(FeatureDetector.FAST);
//Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGBA2RGB);
//Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGBA2RGB);
DescriptorExtractor SurfExtractor = DescriptorExtractor
.create(DescriptorExtractor.SURF);
//extract keypoints
MatOfKeyPoint keypoints, logoKeypoints;
long time= System.currentTimeMillis();
detector.detect(img1, keypoints);
Log.d("LOG!", "number of query Keypoints= " + keypoints.size());
detector.detect(img2, logoKeypoints);
Log.d("LOG!", "number of logo Keypoints= " + logoKeypoints.size());
Log.d("LOG!", "keypoint calculation time elapsed" + (System.currentTimeMillis() -time));
//Descript keypoints
long time2 = System.currentTimeMillis();
Mat descriptors = new Mat();
Mat logoDescriptors = new Mat();
Log.d("LOG!", "logo type" + img2.type() + " intype" + img1.type());
SurfExtractor.compute(img1, keypoints, descriptors);
SurfExtractor.compute(img2, logoKeypoints, logoDescriptors);
Log.d("LOG!", "Description time elapsed" + (System.currentTimeMillis()- time2));
我显然无法将变量 keypoints
和 logoKeypoints
初始化为空,因为那时我会收到空指针异常。如何初始化它们?
最佳答案
您应该明白,这不是一个简单的问题,您可以遵循不同的概念。我只会指出两个没有源代码的解决方案。
- 直方图比较:您可以将两个图像都转换为灰度,在 [0,...,255] 范围内制作直方图。每个像素值都将被计算在内。然后使用两个直方图进行比较。如果像素强度的分布等于或高于某个阈值(可能是所有像素的 90%),您可以将此图像视为重复图像。但是:这是最简单的解决方案之一,如果任何图片的分布均等,则它是不稳定的。
- Interest-Point-Detectors/-Descriptors:了解 SIFT/SURF 图像检测器和描述符。检测器将尝试确定图像中强度的唯一关键点。将在此位置 I(x,y) 处计算描述符。具有蛮力方法和欧几里德距离的普通匹配器可以使用它们的描述符匹配这些图像。如果图像是重复的,则给定匹配的比率应该非常高。这个解决方案很好实现,并且可能有足够的关于这个主题的教程。
我希望这会有所帮助。如果您有任何问题,请询问。
[UPDATE-1] C++ 教程:http://morf.lv/modules.php?name=tutorials&lasit=2#.UR-ewKU3vCk
一些 JavaCV 教程:http://code.google.com/p/javacv/w/list
[UPDATE-2] 这是使用默认参数的 SIFT-Detector 和 SIFT-Descriptor 的示例。 RANSAC 单应性阈值为 65,重投影误差(epsilon)为 10,启用交叉验证。您可以尝试计算匹配的。如果 Inliner-Outlier-Ratio 太高,您可能会将此对视为重复项。 例如:这些图像在 IMG1 中产生 180 个关键点,在 IMG2 中产生 198 个关键点。匹配的描述符有 163 个,其中只有 3 个是异常值。所以这给出了一个非常好的比率,这仅意味着这些图像可能是重复的。
[UPDATE-3] 我不明白你为什么可以初始化 MatOfKeypoints。 I've read the API并且有一个公共(public)构造函数。并且:您可以使用要分析的图像的垫子。这是非常好的。 =)
MatOfKeyPoint reference = new MatOfKeyPoint(matOfReferenceImage);
对于匹配,请使用 BRUTEFORCE_SL2 Descriptor-Matcher因为你需要 SURF 或 SIFT 的欧几里得距离。
关于android - Android中的OpenCV图像比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14853989/