查找两个图像是否相似

时间:2017-02-28 09:48:34

标签: opencv image-processing

我试图找出两个图像与openCV使用图像匹配相似。我正在运行以下代码:

public static void match(String firstImage, String secondImage, String outputFile) {

    FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB);
    DescriptorExtractor descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
    DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);


    Mat firstImg = Imgcodecs.imread(firstImage, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
    MatOfKeyPoint firstKeypoints = new MatOfKeyPoint();
    Mat firstDescriptors = new Mat();
    detector.detect(firstImg, firstKeypoints);
    descriptor.compute(firstImg, firstKeypoints, firstDescriptors);

    Mat secondImg = Imgcodecs.imread(secondImage,      Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
    MatOfKeyPoint secondKeypoints = new MatOfKeyPoint();
    Mat secondDescriptors = new Mat();
    detector.detect(secondImg, secondKeypoints);
    descriptor.compute(secondImg, secondKeypoints, secondDescriptors);

    MatOfDMatch matches = new MatOfDMatch();
    matcher.match(firstDescriptors, secondDescriptors, matches);

    float minDis = Float.MAX_VALUE;
    for (int i = 0;i < matches.rows();i++) {
        if (matches.toArray()[i].distance < minDis)
            minDis = matches.toArray()[i].distance;
    }
    LinkedList<DMatch> goodMatches = new LinkedList<>();
    for (int i = 0;i < matches.rows();i++) {
        if (matches.toArray()[i].distance < minDis*3)
            goodMatches.add(matches.toArray()[i]);
    }


    List<Point> pts1 = new ArrayList<Point>();
    List<Point> pts2 = new ArrayList<Point>();
    for(int i = 0; i<goodMatches.size(); i++){
        pts1.add(firstKeypoints.toList().get(goodMatches.get(i).queryIdx).pt);
        pts2.add(secondKeypoints.toList().get(goodMatches.get(i).trainIdx).pt);
    }

    // convertion of data types - there is maybe a more beautiful way
    Mat outputMask = new Mat();
    MatOfPoint2f pts1Mat = new MatOfPoint2f();
    pts1Mat.fromList(pts1);
    MatOfPoint2f pts2Mat = new MatOfPoint2f();
    pts2Mat.fromList(pts2);

    Calib3d.findHomography(pts1Mat, pts2Mat, Calib3d.RANSAC, 15, outputMask, 2000, 0.995);

    // outputMask contains zeros and ones indicating which matches are filtered
    LinkedList<DMatch> betterMatches = new LinkedList<DMatch>();
    for (int i = 0; i < goodMatches.size(); i++) {
        if (outputMask.get(i, 0)[0] != 0.0) {
            betterMatches.add(goodMatches.get(i));
        }
    }

    Mat outputImg = new Mat();
    MatOfDMatch betterMatchesMat = new MatOfDMatch();
    betterMatchesMat.fromList(betterMatches);
    Features2d.drawMatches(firstImg, firstKeypoints, secondImg, secondKeypoints, betterMatchesMat, outputImg);
    Imgcodecs.imwrite(outputFile, outputImg);
}

当图像相似时,结果如下:

similar example

当图像不相似时,结果如下: non similar example

您可以看到,在第一种情况下,匹配线是平行的,因此两个图像相似是有意义的。在第二种情况下,匹配线不是平行的,因此图像不相似是有意义的。有没有一种标准的方法来分析这些匹配,并找出在哪种情况下图像最可能相似?

2 个答案:

答案 0 :(得分:3)

为了检查相似图像的两个视角之间的单应矩阵的适当性,我编写了这个函数。您可以根据自己的喜好选择自己喜欢的内容,具体取决于您认为哪个更合适:

 private static boolean check_homography(Mat homography_mat){
    /* Check 1. Compute the determinant of the homography, and see if it's too close 
     to zero for comfort*/
    if(!homography_mat.empty())
    {
        double Determinant = Core.determinant(homography_mat);
        if (Determinant > 0.1)
            return true;
        else 
            return false;
    }
    else 
        return false;

    /* Check 2. Compute its SVD, and verify that the ratio of the first-to-last 
     singular value is not too high (order of 1.0E7). */   
    Mat singularValues = new Mat();
    Core.SVDecomp(homography_mat, singularValues, new Mat(), new Mat(), Core.SVD_NO_UV);

    System.out.print("\n Printing the singular values of the homography");
    for (int i = 0; i < singularValues.rows(); i++){
        for ( int j = 0; j < singularValues.cols(); j++){
            System.out.print("\n Element at ( " + i + ", " + j + " ) is " + singularValues.get(i, j)[0]);
        }
    }
    double conditionNumber = singularValues.get(0, 0)[0] / singularValues.get(2, 0)[0];
    System.out.print("\n Condition number is : " + conditionNumber);

    if(conditionNumber < Math.pow(10, 7)){
        System.out.print("\n Homography matrix is non-singular");
        return true;
        }
    else{
        System.out.print("\n Homography matrix is singular (or very close)");
        return false;
        }
    /* Check 3. Check the compare absolute values at (0,0) and (0,1) with (1,1) and (1,0) 
     * respectively. If the two differences are close to 0, the homography matrix is 
     * good. (This just takes of rotation and not translation)
     * */
    if(Math.abs((Math.abs(homography_mat.get(0, 0)[0]) - Math.abs(homography_mat.get(1, 1)[0]))) <= 0.1){
        if(Math.abs((Math.abs(homography_mat.get(0, 1)[0]) - Math.abs(homography_mat.get(1, 0)[0]))) <= 0.1){
            System.out.print("\n The homography matrix is good");
            return true;
        }
    }
        else{
            System.out.print("\n The homography matrix is bad");
            return false;
        }
    return false;
    /*
     * Check 4: If the determinant of the top-left 2 by 2 matrix (rotation) > 0, transformation is orientation
     * preserving.
     * Else if the determinant is < 0, it is orientation reversing
     * 
     * */
     Determinant of the rotation mat
    double det = homography_mat.get(0, 0)[0] * homography_mat.get(1,1)[0] - homography_mat.get(0, 1)[0] * homography_mat.get(1, 0)[0];
    if (det < 0)
        return false;

    double N1 = Math.sqrt(homography_mat.get(0, 0)[0] * homography_mat.get(0, 0)[0] + homography_mat.get(1, 0)[0] * homography_mat.get(1, 0)[0]);
    if (N1 > 4 || N1 < 0.1)
        return false;

    double N2 = Math.sqrt(homography_mat.get(0, 1)[0] * homography_mat.get(0, 1)[0] + homography_mat.get(1, 1)[0] * homography_mat.get(1, 1)[0]);
    if (N2 > 4 || N2 < 0.1)
        return false;

    double N3 = Math.sqrt(homography_mat.get(2, 0)[0] * homography_mat.get(2, 0)[0] + homography_mat.get(2,1)[0] * homography_mat.get(2, 1)[0]);
    if (N3 < 0.002)
        return false;

    return true;

}

注意 - 我在使用ORB时为Java,OpenCV编写了这个代码。我个人(根据我的经验),可以看一下Homography矩阵,如果好或不好,或者说 Check 1 或多或少。希望它有所帮助!!

修改 另外,正如@Micka所提到的,这取决于您的偏好,您还可以逐个像素地迭代这两个图像以找到相似性。我在这里发布的方法用于检查单应性是否良好,但应注意这一点 根据图像和方法(前/后处理,描述符,检测器等),即使两个图像相似,也会出现错误的单应性

答案 1 :(得分:0)

用外行术语来说,相关确定两个变量/数据集/等之间的线性关系。这种关系可能是正线性的,也可能是负线性的。 Pearson的R 是查找两个变量之间相关系数的常用方法。

Pearson's R的结果位于-1+1之间。

  • -1 - &gt; 彼此高度非线性
  • +1 - &gt; 彼此高度线性

这是一种表示两个变量有多相似或不相似的数字方式。

在这种情况下,我假设灰度图像是两个变量。在计算它之前,我将图像展平为1D阵列。

Pearson的R可以通过使用 scipy 库(在Python中)来确定。

from scipy.stats.stats import pearsonr

要获取有关pearsonr及其返回类型的详细信息,请查看THIS LINK

因此,使用python我为所有三个图像计算了Pearson的R,相互之间。

这就是我得到的:

  • 前两张图片:(0.62908215058685268, 0.0)
  • 对于第二张和第三张图片:(-0.34523397781005682, 0.0)
  • 第一张和第三张图片:(-0.36356339857880066, 0.0)

因此,我们可以说(在数字/统计术语中)前两个图像有些相似(假设有一个手提包,另一个没有手提包)。

如果您为两张相同的图像执行Pearson的R,您将获得1

的结果