检查图像与OpenCV的相似性

时间:2012-07-18 12:15:50

标签: image opencv comparison similarity

OpenCV是否支持两个图像的比较,返回一些值(可能是一个百分比)来表示这些图像有多相似?例如。如果相同的图像被传递两次将返回100%,如果图像完全不同,将返回0%。

我已经在StackOverflow上阅读了很多类似的主题。我也做了一些谷歌搜索。可悲的是,我无法得出令人满意的答案。

4 个答案:

答案 0 :(得分:183)

这是一个很大的话题,从3行代码到整个研究杂志的答案。

我将概述最常见的此类技术及其结果。

比较直方图

最简单的一个最快的方法。建议几十年前作为寻找图像相似性的手段。这个想法是,森林将拥有大量的绿色,人脸会有很多粉红色,或者其他什么。因此,如果你将两张图片与森林进行比较,你会在直方图之间得到一些相似之处,因为两者都有很多绿色。

  

缺点:太简单了。香蕉和海滩看起来都一样,都是黄色的。

     

OpenCV方法:compareHist()

模板匹配

这里有一个很好的例子matchTemplate finding good match。它将搜索图像与正在搜索的图像进行卷积。它通常用于在较大的图像中找到较小的图像部分。

  

缺点:只有相同的图像,相同的尺寸和相同的图像才会返回良好的效果。取向。

     

OpenCV方法:matchTemplate()

功能匹配

被认为是进行图像搜索的最有效方法之一。从图像中提取许多特征,以确保即使在旋转,缩放或倾斜时也能再次识别相同的特征。以这种方式提取的特征可以与其他图像特征集匹配。具有与第一个匹配的高比例特征的另一个图像被认为描绘了相同的场景。

找到两组点之间的单应性,您还可以找到原始图片之间的拍摄角度或重叠量的相对差异。

  

有很多OpenCV教程/示例,以及一个不错的视频here。整个OpenCV模块(features2d)专门用于它。

     

缺点:可能很慢。它并不完美。


OpenCV Q&A网站上,我在讨论特征描述符之间的区别,这些特征描述符在比较整个图像和纹理描述符时非常有用,这些描述符用于识别图像中的人脸或汽车等对象。

答案 1 :(得分:30)

如果要匹配相同的图像(相同的尺寸/方向)

// Compare two images by getting the L2 error (square-root of sum of squared error).
double getSimilarity( const Mat A, const Mat B ) {
if ( A.rows > 0 && A.rows == B.rows && A.cols > 0 && A.cols == B.cols ) {
    // Calculate the L2 relative error between images.
    double errorL2 = norm( A, B, CV_L2 );
    // Convert to a reasonable scale, since L2 error is summed across all pixels of the image.
    double similarity = errorL2 / (double)( A.rows * A.cols );
    return similarity;
}
else {
    //Images have a different size
    return 100000000.0;  // Return a bad value
}

Source

答案 2 :(得分:4)

Sam的解决方案应该足够了。我已经使用直方图差异和模板匹配的组合,因为没有一种方法在100%的时间对我有效。我对直方图方法的重视程度较低。这是我在简单的python脚本中实现的方式。

import cv2

class CompareImage(object):

    def __init__(self, image_1_path, image_2_path):
        self.minimum_commutative_image_diff = 1
        self.image_1_path = image_1_path
        self.image_2_path = image_2_path

    def compare_image(self):
        image_1 = cv2.imread(self.image_1_path, 0)
        image_2 = cv2.imread(self.image_2_path, 0)
        commutative_image_diff = self.get_image_difference(image_1, image_2)

        if commutative_image_diff < self.minimum_commutative_image_diff:
            print "Matched"
            return commutative_image_diff
        return 10000 //random failure value

    @staticmethod
    def get_image_difference(image_1, image_2):
        first_image_hist = cv2.calcHist([image_1], [0], None, [256], [0, 256])
        second_image_hist = cv2.calcHist([image_2], [0], None, [256], [0, 256])

        img_hist_diff = cv2.compareHist(first_image_hist, second_image_hist, cv2.HISTCMP_BHATTACHARYYA)
        img_template_probability_match = cv2.matchTemplate(first_image_hist, second_image_hist, cv2.TM_CCOEFF_NORMED)[0][0]
        img_template_diff = 1 - img_template_probability_match

        # taking only 10% of histogram diff, since it's less accurate than template method
        commutative_image_diff = (img_hist_diff / 10) + img_template_diff
        return commutative_image_diff


    if __name__ == '__main__':
        compare_image = CompareImage('image1/path', 'image2/path')
        image_difference = compare_image.compare_image()
        print image_difference

答案 3 :(得分:-2)

有点偏离主题,但有用的是pythonic numpy方法。它强大而快速但只是比较像素而不是图片所包含的对象或数据(它需要相同大小和形状的图像):

在没有openCV和任何计算机视觉库的情况下,一个非常简单快速的方法是通过

来规范图像数组
import numpy as np
picture1 = np.random.rand(100,100)
picture2 = np.random.rand(100,100)
picture1_norm = picture1/np.sqrt(np.sum(picture1**2))
picture2_norm = picture2/np.sqrt(np.sum(picture2**2))

在定义两个标准图片(或矩阵)后,您可以将您想要比较的图片的乘法加以总结:

1)如果你比较相似的图片,总和将返回1:

In[1]: np.sum(picture1_norm**2)
Out[1]: 1.0

2)如果它们不相似,你会得到一个介于0和1之间的值(如果乘以100则为百分比):

In[2]: np.sum(picture2_norm*picture1_norm)
Out[2]: 0.75389941124629822

请注意,如果您有彩色图片,则必须在所有3个维度中执行此操作,或者只是比较灰度版本。我经常需要将大量图片与任意内容进行比较,这是一种非常快速的方式。

相关问题