OpenCV书签 #互信息的原理与相似图片搜索实验

1. 介绍

互信息(Mutual Information) 是信息论中的一个概念,用于衡量两个随机变量之间的关联程度。在图像处理和计算机视觉中,互信息常被用来度量两幅图像之间的相似性。

互信息可以看成是一个随机变量中包含的关于另一个随机变量的信息量,或者说是一个随机变量由于已知另一个随机变量而减少的不肯定性对任意随机变量。比如,不会由于你知道了一个事件,反而使另一个事件的不确定度增加。

1.1 助记

这里引用知乎神贴 - 什么是互信息 中的比喻:

比如说有一天你的女神突然问你:"你猜猜我的爱豆是TFboys里的谁?"

唉,这要是猜不到,女神的心岂不是很完蛋,追求女神的路从此就凉了。

正当你非常不确定的时候,女神又说:"给你个提示吧,名字是四个字。"

此时你特别开心,因为对于答案的不确定性一下子就减少了(当然这个例子比较极端,不确定性直接降为0)

所以,互信息的意思就是,通过了知道一个变量减少了对另一个变量的不确定性。

这个不确定性减少的量也就是互信息的大小。

2. 魔法

使用互信息来度量两幅图像之间的相似性,只需要三步核心操作:

  1. 图像配准: Image Registration,在使用互信息进行相似性度量之前,通常需要对图像进行配准,确保它们对齐。这可以通过一些配准算法来实现,确保图像的空间位置相匹配。
  2. 计算互信息: 使用配准后的图像,计算它们之间的互信息。可以使用一些图像处理库,如 Scikit-ImageOpenCV,来实现互信息的计算。
  3. 相似性度量: 可以根据具体的需求和任务,设定一个阈值,选择互信息值高于该阈值的图像作为相似图像。

3. 实验

3.1 魔法拆解

第一步:图像配准

图像配准(Image Registration),在使用互信息进行相似性度量之前,通常需要对图像进行配准,确保它们对齐。这可以通过一些配准算法来实现,确保图像的空间位置相匹配。

python 复制代码
# 读取图像
img1 = cv2.imread(img1_path)
img2 = cv2.imread(img2_path)

# 检查图像形状,保证两个图像必须具有相同的尺寸,即相同的高度和宽度
if img1.shape != img2.shape:
    # 调整图像大小,使它们具有相同的形状
    img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

第二步:计算互信息

使用配准后的图像,计算它们之间的互信息。可以使用一些图像处理库,如 Scikit-ImageOpenCV,来实现互信息的计算。

这里我们先使用灰度直方图来计算互信息:

python 复制代码
# 将直方图归一化
# 即将直方图中的每个元素除以直方图的总和,以确保它们的和为1
# 这样做的目的是为了消除不同图像的像素数量差异,使得直方图的形状更具可比性
hist1 /= hist1.sum()
hist2 /= hist2.sum()

# 计算两个归一化直方图的互信息
mutual_score = np.sum(np.minimum(hist1, hist2))
print(f"图像2:{os.path.basename(img2_path)} 与 图像1:{img1_path} 的相似性指数:{mutual_score}")

这里首先使用 np.minimum 函数计算 hist1 和 hist2 中每个对应位置的元素的较小值,然后使用 np.sum 计算这些较小值的总和。这个总和即为互信息的计算结果,即互信息的大小。

第三步:相似性度量

根据具体的需求和任务,设定一个阈值,选择互信息值高于该阈值的图像作为相似图像。

python 复制代码
# 在实际应用中,可以根据互信息的阈值来判断两幅图像是否相似
if mutual_score > 0.7:
    print("两图相似")
else:
    print("两图不相似")

3.2 小实验

实验场景

计算两幅灰度图像的直方图,然后通过归一化的直方图计算它们的互信息。最后,根据设定的阈值判断两幅图像是否相似。

实验代码

python 复制代码
"""
以图搜图:互信息(Mutual Information)查找相似图像的原理与实现
实验环境:Win10 | python 3.12.1 | OpenCV 4.9.0 | numpy 1.26.3 | Matplotlib 3.8.2
实验时间:2024-01-24
实验目的:计算两幅灰度图像的直方图,然后通过归一化的直方图计算它们的互信息。最后,根据设定的阈值判断两幅图像是否相似
实例名称:mutualInformation_v1.0.py
"""

import os
import cv2
import time
import numpy as np

time_start = time.time()

