• 图像对比方法介绍及实现


    图像对比方法介绍及实现

    1.引言

    图像对比是在计算机视觉和图像处理中常见的任务之一。它可以用于识别重复图片、图像搜索、图像相似性比较等应用场景。实现图片对比方法的方法有多种,根据不同的需求和图片类型,可以选择适合的实现方案。如果对于简单的图片对比需求,可以选择基于像素比较或直方图比较的方法;如果对于复杂的图片对比需求,可以选择基于特征提取和匹配或深度学习模型的方法。

    2.图像对比方法介绍及优缺点

    图片相似度对比的需求,可以考虑以下几种实现方案:

    2.1基于像素比较:

    • 实现方式:基于像素比较的方法是最简单直接的图像对比方法之一。它通过逐像素比较两张图片的RGB值或灰度值来计算相似度。常用的像素比较方法包括均方差(MSE)和结构相似性指数(SSIM)等。
    • 优点:简单易实现,适用于任何类型的图片。
    • 缺点:对于颜色、亮度、尺寸等变化较大的图片,可能无法准确判断相似度。

    2.2基于直方图比较:

    • 实现方式:计算两张图片的直方图,并比较直方图的相似度(如卡方距离、余弦相似度等)。直方图对比是一种基于图像颜色分布的对比方法。它通过计算两张图片的直方图,并比较直方图之间的差异来评估图像的相似性。直方图对比方法适用于图像颜色分布较为重要的场景,如图像分类、图像搜索等。
      在直方图对比方法中,通常使用颜色直方图来表示图像的颜色分布。颜色直方图将图像中每个像素的颜色值统计为不同颜色区间的频次,从而得到一个描述图像颜色分布的直方图。常用的颜色空间包括RGB、HSV和Lab等。

    • 优点:对于颜色分布相似但像素值不同的图片具有较好的效果,适用于某些类型的图片(如艺术作品)。

    • 缺点:对于颜色分布差异较大的图片,可能无法准确判断相似度。
      直方图对比方法的步骤如下:

    1. 对两张图片分别计算颜色直方图。可以使用OpenCV等库提供的函数来计算直方图。
    2. 比较两个直方图之间的差异,可以使用直方图距离度量方法,如巴氏距离(Bhattacharyya distance)、3. 卡方距离(Chi-square distance)等。
    3. 根据直方图距离计算出两张图片的相似度评分。

    2.3基于特征提取和匹配:

    • 实现方式:使用图像处理库(如OpenCV)提取图片的特征(如SIFT、SURF、ORB等),并进行特征匹配。基于特征提取的方法通过使用预训练的深度学习模型来提取图像的特征表示,并计算特征之间的相似度。常用的特征提取模型包括VGG16、ResNet、Inception等。这些模型可以提取出图像的高级语义信息,从而更准确地衡量图像之间的相似性。
    • 优点:对于物体形状、纹理等特征较为重要的图片,具有较好的效果。
    • 缺点:对于颜色分布相似但形状、纹理不同的图片,可能无法准确判断相似度。

    2.4基于深度学习模型:

    • 实现方式:使用深度学习模型(如卷积神经网络 CNN)对图片进行特征提取,并计算特征的相似度。
    • 优点:对于各种类型的图片,具有较好的效果,可以学习到更高级的特征表示。
    • 缺点:需要大量的训练数据和计算资源,模型训练和部署相对复杂。

    3.图像对比方法实现

    3.1基于像素比较:

    3.1.1基于像素比较的图像相似度对比可以通过计算两张图片的像素级差异来实现。下面是一个简单的示例代码:
    import cv2
    import numpy as np
    
    def compare_images_pixel(img1_path, img2_path):
        # 读取两张图片
        img1 = cv2.imread(img1_path)
        img2 = cv2.imread(img2_path)
    
        # 确保两张图片具有相同的尺寸
        img1 = cv2.resize(img1, (img2.shape[1], img2.shape[0]))
    
        # 计算两张图片的差异
        diff = cv2.absdiff(img1, img2)
        diff_gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
    
        # 将差异图像转换为二值图像
        _, threshold = cv2.threshold(diff_gray, 30, 255, cv2.THRESH_BINARY)
    
        # 计算相似度
        similarity = np.mean(threshold)
    
        return similarity
    
    # 示例用法
    
    img1_path = 'image1.jpg'
    img2_path = 'image2.jpg'
    similarity = compare_images_pixel(img1_path, img2_path)
    print('相似度:', similarity)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    上述代码中,使用OpenCV库读取两张图片,并确保它们具有相同的尺寸。然后,计算两张图片的差异,并将差异图像转换为二值图像。最后,通过计算二值图像的平均值作为相似度指标。较小的平均值表示两张图片的像素差异较小,相似度较高。

    3.1.2优化基于像素比较方法对于颜色、亮度、尺寸等变化较大的图片的相似度判断,可以结合结构相似性(Structural Similarity, SSIM)指标和方差参数进行优化。下面是一个可行的方法:
    1. 计算结构相似性(SSIM)指标:

      • 使用OpenCV的cv2.cvtColor函数将两张图片转换为灰度图像。
      • 使用skimage.measure.compare_ssim函数计算两张灰度图像的SSIM指标。
    2. 计算方差参数:

      • 使用OpenCV的cv2.cvtColor函数将两张图片转换为灰度图像。
      • 计算两张灰度图像的像素值方差,可以使用numpy.var函数。
    3. 综合考虑SSIM指标和方差参数:

      • 对于SSIM指标,值越接近1表示两张图片的结构相似性越高,相似度越高。
      • 对于方差参数,较小的方差表示两张图片的像素值差异较小,相似度越高。
      • 可以通过加权综合考虑SSIM指标和方差参数,得到最终的相似度评分。

    下面是一个示例代码,演示如何使用SSIM指标和方差参数优化基于像素比较的相似度判断:

    import cv2
    import numpy as np
    #from skimage.measure import compare_ssim 原因:因为在skimage高版本中原来的compare_psnr和compare_ssim已经被移除
    from skimage.metrics import structural_similarity as compare_ssim
    from skimage.metrics import peak_signal_noise_ratio as compare_psnr
    
    def compare_images_pixel(img1_path, img2_path):
        # 读取两张图片
        img1 = cv2.imread(img1_path)
        img2 = cv2.imread(img2_path)
    
        # 确保两张图片具有相同的尺寸
        img1 = cv2.resize(img1, (img2.shape[1], img2.shape[0]))
    
        # 计算结构相似性(SSIM)指标
        img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
        img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
        ssim_score = compare_ssim(img1_gray, img2_gray)
    
        # 计算方差参数
        img1_var = np.var(img1_gray)
        img2_var = np.var(img2_gray)
        var_diff = np.abs(img1_var - img2_var)
    
        # 综合考虑SSIM指标和方差参数,得到最终的相似度评分
        similarity = ssim_score * (1 - var_diff)
    
        return similarity
    
    # 示例用法
    img1_path = 'image1.jpg'
    img2_path = 'image2.jpg'
    similarity = compare_images_pixel(img1_path, img2_path)
    print('相似度:', similarity)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在上述示例代码中,首先使用OpenCV的cv2.cvtColor函数将两张图片转换为灰度图像。然后,使用skimage.measure.compare_ssim函数计算灰度图像的SSIM指标。接下来,计算灰度图像的方差参数,通过numpy.var函数计算。最后,通过加权综合考虑SSIM指标和方差参数,得到最终的相似度评分。这样可以更好地处理颜色、亮度、尺寸等变化较大的图片,提高相似度判断的准确性。

    加权的数值可以根据具体需求和实际情况进行调整和优化。在示例代码中,我使用了一个简单的加权方案,将SSIM指标和方差参数进行加权综合。具体来说,我将SSIM指标乘以(1 - var_diff)作为最终的相似度评分。

    这个加权方案的目的是在保持结构相似性的基础上,对方差参数进行一定程度的惩罚。当两张图片的方差差异较大时,相似度评分会相应降低。这样可以更好地处理颜色、亮度、尺寸等变化较大的图片,提高相似度判断的准性。

    然而,这个加权方案可能并不适用于所有情况。根据具体的应用场景和需求,你可能需要根据实际情况进行调整和优化加权的数值。可以尝试不同的加权方案,并通过测试和评估来确定最佳的加权参数。这样可以根据具体情况优化解决像素比较方法对于颜色、亮度、尺寸等变化较大的图片的相似度判断。

    3.2基于直方图比较

    基于直方图比较的图像相似度对比可以通过计算两张图片的颜色直方图差异来实现。下面是一个简单的示例代码:

    import cv2
    import numpy as np
    
    def compare_images_histogram(img1_path, img2_path):
        # 读取两张图片
        img1 = cv2.imread(img1_path)
        img2 = cv2.imread(img2_path)
    
        # 将图片转换为HSV颜色空间
        img1_hsv = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV)
        img2_hsv = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV)
    
        # 计算图片的直方图
        hist1 = cv2.calcHist([img1_hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
        hist2 = cv2.calcHist([img2_hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
    
        # 归一化直方图
        cv2.normalize(hist1, hist1, 0, 1, cv2.NORM_MINMAX, -1)
        cv2.normalize(hist2, hist2, 0, 1, cv2.NORM_MINMAX, -1)
    
        # 计算直方图的差异
        similarity = cv2.compareHist(hist1, hist2, cv2.HISTCMP_CORREL)
    
        return similarity
    
    # 示例用法
    img1_path = 'image1.jpg'
    img2_path = 'image2.jpg'
    similarity = compare_images_histogram(img1_path, img2_path)
    print('相似度:', similarity)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    上述代码中,使用OpenCV库读取两张图片,并将它们转换为HSV颜色空间。然后,计算图片的颜色直方图,并归一化直方图。最后,通过使用cv2.compareHist函数计算直方图的相关性作为相似度指标。相关性的范围是[-1, 1],值越接近1表示两张图片的颜色分布越相似,相似度越高。

    3.3 基于特征提取和匹配

    3.3.1在Python中,可以使用OpenCV库来实现基于特征提取和匹配的图片相似度对比。下面是一些简单的示例代码:

    使用SIFT算法的示例代码:

    import cv2
    
    def compare_images(img1_path, img2_path):
        # 读取两张图片
        img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
        img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)
    
        # 创建SIFT特征提取器
        sift = cv2.xfeatures2d.SIFT_create()
    
        # 在两张图片上检测关键点和计算特征描述子
        keypoints1, descriptors1 = sift.detectAndCompute(img1, None)
        keypoints2, descriptors2 = sift.detectAndCompute(img2, None)
    
        # 创建FLANN匹配器
        flann = cv2.FlannBasedMatcher()
    
        # 使用knnMatch进行特征匹配
        matches = flann.knnMatch(descriptors1, descriptors2, k=2)
    
        # 进行筛选,保留较好的匹配结果
        good_matches = []
        for m, n in matches:
            if m.distance < 0.7 * n.distance:
                good_matches.append(m)
    
        # 计算相似度
        similarity = len(good_matches) / max(len(descriptors1), len(descriptors2))
    
        return similarity
    
    # 示例用法
    img1_path = 'image1.jpg'
    img2_path = 'image2.jpg'
    similarity = compare_images(img1_path, img2_path)
    print('相似度:', similarity)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    上述代码中,使用SIFT算法提取图片的特征描述子,然后使用FLANN匹配器进行特征匹配。通过筛选出较好的匹配结果,计算匹配点数目与特征描述子数目的比值,作为相似度指标。

    使用SURF(加速稳健特征)算法的示例代码:

    import cv2
    
    def compare_images_surf(img1_path, img2_path):
        # 读取两张图片
        img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
        img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)
    
        # 创建SURF特征提取器
        surf = cv2.xfeatures2d.SURF_create()
    
        # 在两张图片上检测关键点和计算特征描述子
        keypoints1, descriptors1 = surf.detectAndCompute(img1, None)
        keypoints2, descriptors2 = surf.detectAndCompute(img2, None)
    
        # 创建FLANN匹配器
        flann = cv2.FlannBasedMatcher()
    
        # 使用knnMatch进行特征匹配
        matches = flann.knnMatch(descriptors1, descriptors2, k=2)
    
        # 进行筛选,保留较好的匹配结果
        good_matches = []
        for m, n in matches:
            if m.distance < 0.7 * n.distance:
                good_matches.append(m)
    
        # 计算相似度
        similarity = len(good_matches) / max(len(descriptors1), len(descriptors2))
    
        return similarity
    
    # 示例用法
    img1_path = 'image1.jpg'
    img2_path = 'image2.jpg'
    similarity = compare_images_surf(img1_path, img2_path)
    print('相似度:', similarity)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    使用ORB算法的示例代码:

    import cv2
    
    def compare_images_orb(img1_path, img2_path):
        # 读取两张图片
        img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
        img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)
    
        # 创建ORB特征提取器
        orb = cv2.ORB_create()
    
        # 在两张图片上检测关键点和计算特征描述子
        keypoints1, descriptors1 = orb.detectAndCompute(img1, None)
        keypoints2, descriptors2 = orb.detectAndCompute(img2, None)
    
        # 创建BFMatcher匹配器
        bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
    
        # 使用match进行特征匹配
        matches = bf.match(descriptors1, descriptors2)
    
        # 进行筛选,保留较好的匹配结果
        good_matches = sorted(matches, key=lambda x: x.distance)[:int(len(matches) * 0.15)]
    
        # 计算相似度
        similarity = len(good_matches) / max(len(descriptors1), len(descriptors2))
    
        return similarity
    
    # 示例用法
    img1_path = 'image1.jpg'
    img2_path = 'image2.jpg'
    similarity = compare_images_orb(img1_path, img2_path)
    print('相似度:', similarity)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在上述代码中,使用SURF算法或ORB算法提取图片的特征描述子,并使用FLANN匹配器或BFMatcher匹配器进行特征匹配。通过筛选出较好的匹配结果,计算匹配点数目与特征描述子数目的比值,作为相似度指标。

    3.3.2 这三种算法(SIFT、SURF和ORB)是用于图像特征提取和匹配的常见算法,它们有以下区别:
    1. SIFT(尺度不变特征变换)算法:

      • SIFT算法在尺度空间中检测关键点,并计算关键点的局部特征描述子。
      • SIFT算法具有较好的尺度不变性和旋转不变性,对于尺度和旋转变化较大的图片具有较好的效果。
      • SIFT算法相对复杂,计算量较大,但在特征提取方面具有很好的效果。
    2. SURF(加速稳健特征)算法:

      • SURF算法是对SIFT算法的改进,通过使用快速Hessian矩阵检测关键点,并使用积分图像计算特征描述子,提高了算法的速度。
      • SURF算法对于尺度和旋转变化较大的图片具有较好的效果,且速度比SIFT算法更快。
      • SURF算法相对于SIFT算法来说,对于一些尺寸较小的特征和一些噪声更加敏感。
    3. ORB(Oriented FAST and Rotated BRIEF)算法:

      • ORB算法是一种基于FAST特征检测器和BRIEF特征描述子的快速特征提取算法。
      • ORB算法结合了FAST特征检测器的速度和BRIEF特征描述子的简洁性,具有较快的速度和较小的内存占用。
      • ORB算法对于尺度和旋转变化较小的图片具有较好的效果,适用于实时应用和计算资源有限的场景。

    总体而言,SIFT算法在精度和鲁棒性方面表现良好,但计算量较大;SURF算法在速度上有所改进,对尺度和旋转变化较大的图片具有较好的效果;ORB算法在速度和内存占用方面具有优势,适用于实时应用和计算资源有限的场景。选择哪种算法取决于具体应用场景和对速度、精度、计算资源的要求。

    3.4 基于深度学习模型

    基于深度学习模型的图像相似度对比可以通过使用卷积神经网络(Convolutional Neural Network, CNN)来提取图像的特征表示,并计算特征之间的相似度来实现。下面是一个示例代码,演示如何使用预训练的CNN模型来计算图像相似度:

    import cv2
    import numpy as np
    from tensorflow.keras.applications import VGG16
    from tensorflow.keras.models import Model
    from tensorflow.keras.preprocessing import image
    from tensorflow.keras.applications.vgg16 import preprocess_input
    
    def extract_features(img_path, model):
        # 读取图像并预处理
        img = image.load_img(img_path, target_size=(224, 224))
        x = image.img_to_array(img)
        x = np.expand_dims(x, axis=0)
        x = preprocess_input(x)
    
        # 提取特征
        features = model.predict(x)
        return features.flatten()
    
    def compare_images_deep(img1_path, img2_path):
        # 加载预训练的VGG16模型(不包括顶层分类器)
        base_model = VGG16(weights='imagenet', include_top=False)
        model = Model(inputs=base_model.input, outputs=base_model.get_layer('block5_pool').output)
    
        # 提取图像特征
        img1_features = extract_features(img1_path, model)
        img2_features = extract_features(img2_path, model)
    
        # 计算特征之间的余弦相似度
        similarity = np.dot(img1_features, img2_features) / (np.linalg.norm(img1_features) * np.linalg.norm(img2_features))
    
        return similarity
    
    # 示例用法
    img1_path = 'image1.jpg'
    img2_path = 'image2.jpg'
    similarity = compare_images_deep(img1_path, img2_path)
    print('相似度:', similarity)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    在上述示例代码中,首先加载预训练的VGG16模型,并提取模型的某一层的输出作为图像的特征表示。然后,使用extract_features函数读取图片并预处理,然后通过模型提取特征。接下来,计算两张图片特征之间的余弦相似度,作为相似度评分。余弦相似度的范围是[-1, 1],值越接近1表示两张图片的特征表示越相似,相似度越高。

    需要注意的是,上述示例代码使用了预训练的VGG16模型作为示例,你也可以根据具体需求选择其他的预训练模型,或者自己训练一个适合特定任务的深度学习模型。同时,根据具体情况,你可能需要对模型进行微调或调整参数,以获得更好的相似度判断效果。

    运行上述代码需python版本小于3.7,opencv版本建议版本 3.4.2.17,否则由于版权问题SURF ORB SIFT算法无法使用,请不要使用最新版的opencv。

  • 相关阅读:
    vue - Vue脚手架(终结篇)/ vue动画
    解决“ImportError: DLL load failed while importing _rust: 找不到指定的程序的问题
    Android Activity跳转
    java设计模式(十七)状态模式(State Pattern)
    pytest文档82 - 用例收集钩子 pytest_collect_file 的使用
    1、5伪类选择器
    Transformer预测 | Pytorch实现基于Transformer的时间序列预测(含单步与多步实验)
    [附源码]计算机毕业设计JAVA校园一卡通管理信息系统台
    智慧水利数字孪生案例分享:数字孪生水利,助力三峡科学防洪防汛
    计算机网络期末复习题四
  • 原文地址:https://blog.csdn.net/qq_41290252/article/details/134290491