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

news2024/9/29 21:18:27

1. 介绍

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

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

1.1 助记

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

比如说有一天你的女神突然问你:“你猜猜我的爱豆是TFboys里的谁?”
唉,这要是猜不到,女神的心岂不是很完蛋,追求女神的路从此就凉了。
正当你非常不确定的时候,女神又说:“给你个提示吧,名字是四个字。”
此时你特别开心,因为对于答案的不确定性一下子就减少了(当然这个例子比较极端,不确定性直接降为0)

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

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

 

2. 魔法

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

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

 

3. 实验

3.1 魔法拆解

第一步:图像配准

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

# 读取图像
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,来实现互信息的计算。

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

# 将直方图归一化
# 即将直方图中的每个元素除以直方图的总和,以确保它们的和为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 计算这些较小值的总和。这个总和即为互信息的计算结果,即互信息的大小。

第三步:相似性度量

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

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

 

3.2 小实验

实验场景

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

实验代码

"""
以图搜图:互信息(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}")

输出打印:

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

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

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

 

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

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

互信息(Mutual Information):

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

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

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

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

 

4. 测试

4.1 实验素材

MutualInformation-001

4.2 实验过程

纵向比较

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

实验代码
"""
以图搜图:互信息(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_scoreV-Measure(V值)分数。结合了聚类的均匀性和完整性,提供了一个综合的聚类性能度量
homogeneity_score均匀性分数。用于度量每个聚类的成员是否都属于同一类别,高均匀性表示每个聚类都很“纯净”
completeness_score完整性分数。度量每个真实类别的成员是否都被分配到同一聚类中,高完整性表示每个类别都被很好地捕捉
adjusted_rand_score调整的兰德指数。度量两个聚类结果之间的相似性,考虑了数据集的随机性
fowlkes_mallows_scoreFowlkes-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,可以通过源码了解更多,比如:

    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

实验代码输出打印:

互信息相似度比较,图像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 算法,耗时最短。

横向比较

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

实验代码
"""
以图搜图:互信息(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)

第一组测试

测试结果输出打印:

图像:..\..\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

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

第二组测试

测试结果输出打印:

图像:..\..\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

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

 

5. 总结

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

优点

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

缺点

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

 

6. 问题

异常现象1

    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 依赖项:

pip install --upgrade scikit-image
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,以获取缺失的文件:

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 依赖项:

pip install scikit-learn

 

异常现象2

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算法的原理与图片相似性实验

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1410165.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯云tsf平台-部署微服务项目

腾讯云tsf平台-部署微服务项目 一、腾讯云tsf平台简介二、部署准备0&#xff08;数据库、中间件等部署&#xff09;三、部署准备1&#xff08;创建集群和命名空间&#xff09;1、准备部署资源--集群2、使用容器部署微服务步骤 1&#xff1a;创建容器集群步骤 2&#xff1a;创建…

数据结构:非完全二叉树(递归实现)

非完全二叉树是指在二叉树中&#xff0c;除了叶子节点&#xff08;无子节点&#xff09;外&#xff0c;其他节点的子节点个数可以不同&#xff0c;即不一定是每个节点都有两个子节点&#xff0c;有右孩子时也不一定有左孩子。 tree.h /* * 文件名称&#xff1a;tree.h * …

SpringBootAdmin邮件通知

在上一篇中我们学习到了 Admin Service Clustering 分布式缓存配置 &#xff0c;这一篇我们来学习&#xff0c;客户端离线&#xff0c;出现故障的时候&#xff0c;我们这么能及时知道呢&#xff0c;发现邮件通知也许是最简单的方式了&#xff01; 邮件通知 邮件通知将作为使用…

代码随想录 Leetcode111. 二叉树的最小深度

题目&#xff1a; 代码(首刷自解 2024年1月24日&#xff09;&#xff1a; class Solution { public:int minDepth(TreeNode* root) {if(root nullptr) return 0;queue<TreeNode*> que;TreeNode* cur root;que.push(cur);int size 0;int depth 0;while (!que.empty()…

【方法】如何打开7Z格式压缩文件?

7Z是一种常见的压缩文件格式&#xff0c;那遇到7Z压缩文件&#xff0c;要如何打开呢&#xff1f; 想要打开7Z压缩包&#xff0c;需要用到解压缩软件&#xff0c;比如WinRAR、7-Zip等软件。安装软件后&#xff0c;只需要用鼠标双击7Z压缩包&#xff0c;就可以打开压缩包&#x…

高数总结(3

目录 1.总结&#xff1a;小结&#xff1a; 1.总结&#xff1a; 小结&#xff1a; 关注我给大家分享更多有趣的知识&#xff0c;以下是个人公众号&#xff0c;提供 ||代码兼职|| ||代码问题求解|| 由于本号流量还不足以发表推广&#xff0c;搜我的公众号即可&#xff1a;

ECharts实现简单饼图和柱状图

1.JAVA 1.饼图 前端使用vue&#xff0c;后端使用SpringBoot <template><div><div class"card" style"padding: 15px">数据可视化分析&#xff1a;图书类型销量</div><div style"display: flex; margin: 10px 0"&g…

autosar学习笔记 之SecOC

SecOC 接下来SecOC标准就更复杂一点,它不单单是做了通讯校验。 SecOC是基于对称密钥加密的一套机制,需要对ECU间的通讯作身份认证处理,来更好的防止伪装攻击,谈起对称或非对称加密,就会涉及到密钥的存储和Mac值的计算。 因此SECOC机制对于密钥的硬件存储,也有一定的要求…

从零学习Hession RPC

为什么学习Hessian RPC&#xff1f; 存粹的RPC&#xff0c;只解决PRC的四个核心问题&#xff08;1.网络通信2.协议 3.序列化 4.代理&#xff09;Java写的HessianRPC落伍了&#xff0c;但是它的序列化方式还保存着&#xff0c;被Dubbo(Hessian Lite)使用。 被落伍&#xff0c;只…

K8S图像化工具rancher

Rancher是一个开源的企业级多集群的k8s管理平台 Rancher和k8s的区别 都是为了容器的调度和编排系统&#xff0c;但是rancher不仅能够调度&#xff0c;还能挂历k8s集群&#xff0c;自带监控&#xff08;普罗米修斯&#xff09;&#xff0c;你哪怕不知带k8s是什么&#xff0c;一样…

如何在Kali系统配置启动SSH并结合内网穿透实现远程连接

文章目录 1. 启动kali ssh 服务2. kali 安装cpolar 内网穿透3. 配置kali ssh公网地址4. 远程连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 简单几步通过[cpolar 内网穿透](cpolar官网-安全的内网穿透工具 | 无需公网ip | 远程访问 | 搭建网站)软件实现ssh 远程连接kali! …

【Kafka】Kafka安装:Linux本地和Docker

目录 Linux本地安装kafkajava环境配置Zookeeper的安装配置Kafka的安装与配置生产与消费 Docker安装kafkaZookeeper安装Kafka安装 Linux本地安装kafka java环境配置 1、上传jdk-8u261-linux-x64.rpm到服务器并安装&#xff1a; rpm -ivh jdk-8u261-linux-x64.rpm2、配置环境变…

抖音跳转微信公众号是怎么实现的丨数灵通

抖音是一款非常流行的社交媒体应用程序&#xff0c;用户可以在其中分享短视频和互动内容。许多用户希望通过抖音来引流到他们的微信公众号&#xff0c;以扩大影响力并吸引更多粉丝。以下是一些关于如何在抖音上跳转到微信公众号的科普信息&#xff1a; 1.信息流广告&#xff1a…

爬虫笔记(二):实战58二手房

第一&#xff1a;给大家推荐一个爬虫的网课哈&#xff0c;码起来 第二&#xff1a;今夜主题&#xff1a;通过xpath爬取58二手房的title信息&#xff0c;也就是标红的位置~ 第三&#xff1a;先分析一波title所在的位置 打开按下f12打开抓包工具&#xff0c;即可看到网站的源码…

RBD —— 不同材质破碎

目录 Working with concrete Chipping Details Proxy geometry Constraints Working with glass Chipping Proxy geometry Constraints Resolving issues with glass fracturing Working with wood Clustering Using custom cutters Working with concrete Concr…

2024年破圈9套商业模式电商干货,真心分享丨项目孵化必看

2024年破圈9套商业模式电商干货&#xff0c;真心分享丨项目孵化必看 文丨微三云营销总监胡佳东&#xff0c;点击上方“关注”&#xff0c;为你分享市场商业模式电商干货。 - 疫情过后&#xff0c;市场瞬息万变&#xff0c;理想状态的消费复苏和消费回暖的机遇并没有到来&…

简述Elasticsearch(ES)是什么 全文搜索概念 (倒排索引 管理文档)

今天 我们来说说 NoSql 中的 Elasticsearch 大家基本都叫它 ES 官方介绍 它是一个分布式全文搜索引擎 分布式是一个系统架构的概念 而 全文搜索引擎 全文搜索 可以说基本大家天天都在接触 就比如 我们京东购物 想买什么东西 在全文输入框中搜索 它就会在所有物品中 帮你找出需…

2023年AI大模型:从科技热潮到商业变革

出品&#xff1a;新商纪&#xff0c;作者&#xff1a;独孤依风 2023年&#xff0c;大模型技术在全球科技界掀起了一场风暴&#xff0c;引发了科技巨头们的激烈角逐。这一年&#xff0c;大模型不仅重新定义了人工智能的边界&#xff0c;还催生了跨行业技术革新。 根据IDC的预测…

年少不知 Base 好,错把总包当成宝。。

今天聊一个很现实的话题&#xff1a;选 offer 对比薪资时&#xff0c;我强烈建议以 Base 为主&#xff0c;而不是总包。 为什么&#xff1f;且听鱼皮娓娓道来。 注意&#xff0c;以下为个人观点&#xff0c;仅供参考&#xff01; 首先明确 Base 和总包的概念&#xff1a; Base&…

使用PowerShell命令行,批量修改文件编码

目录 ■前言 ■PowerShell命令 ■效果 ■前言 今天统计修改代码量&#xff0c;使用工具时&#xff0c;发现有些代码无法统计。 原因时UTF-8中有某些特殊字符&#xff0c;工具不能识别。 但是&#xff0c;如果把代码转换为SJIS格式&#xff0c;就能正常统计了。 因此&…