# 目标图像素材库文件夹路径
database_dir = '../../P0_Doc/img_data/'

# 读取查询图像和数据库中的图像
img1_path = database_dir + 'car-101.jpg'
img2_path = database_dir + 'car-102.jpg'
img2_path = database_dir + 'car-103.jpg'

# 读取两幅图像
img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)

# 检查图像形状,保证两个图像必须具有相同的尺寸,即相同的高度和宽度
if img1.shape != img2.shape:
    # 调整图像大小,使它们具有相同的形状
    img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

# 使用 OpenCV 中的 calcHist 函数计算直方图
hist1 = cv2.calcHist([img1], [0], None, [256], [0, 256])
hist2 = cv2.calcHist([img2], [0], None, [256], [0, 256])

# 将直方图归一化
# 即将直方图中的每个元素除以直方图的总和,以确保它们的和为1
# 这样做的目的是为了消除不同图像的像素数量差异,使得直方图的形状更具可比性
hist1 /= hist1.sum()
hist2 /= hist2.sum()

# 计算两个归一化直方图的互信息
# 首先,使用 np.minimum 函数计算了 hist1 和 hist2 中每个对应位置的元素的较小值,然后使用 np.sum 计算了这些较小值的总和。这个总和即为互信息的计算结果
mutual_score = np.sum(np.minimum(hist1, hist2))
print(f"图像2:{os.path.basename(img2_path)} 与 图像1:{img1_path} 的相似性指数:{mutual_score}")

# 在实际应用中,可以根据互信息的阈值来判断两幅图像是否相似
if mutual_score > 0.7:
    print("两图相似")
else:
    print("两图不相似")

time_end = time.time()
print(f"耗时:{time_end - time_start}")

输出打印:

python 复制代码
图像2:car-103.jpg 与 图像1:../../P0_Doc/img_data/car-101.jpg 的相似性指数:0.6439836025238037
两图不相似
耗时:0.0687875747680664

示例中的互信息计算,利用了灰度直方图比较方法,通过比较两幅图像的灰度直方图,评估它们的相似性。
注意: 如果这里不进行图像配准,不保证等高等宽,互信息的相似度也会产生差异。

插播: 直方图是一种统计图像中像素值分布的方法,它可以描述图像中不同灰度级别的像素数量。关于直方图的原理与实验,可详见:OpenCV书签 #直方图算法的原理与相似图片搜索实验

为什么要用灰度直方图呢?有什么关联和区别?

互信息和灰度直方图算法是两个不同的概念,虽然在图像处理中它们有时候会交叉使用,但是还是需要注意:

互信息(Mutual Information):

  • 互信息是一种信息论中的概念,用于衡量两个随机变量之间的关联程度。
  • 在图像处理中,互信息通常用于度量两幅图像之间的相似性。它考虑的是两个变量的联合概率分布与各自边缘概率分布之间的关系。
  • 互信息越高,表示两个随机变量之间的关联越强。

灰度直方图算法(Image Histogram):

  • 灰度直方图是一种统计图像中像素值分布的方法,它描述了图像中不同灰度级别的像素数量。
  • 在灰度直方图算法中,图像的直方图表示了图像中每个灰度级别的像素数量。
  • 直方图比较是通过比较两幅图像的灰度直方图来评估它们的相似性。常见的比较方法包括交叉相关性、巴氏距离等。

虽然互信息的计算可以涉及到灰度直方图,但两者并不等同。互信息是一种更广泛的概念,而灰度直方图算法是一种具体的图像表示和相似性度量方法。

4. 测试

4.1 实验素材

4.2 实验过程

纵向比较

通过 sklearn.metrics 提供的各类互信息比较算法,纵向比较两图的相似性。

实验代码
python 复制代码
"""
以图搜图:互信息(Mutual Information)查找相似图像的原理与实现
实验环境:Win10 | python 3.12.1 | OpenCV 4.9.0 | numpy 1.26.3 | Matplotlib 3.8.2
实验时间:2024-01-24
实验目的:通过 sklearn.metrics 提供的各类互信息比较算法,纵向比较两图的相似性
实例名称:mutualInformation_v2.1.py
"""

import time
import cv2
from sklearn import metrics as mr
# from sklearn.metrics.cluster import normalized_mutual_info_score
# from sklearn.metrics.cluster import adjusted_mutual_info_score

