Android中的OpenCV图像比较

Kar*_*nan 19 android opencv image-comparison surf feature-detection

[编辑] 我设计了一些图像比较代码.匹配的部分仍然有点缺陷,我希望得到一些帮助.该项目可在 - GitHub找到.

我有这两个图像Img1Img2:

在此输入图像描述 在此输入图像描述

当我在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
}
Run Code Online (Sandbox Code Playgroud)

我得到了l2_norm的double值.对于重复的图像对,此双值会有所不同.但是如果图像不同,则抛出异常.这是我识别重复图像的方式吗?还是有更好的方法?我用Google搜索广泛,无法找到真正有说服力的答案.我希望代码和解释如何比较两个图像并获得布尔值truefalse取决于图像.

编辑

Scalar blah= Core.sumElems(img2);
    Scalar blah1=Core.sumElems(img1);

    if(blah.equals(blah1))
    {
        tv.setText("same image");
    }
    }
Run Code Online (Sandbox Code Playgroud)

我试过这个,但if条件永远不会满足.我假设有一些差异,但没有任何compare功能Scalar.我该怎么办?

编辑

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);
    }
Run Code Online (Sandbox Code Playgroud)

这种方法又有缺陷.虽然它可以用于比较具有相当精确度的图像,但是当图像具有不同的尺寸时它会失败.

当图像具有不同的大小并且我打印标量值时,我得到:

[9768383.0, 1.0052889E7, 1.0381814E7, 0.0] [1.5897384E7, 1.6322252E7, 1.690251E7, 0.0]

与比较相同尺寸的图像相比,第二和第三数字之间的变化虽然不是很大但是相当大.然而,第一个数字遭受的变化最大.

比较两个图像内容的最快方法是什么?

[编辑]

我正在使用我在这里找到的代码.

我无法弄清楚的是如何初始化MatOfKeyPoint变量keypointslogoKeypoints.这是我的代码片段:

           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));
Run Code Online (Sandbox Code Playgroud)

我显然无法初始化变量keypointslogoKeypointsnull cuz然后我会收到一个空指针异常.我该如何初始化它们?

Mr.*_*ain 26

您应该明白,这不是一个简单的问题,您可以遵循不同的概念.我只会指出两个没有源代码的解决方案.

  1. 直方图比较:您可以将两个图像转换为灰度,使直方图在[0,...,255]范围内.每个像素值都将被计算在内.然后使用两个直方图进行比较.如果像素强度的分布等于或高于某个阈值(可能是所有像素的90%),则可以将此图像视为重复.但是:这是最简单的解决方案之一,如果任何图片具有相同的分布,它就不稳定.
  2. 兴趣点检测器/描述符:看看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太高,您可能会看到这对重复. 使用SIFT检测器和SIFT描述符匹配img1和img2 例如:这些图像在IMG1中生成180个关键点,在IMG2中生成198个关键点.匹配的描述符是163,其中只有3个是异常值.所以这给出了一个非常好的比例,这可能意味着这些图像可能是重复的.

[UPDATE-3] 我不明白为什么你可以初始化MatOfKeypoints.我已经阅读了API,并且有一个公共构造函数.AND:您可以使用要分析的图像的Mat.这非常好.=)

MatOfKeyPoint reference = new MatOfKeyPoint(matOfReferenceImage);
Run Code Online (Sandbox Code Playgroud)

对于匹配使用BRUTEFORCE_SL2 Descriptor-Matcher,因为您需要SURF或SIFT的欧氏距离.