【问题标题】:Finding if two images are similar查找两个图像是否相似
【发布时间】:2017-07-19 05:17:13
【问题描述】:

我试图找出两个图像与使用图像匹配的 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);
}

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

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

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

【问题讨论】:

  • 执行互相关
  • ORB、SIFT、SURF等主要用于查找图像中的特定对象。您可以执行相关性以确定图像的相似性。您可以单独上传您正在使用的图像吗?
  • 平行度不足以判断匹配是否成功,如果您假设相机几乎是静止的,或者是一个几乎平面的场景/对象,您可以从匹配的点计算单应性。如果找到“良好”的单应性,则图像在这些点上是完全相等的。此外,在“应用”单应性(例如图像变形)之后,您可以使用比较像素等简单方法更好地比较两个图像。总而言之,这个主题非常难,但取决于您对“图像相似性”的定义/需求,它可能会或可能不会变得更容易。
  • @JeruLuke 你所说的相关性是什么意思?请注意,图像不相同但相似

标签: opencv image-processing


【解决方案1】:

通俗地说,相关性决定了两个变量/数据集/等之间的线性关系。这种关系可能是正线性或负线性。 Pearson's R是求两个变量之间相关系数的常用方法。

皮尔逊 R 的结果介于 -1+1 之间。

  • -1 -> 彼此高度非线性
  • +1 ->彼此高度线性

这是一种说明两个变量相似或不同程度的数值方式。

在这种情况下,我假设灰度图像是两个变量。在计算之前,我将图像展平为一维数组。

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

from scipy.stats.stats import pearsonr

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

因此,我使用 python 计算了所有三个图像的 Pearson's R。

这是我得到的:

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

因此我们可以说(在数字/统计方面)前两张图片有些相似(考虑到一张有手提包而另一张没有)。

如果您对两个相同图像执行 Pearson's R,您将获得 1 的结果

【讨论】:

  • 我觉得这里不适合
  • @RickM. 你为什么这么说?
  • 首先,皮尔逊相关适用​​于标准化数据集。其次,从结果中可以看出,对于后两种情况,相关性具有误导性
  • 干杯伙伴!相关性对我来说确实有意义,但统计数据有几个相关性,它们都受条件限制,何时使用是诀窍;)
  • 更合适的是here
【解决方案2】:

为了检查相似图像的两个视角之间单应矩阵的适当性,我编写了这个函数。您可以从各种可能性中选择您喜欢的,具体取决于您认为哪个更合适:

 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 所提到的,这取决于您的偏好,您还可以逐个像素地遍历两个图像以查找相似性。我这里贴的方法是用来检查单应性好不好的,但是需要注意的是 根据图像和方法(前/后处理、描述符、检测器等),即使两幅图像相似,您也可能会得到糟糕的单应性

【讨论】:

  • 伟大的洞察力:D。我会试试这个
  • 希望它对 OP 也有帮助,或者至少适合这个问题!
  • @RickM。这正是我想要的。谢谢!
  • @DanielB 很高兴它帮助了你!
猜你喜欢
  • 1970-01-01
  • 2018-09-25
  • 2015-10-17
  • 1970-01-01
  • 2011-09-18
  • 1970-01-01
  • 1970-01-01
  • 2012-08-25
  • 1970-01-01
相关资源
最近更新 更多