def mutual_information_score(img1_reshape, img2_reshape):
    # mutual_info_score:标准互信息分数。度量两个随机变量之间的互信息,可用于衡量它们之间的关联性
    m_time_start = time.time()
    score_info = mr.mutual_info_score(img1_reshape, img2_reshape)
    m_time_end = time.time()
    print(f"互信息 mutual_info_score:标准互信息分数:{score_info},耗时:{m_time_end - m_time_start}")

    # normalized_mutual_info_score:归一化互信息分数。用于衡量两个聚类结果之间的相似性,考虑到了数据集的随机性。通常被用作聚类性能的评估指标
    m_time_start = time.time()
    score_normal = mr.normalized_mutual_info_score(img1_reshape, img2_reshape)
    m_time_end = time.time()
    print(f"互信息 normalized_mutual_info_score:归一化互信息分数:{score_normal},耗时:{m_time_end - m_time_start}")

    # adjusted_mutual_info_score:调整的归一化互信息分数。该分数考虑到了数据集的随机性,对标准互信息进行了调整,以提供更准确的聚类性能度量
    m_time_start = time.time()
    score_adjusted = mr.adjusted_mutual_info_score(img1_reshape, img2_reshape)
    m_time_end = time.time()
    print(f"互信息 adjusted_mutual_info_score:调整的归一化互信息分数:{score_adjusted},耗时:{m_time_end - m_time_start}")

    # v_measure_score: V-Measure(V值)分数。结合了聚类的均匀性和完整性,提供了一个综合的聚类性能度量
    m_time_start = time.time()
    score_measure = mr.v_measure_score(img1_reshape, img2_reshape)
    m_time_end = time.time()
    print(f"互信息 v_measure_score:V-Measure(V值)分数:{score_measure},耗时:{m_time_end - m_time_start}")

    # homogeneity_score: 均匀性分数。用于度量每个聚类的成员是否都属于同一类别,高均匀性表示每个聚类都很"纯净"
    m_time_start = time.time()
    score_homogeneity = mr.homogeneity_score(img1_reshape, img2_reshape)
    m_time_end = time.time()
    print(f"互信息 homogeneity_score:均匀性分数:{score_homogeneity},耗时:{m_time_end - m_time_start}")

    # completeness_score: 完整性分数。度量每个真实类别的成员是否都被分配到同一聚类中,高完整性表示每个类别都被很好地捕捉
    m_time_start = time.time()
    score_completeness = mr.completeness_score(img1_reshape, img2_reshape)
    m_time_end = time.time()
    print(f"互信息 completeness_score:完整性分数:{score_completeness},耗时:{m_time_end - m_time_start}")

    # adjusted_rand_score: 调整的兰德指数。度量两个聚类结果之间的相似性,考虑了数据集的随机性
    m_time_start = time.time()
    score_adjusted_rand = mr.adjusted_rand_score(img1_reshape, img2_reshape)
    m_time_end = time.time()
    print(f"互信息 adjusted_rand_score:调整的兰德指数:{score_adjusted_rand},耗时:{m_time_end - m_time_start}")

    # fowlkes_mallows: Fowlkes-Mallows指数。度量两个聚类结果之间的精度,考虑了聚类的精确度
    m_time_start = time.time()
    score_fowlkes_mallows = mr.fowlkes_mallows_score(img1_reshape, img2_reshape)
    m_time_end = time.time()
    print(f"互信息 fowlkes_mallows_score:Fowlkes-Mallows指数:{score_fowlkes_mallows},耗时:{m_time_end - m_time_start}")

    # silhouette_score: 轮廓系数。度量每个样本在其自己的聚类中的相似性与最近的相邻聚类之间的不相似性
    # 输入是两张图片,而不是聚类数据,计算轮廓系数就不太适用了,因为轮廓系数通常用于衡量聚类的质量
    # score_silhouette = mr.silhouette_score(img1.reshape(-1, 1), img2.reshape(-1, 1))

if __name__ == "__main__":

    time_start = time.time()

    # 目标图像素材库文件夹路径
    database_dir = '../../P0_Doc/img_data/'

    # 读取查询图像和数据库中的图像
    img1_path = database_dir + 'car-101.jpg'
    img2_path = database_dir + 'car-102.jpg'
    img1_path = database_dir + 'apple-101.jpg'
    img2_path = database_dir + 'apple-102.jpg'

    print(f"互信息相似度比较,图像1:{img1_path},图像2:{img2_path}")

    # 读取图像
    img1 = cv2.imread(img1_path)
    img2 = cv2.imread(img2_path)

    # 检查图像形状,保证两个图像必须具有相同的尺寸,即相同的高度和宽度
    if img1.shape != img2.shape:
        # 调整图像大小,使它们具有相同的形状
        img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))

    print("------------------------- 原图像 互信息相似度           -------------------------")

    # 原图应用于常见的互信息相关方法和算法及相似度
    mutual_information_score(img1.reshape(-1), img2.reshape(-1))

    # 将图像转换为灰度图像
    img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
    img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

    print("------------------------- 图像转换为灰度图像 互信息相似度 -------------------------")

    # 原图灰度图像应用于常见的互信息相关方法和算法及相似度
    mutual_information_score(img1_gray.reshape(-1), img2_gray.reshape(-1))

    time_end = time.time()
    print(f"耗时:{time_end - time_start}")

sklearn.metrics.cluster 提供了很多互信息相关的方法和算法,主要用于不同的评估场景,涉及到聚类的性能和相似性的测量:

互信息算法/方法 说明
adjusted_mutual_info_score 调整的归一化互信息分数。该分数考虑到了数据集的随机性,对标准互信息进行了调整,以提供更准确的聚类性能度量
normalized_mutual_info_score 归一化互信息分数。用于衡量两个聚类结果之间的相似性,考虑到了数据集的随机性。通常被用作聚类性能的评估指标
mutual_info_score 标准互信息分数。度量两个随机变量之间的互信息,可用于衡量它们之间的关联性
v_measure_score V-Measure(V值)分数。结合了聚类的均匀性和完整性,提供了一个综合的聚类性能度量
homogeneity_score 均匀性分数。用于度量每个聚类的成员是否都属于同一类别,高均匀性表示每个聚类都很"纯净"
completeness_score 完整性分数。度量每个真实类别的成员是否都被分配到同一聚类中,高完整性表示每个类别都被很好地捕捉
adjusted_rand_score 调整的兰德指数。度量两个聚类结果之间的相似性,考虑了数据集的随机性
fowlkes_mallows_score Fowlkes-Mallows指数。度量两个聚类结果之间的精度,考虑了聚类的精确度
silhouette_score 轮廓系数。度量每个样本在其自己的聚类中的相似性与最近的相邻聚类之间的不相似性

img1_reshape.reshape(-1)img1_reshape.reshape(-1, 1)NumPy 中用于改变数组形状的方法。
reshape(-1) 用于展平数组,而 reshape(-1, 1) 用于将数组转换为包含单个列的二维数组。区别在于得到的形状不同。

  • img1_reshape.reshape(-1): 这将多维数组 img1_reshape 转换为一个展平的一维数组。NumPy 会根据数组的大小自动计算另一维度的大小,以确保总的元素数量不变。这通常用于将多维数组展平为一维数组,方便某些操作。
  • img1_reshape.reshape(-1, 1): 这将多维数组 img1_reshape 转换为一个包含单个列的二维数组。其中,-1 表示自动计算行数,而 1 表示只有一列。这通常用于确保某些函数接受的输入是二维数组,并且每个样本在单独的列中。

关于这些算法/方法,源码提供了使用 Demo,可以通过源码了解更多,比如:

python 复制代码
    Examples
    --------

    Perfect labelings are both homogeneous and complete, hence have
    score 1.0::

      >>> from sklearn.metrics.cluster import normalized_mutual_info_score
      >>> normalized_mutual_info_score([0, 0, 1, 1], [0, 0, 1, 1])
      ... # doctest: +SKIP
      1.0
      >>> normalized_mutual_info_score([0, 0, 1, 1], [1, 1, 0, 0])
      ... # doctest: +SKIP
      1.0

    If classes members are completely split across different clusters,
    the assignment is totally in-complete, hence the NMI is null::

      >>> normalized_mutual_info_score([0, 0, 0, 0], [0, 1, 2, 3])
      ... # doctest: +SKIP
      0.0

实验代码输出打印:

python 复制代码
互信息相似度比较,图像1:../../P0_Doc/img_data/apple-101.jpg,图像2:../../P0_Doc/img_data/apple-102.jpg
------------------------- 原图像 互信息相似度           -------------------------
互信息 mutual_info_score:标准互信息分数:0.3334500090190323,耗时:0.4178807735443115
互信息 normalized_mutual_info_score:归一化互信息分数:0.1442800195961649,耗时:0.704125165939331
互信息 adjusted_mutual_info_score:调整的归一化互信息分数:0.13897879139743463,耗时:27.81876230239868
互信息 v_measure_score:V-Measure(V值)分数:0.14428001959616493,耗时:0.6462442874908447
互信息 homogeneity_score:均匀性分数:0.1393427892877539,耗时:0.6453077793121338
互信息 completeness_score:完整性分数:0.14957997661474184,耗时:0.6043868064880371
互信息 adjusted_rand_score:调整的兰德指数:0.5983897700024668,耗时:0.39893531799316406
互信息 fowlkes_mallows_score:Fowlkes-Mallows指数:0.7874850623258953,耗时:0.3939492702484131
------------------------- 图像转换为灰度图像 互信息相似度 -------------------------
互信息 mutual_info_score:标准互信息分数:0.3114601065499291,耗时:0.12766075134277344
互信息 normalized_mutual_info_score:归一化互信息分数:0.14164731215313434,耗时:0.2203817367553711
互信息 adjusted_mutual_info_score:调整的归一化互信息分数:0.13105360189408213,耗时:6.436821222305298
互信息 v_measure_score:V-Measure(V值)分数:0.14164731215313434,耗时:0.20248985290527344
互信息 homogeneity_score:均匀性分数:0.1361761519096563,耗时:0.25429248809814453
互信息 completeness_score:完整性分数:0.14757650531529792,耗时:0.19750332832336426
互信息 adjusted_rand_score:调整的兰德指数:0.6065766924224203,耗时:0.1396336555480957
互信息 fowlkes_mallows_score:Fowlkes-Mallows指数:0.7932503296629234,耗时:0.13862109184265137
耗时:39.388914585113525

通过简单的测试,从纵向比较两图的相似性结果来看:

原图像

  • 互信息使用 adjusted_mutual_info_score 算法,相似度得分最低,耗时最长。
  • 互信息使用 fowlkes_mallows_score 算法,相似度得分最高,耗时最短。

图像灰度之后,去除了彩色像素处理,速度明显变快很多:

  • 互信息使用 adjusted_mutual_info_score 算法,相似度得分最低,耗时最长。
  • 互信息使用 fowlkes_mallows_score 算法,相似度得分最高。
  • 互信息使用 mutual_info_score 算法,耗时最短。

横向比较

通过使用某一互信息计算方法,配合相似阈值,在测试图片素材库中搜索查找与目标图像相似的图片。

实验代码
python 复制代码
"""
以图搜图:互信息(Mutual Information)查找相似图像的原理与实现
实验环境:Win10 | python 3.12.1 | OpenCV 4.9.0 | numpy 1.26.3 | Matplotlib 3.8.2
实验时间:2024-01-24
实验目的:通过使用某一互信息计算方法,配合相似阈值,在测试图片素材库中搜索查找与目标图像相似的图片
实例名称:mutualInformation_v2.2.py
"""

import os
import time
import cv2
import matplotlib.pyplot as plt
from sklearn import metrics as mr

def search_mutual_info(img_org_path, database_paths):

    # 将原图像转换为灰度图像
    img_original_gray = cv2.cvtColor(cv2.imread(img_org_path), cv2.COLOR_BGR2GRAY)

    # 遍历数据库图像并比较相似度
    similaritys = []
    for img_path in database_paths:
        # 获取相似图像文件路径
        img_target_path = os.path.join(script_dir, database_dir_path, img_path)

        # 将图像转换为灰度图像
        img_target_gray = cv2.cvtColor(cv2.imread(img_target_path), cv2.COLOR_BGR2GRAY)

        # 检查图像形状,保证两个图像必须具有相同的尺寸,即相同的高度和宽度
        if img_original_gray.shape != img_target_gray.shape:
            # 调整图像大小,使它们具有相同的形状
            img_target_gray = cv2.resize(img_target_gray, (img_original_gray.shape[1], img_original_gray.shape[0]))

        # 灰度图像应用于常见的互信息相关方法和算法及相似度
        score = mr.fowlkes_mallows_score(img_original_gray.reshape(-1), img_target_gray.reshape(-1))
        # print(f"互信息 fowlkes_mallows_score:{score}")

        # 将结果保存到列表中(仅保留相似值大于等于 0.7 的图像)
        if (score >= 0.7):
            similaritys.append((os.path.relpath(img_target_path), score))
            # print(f"图像名称:{img_target_path},与目标图像 {os.path.basename(img_resouce)} 的近似值:{ssim[0]}")

    return similaritys


def show_similar_images(similar_images, images_per_column=4):
    # 计算总共的图片数量
    num_images = len(similar_images)
    # 计算所需的行数
    num_rows = (num_images + images_per_column - 1) // images_per_column

    # 创建一个子图,每行显示 images_per_column 张图片
    fig, axes = plt.subplots(num_rows, images_per_column, figsize=(12, 15), squeeze=False)

    # 遍历每一行
    for row in range(num_rows):
        # 遍历每一列
        for col in range(images_per_column):
            # 计算当前图片在列表中的索引
            index = row * images_per_column + col
            # 检查索引是否越界
            if index < num_images:
                # 获取当前相似图片的路径和相似度
                image_path = similar_images[index][0]
                similarity = similar_images[index][1]

                # 读取图片并转换颜色通道
                image = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)

                # 在子图中显示图片
                axes[row, col].imshow(image)
                # 设置子图标题,包括图片路径和相似度
                axes[row, col].set_title(f"Similar Image: {os.path.basename(image_path)} \n Similar Score: {similarity}")
                # 关闭坐标轴
                axes[row, col].axis('off')
    # 显示整个图
    plt.show()


if __name__ == "__main__":

    time_start = time.time()

    # 获取当前执行脚本所在目录
    script_dir = os.path.dirname(__file__)

    # 目标图像素材库文件夹路径
    database_dir_path = '../../P0_Doc/img_data/'
    # 指定测试图像文件扩展名
    img_suffix = ['.jpg', '.jpeg', '.png', '.bmp', '.gif']

    # 获取测试图像库中所有文件
    all_files = os.listdir(os.path.join(script_dir, database_dir_path))
    # 筛选测试图像库中指定后缀的图像文件
    img_files = [img_file for img_file in all_files if any(img_file.endswith(suffix) for suffix in img_suffix)]
    # 获取测试图像库中所有图像的路径
    img_files_path = [os.path.join(database_dir_path, filename) for filename in img_files]

    # 获取目标测试图像的全路径
    img_org_path = os.path.join(script_dir, database_dir_path, 'apple-101.jpg')
    img_org_path = os.path.join(script_dir, database_dir_path, 'iphone15-001.jpg')
    img_org_path = os.path.join(script_dir, database_dir_path, 'car-101.jpg')

    # 原图应用于常见的互信息相关方法和算法及相似度
    img_search_results = search_mutual_info(img_org_path, img_files_path)

    # 按相似度降序排序
    img_search_results.sort(key=lambda item: item[1], reverse=True)
    for similarity in img_search_results:
        print(f"图像:{similarity[0]},与目标图像 {os.path.basename(img_org_path)} 的相似值:{similarity[1]}")

    time_end = time.time()
    print(f"测试素材库图像数量:{len(img_files)},耗时:{time_end - time_start}")

    # 显示目标相似图像
    show_similar_images(img_search_results)
第一组测试

测试结果输出打印:

python 复制代码
图像:..\..\P0_Doc\img_data\apple-101.jpg,与目标图像 apple-101.jpg 的相似值:1.0
图像:..\..\P0_Doc\img_data\apple-103.jpg,与目标图像 apple-101.jpg 的相似值:0.8185132476782856
图像:..\..\P0_Doc\img_data\apple-105.jpg,与目标图像 apple-101.jpg 的相似值:0.8069378648696433
图像:..\..\P0_Doc\img_data\apple-102.jpg,与目标图像 apple-101.jpg 的相似值:0.7932928654393832
图像:..\..\P0_Doc\img_data\iphone15-001.jpg,与目标图像 apple-101.jpg 的相似值:0.771736183796336
图像:..\..\P0_Doc\img_data\iphone15-002.jpg,与目标图像 apple-101.jpg 的相似值:0.7715952189959523
图像:..\..\P0_Doc\img_data\iphone15-003.jpg,与目标图像 apple-101.jpg 的相似值:0.7707667748546456
图像:..\..\P0_Doc\img_data\apple-109.jpg,与目标图像 apple-101.jpg 的相似值:0.7528870440060801
图像:..\..\P0_Doc\img_data\pear-201.jpg,与目标图像 apple-101.jpg 的相似值:0.7208068021727383
图像:..\..\P0_Doc\img_data\apple-104.jpg,与目标图像 apple-101.jpg 的相似值:0.7066478416742119
测试素材库图像数量:48,耗时:7.807173013687134

互信息相似图片查找效果可视化:

第二组测试

测试结果输出打印:

python 复制代码
图像:..\..\P0_Doc\img_data\iphone15-001.jpg,与目标图像 iphone15-001.jpg 的相似值:1.0
图像:..\..\P0_Doc\img_data\iphone15-002.jpg,与目标图像 iphone15-001.jpg 的相似值:0.9985563921236876
图像:..\..\P0_Doc\img_data\iphone15-003.jpg,与目标图像 iphone15-001.jpg 的相似值:0.996718480433257
图像:..\..\P0_Doc\img_data\apple-102.jpg,与目标图像 iphone15-001.jpg 的相似值:0.8165921658980023
图像:..\..\P0_Doc\img_data\apple-104.jpg,与目标图像 iphone15-001.jpg 的相似值:0.7733543220682563
图像:..\..\P0_Doc\img_data\apple-101.jpg,与目标图像 iphone15-001.jpg 的相似值:0.7717483756822613
图像:..\..\P0_Doc\img_data\apple-103.jpg,与目标图像 iphone15-001.jpg 的相似值:0.7579136253684923
图像:..\..\P0_Doc\img_data\apple-105.jpg,与目标图像 iphone15-001.jpg 的相似值:0.7540519846067019
测试素材库图像数量:48,耗时:30.248269081115723

互信息相似图片查找效果可视化:

5. 总结

在图像处理中,互信息可以用来衡量两幅图像的相似性,尤其在配准(registration)和图像匹配(image matching)的任务中经常被使用。通过最大化互信息,可以找到两个图像之间的最佳匹配,以便更好地对齐它们。

优点

  1. 对比度不敏感: 互信息对比度不敏感,适用于对比度较大的图像。
  2. 非线性关系: 互信息适用于具有非线性关系的图像数据,因此对于复杂的图像相似性度量具有一定优势。
  3. 不依赖特定颜色空间: 互信息在计算过程中不依赖于特定的颜色空间,因此对于不同颜色表示的图像也能够有效计算相似性。

缺点

  1. 图像配准: 如果两张图片尺寸相同,还是能在一定程度上表征两张图片的相似性的。但是,大部分情况下图片的尺寸不相同,如果把两张图片尺寸调成相同的话,又会让原来很多的信息丢失,所以很难把握。
  2. 计算复杂度: 互信息的计算涉及到直方图的操作,因此在图像尺寸较大、直方图维度较高时计算复杂度较高。
  3. 对噪声敏感: 互信息对噪声敏感,噪声可能对互信息的计算产生一定影响。
  4. 不考虑空间结构: 互信息不考虑像素在图像中的空间结构,可能对图像中物体的空间排列不敏感。

6. 问题

异常现象1

python 复制代码
    from skimage.feature import mutual_info_score
ImportError: cannot import name 'mutual_info_score' from 'skimage.feature' (D:\Tp_Mylocal\20_Install\python-3.9.13\lib\site-packages\skimage\feature\__init__.py)

可以尝试安装或更新 scikit-image 依赖项:

python 复制代码
pip install --upgrade scikit-image
python 复制代码
Installing collected packages: pillow, packaging, numpy, networkx, lazy_loader, tifffile, scipy, imageio, scikit-image
  WARNING: Failed to write executable - trying to use .deleteme logic
ERROR: Could not install packages due to an OSError: [WinError 2] 系统找不到指定的文件。: 'C:\\Python312\\Scripts\\f2py.exe' -> 'C:\\Python312\\Scripts\\f2py.exe.deleteme'

f2py.exeFortran 到 Python 接口生成器的可执行文件。它用于将 Fortran 代码集成到 Python 中,使得可以在 Python 中调用 Fortran 编写的函数或子程序。

在正常情况下,f2py.exe 应该包含在 NumPy 库中。由于我本地环境没有,可能是之前安装出现的问题。这里重新安装 NumPy,以获取缺失的文件:

python 复制代码
pip install --upgrade --force-reinstall numpy

还是不行的话,尝试一下在应用程序中先卸载 Python,再重装最新版的 Python。

以我的案例看,我本地的 Python 版本是 python 3.9.13,卸载后重装了最新版的 Python 3.12.1。

如果重装 python 时,选择了新的路径,这里同样需要确认或调整一下系统环境变量中关于 python 的路径指向。

然后重新安装本地运行 python 脚本缺失的依赖项,包括 scikit-learn。

然后就可以了。也没有类似需要 f2py.exe 的错误提示。

需要注意的是,目前互信息提供的相似算法都在 from sklearn.metrics.cluster 下。

安装 scikit-learn 依赖项:

python 复制代码
pip install scikit-learn

异常现象2

python 复制代码
Traceback (most recent call last):
  File "D:\Ct_ iSpace\Wei\Python\iPython\T30_Algorithm\P2_Algo\03_MutualInformation\mutualInformation_v2.1.py", line 119, in <module>
    mutual_information_score(img1.reshape(-1), img2.reshape(-1))
  File "D:\Ct_ iSpace\Wei\Python\iPython\T30_Algorithm\P2_Algo\03_MutualInformation\mutualInformation_v2.1.py", line 89, in mutual_information_score
    score_silhouette = mr.silhouette_score(img1_reshape, img2_reshape)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Ct_ iSpace\Wei\Python\iPython\T00_Env\Lib\site-packages\sklearn\utils\_param_validation.py", line 213, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "D:\Ct_ iSpace\Wei\Python\iPython\T00_Env\Lib\site-packages\sklearn\metrics\cluster\_unsupervised.py", line 140, in silhouette_score
    return np.mean(silhouette_samples(X, labels, metric=metric, **kwds))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Ct_ iSpace\Wei\Python\iPython\T00_Env\Lib\site-packages\sklearn\utils\_param_validation.py", line 186, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "D:\Ct_ iSpace\Wei\Python\iPython\T00_Env\Lib\site-packages\sklearn\metrics\cluster\_unsupervised.py", line 267, in silhouette_samples
    X, labels = check_X_y(X, labels, accept_sparse=["csr"])
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Ct_ iSpace\Wei\Python\iPython\T00_Env\Lib\site-packages\sklearn\utils\validation.py", line 1192, in check_X_y
    X = check_array(
        ^^^^^^^^^^^^
  File "D:\Ct_ iSpace\Wei\Python\iPython\T00_Env\Lib\site-packages\sklearn\utils\validation.py", line 989, in check_array
    raise ValueError(msg)
ValueError: Expected 2D array, got 1D array instead:
array=[253 253 253 ... 253 253 253].
Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample.

异常原因: silhouette_score 函数期望接收的数据是一个2D数组,而 Demo 提供的是一个1维数组。因为输入是两张图片,而不是聚类数据,计算轮廓系数就不太适用了,因为轮廓系数通常用于衡量聚类的质量。

解决方案: 使用 array.reshape(-1, 1) 来将数据转换成2D数组。

7. 参考资料

互信息 - 百度百科
什么是「互信息」?
互信息是什么?

8. 系列书签

均值哈希算法: OpenCV书签 #均值哈希算法的原理与相似图片搜索实验

感知哈希算法: OpenCV书签 #感知哈希算法的原理与相似图片搜索实验

差值哈希算法: OpenCV书签 #差值哈希算法的原理与相似图片搜索实验

直方图算法: OpenCV书签 #直方图算法的原理与相似图片搜索实验

余弦相似度: OpenCV书签 #余弦相似度的原理与相似图片/相似文件搜索实验

SSIM结构相似性: OpenCV书签 #结构相似性SSIM算法的原理与图片相似性实验

相关推荐
galileo20163 分钟前
转化为MarkDown
人工智能
沐霜枫叶8 分钟前
解决pycharm无法识别miniconda
ide·python·pycharm
途途途途30 分钟前
精选9个自动化任务的Python脚本精选
数据库·python·自动化
说私域42 分钟前
私域电商逆袭密码:AI 智能名片小程序与商城系统如何梦幻联动
人工智能·小程序
蓝染然1 小时前
jax踩坑指南——人类早期驯服jax实录
python
请站在我身后1 小时前
复现Qwen-Audio 千问
人工智能·深度学习·语言模型·语音识别
许野平1 小时前
Rust: enum 和 i32 的区别和互换
python·算法·rust·enum·i32
问道飞鱼1 小时前
【Python知识】Python进阶-什么是装饰器?
开发语言·python·装饰器
love you joyfully1 小时前
目标检测与R-CNN——paddle部分
人工智能·目标检测·cnn·paddle
AI视觉网奇2 小时前
Detected at node ‘truediv‘ defined at (most recent call last): Node: ‘truediv‘
人工智能·python·tensorflow