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

1. 介绍

直方图算法(Image Histogram Algorithm) 通过统计图像中各个颜色值的分布情况来提供关于图像颜色特征的信息,它可以用来衡量两张图片在颜色分布上的相似度,进而可以用来进行图像相似度的比较,因此,直方图算法是一种常用的图片相似度算法,通常是一个一维的数组(取决于使用通道的数量),其中每个元素表示特定颜色或强度值的像素数量。

关于直方图算法的一些概念:

直方图的定义

直方图是一个二维数组,通常是一维的(取决于使用通道的数量),其中每个元素表示特定颜色或强度值的像素数量。对于彩色图像,通常有多个通道,比如蓝、绿、红(BGR),因此可能有多个直方图。

直方图的统计

  • 直方图的统计是通过扫描图像的每个像素来收集颜色信息的过程。
  • 对于灰度图像(属于单通道),每个像素只有一个强度值,因此只有一个通道的直方图。对于彩色图像,每个像素有多个通道的值,所以需要分别统计每个通道的直方图。
  • 关于单通道更详细的详细实验可见下文:讨论1#关于单通道 [0]

直方图的用途

  • 直方图可以用于多种图像处理任务,包括图像增强、颜色校正、图像分割、物体检测和图像相似性比较。
  • 通过分析直方图,可以获得有关图像的颜色分布、对比度、亮度等信息。

直方图均衡化

  • 直方图均衡化是一种用于增强图像对比度的技术,它通过重新分配像素的强度值来拉伸或压缩直方图,以使其分布更均匀。这可以使图像中的细节更加清晰。

直方图相似度

  • 直方图相似度用于比较两幅图像的相似程度。通过计算两个图像的直方图之间的差异,可以量化它们的相似性。
  • 常见的直方图相似度度量包括交叉相关性(cv2.HISTCMP_INTERSECT)、卡方距离(cv2.HISTCMP_CHISQR)、相关性(cv2.HISTCMP_CORREL)、巴氏距离(cv2.HISTCMP_BHATTACHARYYA)等。
  • 对于直方图比较方法的详细实验可见下文:讨论2#直方图相似度函数

颜色直方图

  • 对于彩色图像,颜色直方图通常分别计算每个通道的直方图。这可以提供关于不同颜色通道的颜色分布信息,有助于颜色特征的分析。
  • 对于彩色图像直方图的详细实验可见下文:讨论3#彩色图像直方图

 

2. 原理

直方图算法通过统计图像中不同颜色的像素数量,并以直方图的形式呈现,进而进行图像相似度的比较。

关于 bin

在一个灰度图像中,像素值的范围通常从黑色(0)到白色(255)之间变换。如果将图像的像素值范围分成 256 个 bin 格子,那么每个 bin 格子则代表一个灰度级别,其灰度值从 0 到 255。直方图中每个 bin 格子记录了对应灰度级别的像素数量,通过统计每个 bin 格子中的像素数量,就可以了解图像中不同灰度级别的分布情况。

即可看作有你 256 张灰色系色度卡,每一个灰度卡上都统计了灰度图像中所有该色度的像素数量,这样就可以直观看出灰度图像的像素在不同色度卡上的分布,然后和其它图像加以对比分析。

 

3. 魔法

直方图计算图片相似度的步骤:

  1. 图像预处理: 将目标图像转换为灰度图像或彩色图像,并根据需要进行尺寸调整。
  2. 计算直方图: 对于灰度图像,直方图表示不同灰度级别的像素数量。对于彩色图像,可以分别计算各个通道(如红、绿、蓝)的直方图对图像中的每个像素进行像素值的统计,以确定每个像素值的频率或数量。这通常包括遍历图像的每个像素,并将其像素值归类到相应的像素值区间(通常是0到255)。最终,得到一个表示像素值频率的直方图。
  3. 直方图比较: 对于两张图片的直方图,可以使用不同的距离或相似度度量方法来进行比较。常见的度量方法包括相关性、卡方距离、巴氏距离等。
  4. 相似度评估: 根据直方图比较的结果,计算出两张图片之间的相似度得分。

 

4. 实验

4.1 魔法

第一步:图像预处理

将目标图像转换为灰度图像或彩色图像,并根据需要进行尺寸调整。
1)读取原图: 首先读取我们要分析的图像。
2)图像灰度化: 如果需要计算灰度直方图,将彩色图像转换为灰度图像。这里我们使用 [0],只考虑图像灰度级别(亮度)信息,结果是一维数组。

第二步:计算直方图

对于灰度图像,直方图表示不同灰度级别的像素数量。

"""
以图搜图:图像直方图(Image Histogram)查找相似图像的原理与实现
测试环境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | matplotlib 3.7.1
实验时间:2023-10-27
实例名称:imgHistogram_v1.0.py
"""import cv2
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties# 目标图像素材库文件夹路径
database_dir = '../../P0_Doc/'
# 文件路径
img_path = database_dir + 'img_data/car-101.jpg'
font_path = database_dir + 'fonts/chinese_cht.ttf'# 读取图像
img = cv2.imread(img_path)
# 计算直方图
img_hist = cv2.calcHist([img], [0], None, [256], [0, 256])
print(img_hist)# 设置中文字体
font = FontProperties(fname=font_path, size=14)
# 绘制直方图
plt.plot(img_hist)
plt.title('Histogram(直方图)', fontproperties=font)
plt.xlabel('Pixel Value(像素值)', fontproperties=font)
plt.ylabel('Frequency(频率)', fontproperties=font)
# 像素分布可视化
plt.show()

输出打印:255个像素亮度

[[   25.][   13.][   13.][   25.][   39.]......[  798.][  779.][ 2034.]]

像素分布可视化效果(直方图):
ImageHistogram-0001
对于彩色图像,可以分别计算各个通道(如红、绿、蓝)的直方图。对图像中的每个像素进行像素值的统计,以确定每个像素值的频率或数量。这通常包括遍历图像的每个像素,并将其像素值归类到相应的像素值区间(通常是0到255)。最终,得到一个表示像素值频率的直方图。

img_hist = cv2.calcHist([img], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])

注:彩色直方图我们下后面详说。

cv2.calcHist 函数用于计算图像的直方图。以下是它的主要参数和说明:

  • img:要计算直方图的图像。它以方括号的形式传递,允许计算多个图像的直方图。例如,[img] 表示计算单个图像的直方图,[img1, img2] 表示计算两个图像的直方图。
  • channels:指定要考虑的通道。这是一个通道索引列表,用于选择要计算直方图的通道。在 OpenCV 中,通常情况下,通道 0 对应于蓝色(B),通道 1 对应于绿色(G),通道2 对应于红色(R)。如果要考虑所有通道,可以使用 [0, 1, 2],而对于单通道,只会考虑图像的灰度信息,而不考虑颜色信息。使用 [0] 即可表示灰色通道,也可以使用 [1] 或 [2] 表示灰色单通道。B、G、R 单通道的对比效果见下文 讨论1#关于单通道 [0]
  • mask:可选参数,用于指定一个掩码图像,以便只计算掩码中非零元素对应的像素值。如果不需要掩码,可以将其设置为 None。
    histSize:指定直方图的 bin 数量,即要计算的直方图的维度。它通常以方括号形式传递,例如 [256] 表示每个通道有 256 个 bin(256个色卡)。
  • ranges:指定像素值的范围。通常以方括号形式传递,例如 [0, 256] 表示单通道像素值的范围从 0 到 255。对于彩色图像,通常设置为 [0, 256, 0, 256, 0, 256],表示三个通道的范围。

 

讨论1:关于单通道 [0]

  • 因为通道 0 对应的是蓝色(B),所以 [0] ,即使用了蓝色(B)单通道的灰度图像,因为灰度图像中只有一个通道(单通道)。
  • 所以,[1]、[2] 都可以表示单通道的灰度图像。
  • 同理,[0]、[1]、[2] 虽然都可以表示单通道的灰度图像,但由于使用的通道分别是 0:蓝色(Blue)、1:绿色(Green)、2:红色(Red),所以,灰度图像的亮度略有区别(会影响灰度像素亮度分布)。

效果如下(分别是BGR、RGB、B、G、R):
ImageHistogram-0002
示图代码:

"""
以图搜图:图像直方图(Image Histogram)查找相似图像的原理与实现
测试环境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | matplotlib 3.7.1
实验时间:2023-10-27
实例名称:imgHistogram_v1.2_rgb_split.py
"""import cv2
import matplotlib.pyplot as plt# 目标图像素材库文件夹路径
database_dir = '../../P0_Doc/'
# 文件路径
img_path = database_dir + 'img_data/car-101.jpg'# 读取图像:默认使用BGR加载图像
img = cv2.imread(img_path)
# 分离通道:将彩色图像分离成各个通道(R、G、B),然后分别绘制它们的直方图
img_b, img_g, img_r = cv2.split(img)# 绘制子图
plt.figure(figsize=(15, 5))
# 151:表示子图位于一个 1x5 的网格中的第一个位置。如比第2张图的位置152,即一行五列第2张图
# 显示各通道的图像
plt.subplot(151)
plt.imshow(img)
plt.title('BGR (Default)')plt.subplot(152)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('BGR TO RGB')plt.subplot(153)
plt.imshow(cv2.cvtColor(img_b, cv2.COLOR_BGR2RGB))
plt.title('Blue Channel')plt.subplot(154)
plt.imshow(cv2.cvtColor(img_g, cv2.COLOR_BGR2RGB))
plt.title('Green Channel')plt.subplot(155)
plt.imshow(cv2.cvtColor(img_r, cv2.COLOR_BGR2RGB))
plt.title('Red Channel')plt.show()

代码对目标图像进行 R、G、B 通道分离,读取像素,然后分别绘制它们的直方图。

下图中,读取目标图像的方式分别是:BGR、RGB、B、G、R,绘画出来的直方图灰度像素分布效果如下:
ImageHistogram-0003
可以看到,BGR 与 Blue(第1张与第3张)、RGB 与 Red(第2张与第5张)的灰度像素分布趋势一致。

示图代码:

"""
以图搜图:图像直方图(Image Histogram)查找相似图像的原理与实现
测试环境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | matplotlib 3.7.1
实验时间:2023-10-27
实例名称:imgHistogram_v1.3_rgb_split.py
"""import cv2
import matplotlib.pyplot as plt# 目标图像素材库文件夹路径
database_dir = '../../P0_Doc/'
# 文件路径
img_path = database_dir + 'img_data/car-101.jpg'# 读取图像:默认使用BGR加载图像
img = cv2.imread(img_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 分离通道:将彩色图像分离成各个通道(R、G、B),然后分别绘制它们的直方图
img_b, img_g, img_r = cv2.split(img)# 计算各通道的直方图
hist_bgr = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_rgb = cv2.calcHist([img_rgb], [0], None, [256], [0, 256])
hist_b = cv2.calcHist([img_b], [0], None, [256], [0, 256])
hist_g = cv2.calcHist([img_g], [0], None, [256], [0, 256])
hist_r = cv2.calcHist([img_r], [0], None, [256], [0, 256])# 绘制线图子图展示各通道的直方图灰度趋势
plt.subplot(151)
plt.plot(hist_bgr, color='orange')
plt.title('BGR Histogram')plt.subplot(152)
plt.plot(hist_rgb, color='purple')
plt.title('RGB Histogram')plt.subplot(153)
plt.plot(hist_b, color='b')
plt.title('Blue Histogram')plt.subplot(154)
plt.plot(hist_g, color='g')
plt.title('Green Histogram')plt.subplot(155)
plt.plot(hist_r, color='r')
plt.title('Red Histogram')plt.show()

如果不好分辨,我们再加上 [0]、[1]、[2] 单通道合成一张直方图:
ImageHistogram-0004
可以清楚看到,合成后的直方图,只剩下 B、G、R 三通道的灰度像素分布趋势。

示图代码:

"""
以图搜图:图像直方图(Image Histogram)查找相似图像的原理与实现
测试环境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | matplotlib 3.7.1
实验时间:2023-10-27
实例名称:imgHistogram_v1.4_rgb_one.py
"""import cv2
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties# 目标图像素材库文件夹路径
database_dir = '../../P0_Doc/'
# 文件路径
img_path = database_dir + 'img_data/car-101.jpg'
# 字体路径
font_path = database_dir + 'fonts/chinese_cht.ttf'# 读取图像
img = cv2.imread(img_path)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 分离通道:将彩色图像分离成各个通道(R、G、B),然后分别绘制它们的直方图
img_b, img_g, img_r = cv2.split(img)# 计算各通道的直方图(依次为 BGR、RGB、0:蓝色通道,1:绿色通道,2:红色通道)
hist_bgr = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_rgb = cv2.calcHist([img_rgb], [0], None, [256], [0, 256])hist_b = cv2.calcHist([img_b], [0], None, [256], [0, 256])
hist_g = cv2.calcHist([img_g], [0], None, [256], [0, 256])
hist_r = cv2.calcHist([img_r], [0], None, [256], [0, 256])hist_0 = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_1 = cv2.calcHist([img], [1], None, [256], [0, 256])
hist_2 = cv2.calcHist([img], [2], None, [256], [0, 256])# 绘制多线线图,展示各通道的直方图灰度趋势
plt.plot(hist_bgr, color='orange', label='BGR')
plt.plot(hist_rgb, color='purple', label='RGB')plt.plot(hist_b, color='blue', label='Channel Blue')
plt.plot(hist_0, color='blue', label='Channel 0')plt.plot(hist_g, color='green', label='Channel Green')
plt.plot(hist_1, color='green', label='Channel 1')plt.plot(hist_r, color='red', label='Channel Red')
plt.plot(hist_2, color='red', label='Channel 2')# 设置中文字体
font = FontProperties(fname=font_path, size=14)
plt.title('Histogram(直方图)', fontproperties=font)
plt.xlabel('Pixel Value(像素值)', fontproperties=font)
plt.ylabel('Frequency(频率)', fontproperties=font)# 添加图例
plt.legend()
# 显示图像
plt.show()

计算各通道的直方图(依次为 BGR,RGB,0:蓝色通道,1:绿色通道,2:红色通道):

  • [0]: 使用 cv2.imread(img_path) 的 img、cv2.split(img) 中的 img_b、[0] 获得到的灰度像素分布趋势等同
  • [1]: 使用 cv2.split(img) 中的 img_g、[1] 获得到的灰度像素分布趋势等同
  • [2]: 使用 cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 的 img_rgb、cv2.split(img) 中的 img_r、[2] 获得到的灰度像素分布趋势等同

所以,[0]、[1]、[2] 都可以表示单通道的灰度图像,但由于使用的通道分别是 蓝色(Blue)、绿色(Green)、红色(Red),所以,灰度图像的亮度略有区别(会影响灰度像素亮度分布),体现在直方图上,则表现为灰度像素的分布趋势略有差异。

第三步:直方图比较

对于两张图像的直方图比较,可以使用不同的距离或相似度度量方法来进行比较。常见的度量方法包括相关性、卡方距离、巴氏距离等。

"""
以图搜图:图像直方图(Image Histogram)查找相似图像的原理与实现
测试环境:win10 | python 3.9.13 | OpenCV 4.4.0
实验时间:2023-10-27
实例名称:imgHistogram_v2.1_graySimilarity.py
"""import cv2def get_calcHist(img1_path, img2_path):# 读取图像img1 = cv2.imread(img1_path)img2 = cv2.imread(img2_path)# 计算图像灰度单通道直方图img1_hist = cv2.calcHist([img1], [0], None, [256], [0, 256])img2_hist = cv2.calcHist([img2], [0], None, [256], [0, 256])# 计算直方图相似度# cv2.HISTCMP_CORREL: 相关性比较,值越接近 1 表示颜色分布越相似similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_CORREL)print("图像2与图像1的相似度(HISTCMP_CORREL/相关性):", similarity)# 或者# 计算直方图的重合度degree = 0for i in range(len(img1_hist)):if img1_hist[i] != img2_hist[i]:degree = degree + (1 - abs(img1_hist[i] - img2_hist[i]) / max(img1_hist[i], img2_hist[i]))else:degree = degree + 1degree = degree / len(img1_hist)print("图像2与图像1的重合度:", degree)return similarity# 目标图像素材库文件夹路径
database_dir = '../../P0_Doc/img_data/'
# 文件路径
img1_path = database_dir + 'car-101.jpg'
img2_path = database_dir + 'car-102.jpg'print("图像1路径:", img1_path)
print("图像2路径:", img2_path)get_calcHist(img1_path, img2_path)

输出打印:

图像1路径: ../../P0_Doc/img_data/car-101.jpg
图像2路径: ../../P0_Doc/img_data/car-102.jpg
图像2与图像1的相似度(HISTCMP_CORREL/相关性): 1.0
图像2与图像1的重合度: 1.0

说明:图像2是图像1的180度倒置图。

cv2.compareHistOpenCV 中用于比较直方图相似度的函数。用于计算两个直方图之间的相关性(correlation)。img1_hist 和 img2_hist 是两个直方图,它们分别代表两幅图像的颜色分布。

直方图的比较方法:

  • cv2.HISTCMP_CORREL(相关性): 计算两个直方图之间的相关性。相关性的值越接近1,表示两幅图像的颜色分布越相似,值越接近-1表示颜色分布越不相似,值接近0表示中等相似度。但不太适用于颜色直方图比较。
  • cv2.HISTCMP_CHISQR(卡方距离): 计算卡方距离,用于比较两个直方图之间的差异。值越接近 0 表示颜色分布越相似。
  • cv2.HISTCMP_INTERSECT(交集性): 计算两个直方图的交集,用于度量它们的相似度。该值越大表示相似度越高。
  • cv2.HISTCMP_BHATTACHARYYA(巴氏距离): 计算两个直方图之间的巴氏距离。值越接近 0 表示颜色分布越相似。

 

讨论2:直方图相似度函数
使用 cv2.compareHist(),不同的直方图比较方法,对比结果略有差异。这里,我们使用 [0] 作为灰度通道进行测试实验。

"""
以图搜图:图像直方图(Image Histogram)查找相似图像的原理与实现
测试环境:win10 | python 3.9.13 | OpenCV 4.4.0
实验时间:2023-10-27
实例名称:imgHistogram_v2.3_compareHist.py
"""import cv2
import osdef get_degreeHist(img1_hist, img2_hist):# 计算直方图的重合度degree = 0for i in range(len(img1_hist)):if img1_hist[i] != img2_hist[i]:degree = degree + (1 - abs(img1_hist[i] - img2_hist[i]) / max(img1_hist[i], img2_hist[i]))else:degree = degree + 1degree = degree / len(img1_hist)return degreedef all_compareHist(img1_path, img2_path):img1 = cv2.imread(img1_path)img2 = cv2.imread(img2_path)img1_hist = cv2.calcHist([img1], [0], None, [256], [0, 256])img2_hist = cv2.calcHist([img2], [0], None, [256], [0, 256])similarity = get_degreeHist(img1_hist, img2_hist)print(f"图像 {os.path.basename(img2_path)} 与目标图像 {os.path.basename(img1_path)} 的相似度:", similarity)# 计算直方图相似度# cv2.HISTCMP_BHATTACHARYYA: 巴氏距离比较,值越接近 0 表示颜色分布越相似similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_BHATTACHARYYA)print(f"图像 {os.path.basename(img2_path)} 与目标图像 {os.path.basename(img1_path)} 的相似度(HISTCMP_BHATTACHARYYA/巴氏距离):", similarity)# cv2.HISTCMP_CHISQR: 卡方比较,值越接近 0 表示颜色分布越相似similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_CHISQR)print(f"图像 {os.path.basename(img2_path)} 与目标图像 {os.path.basename(img1_path)} 的相似度(HISTCMP_CHISQR/卡方比较):", similarity)# cv2.HISTCMP_CORREL: 相关性比较,值越接近 1 表示颜色分布越相似similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_CORREL)print(f"图像 {os.path.basename(img2_path)} 与目标图像 {os.path.basename(img1_path)} 的相似度(HISTCMP_CORREL/相关性):", similarity)# cv2.HISTCMP_INTERSECT: 直方图交集比较,值越大表示颜色分布越相似similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_INTERSECT)print(f"图像 {os.path.basename(img2_path)} 与目标图像 {os.path.basename(img1_path)} 的相似度(HISTCMP_INTERSECT/交集比较):", similarity)return similarity# 目标图像素材库文件夹路径
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'all_compareHist(img1_path, img2_path)

输出打印:

图像 car-102.jpg 与目标图像 car-101.jpg 的相似度: 1.0
图像 car-102.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_BHATTACHARYYA/巴氏距离): 0.0
图像 car-102.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_CHISQR/卡方比较): 0.0
图像 car-102.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_CORREL/相关性): 1.0
图像 car-102.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_INTERSECT/交集比较): 1232154.0图像 car-103.jpg 与目标图像 car-101.jpg 的相似度: [0.6923658]
图像 car-103.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_BHATTACHARYYA/巴氏距离): 0.2135487778250319
图像 car-103.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_CHISQR/卡方比较): 11867327.715396598
图像 car-103.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_CORREL/相关性): 0.4266303485505497
图像 car-103.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_INTERSECT/交集比较): 972986.0

 

讨论3:彩色图像直方图

"""
以图搜图:图像直方图(Image Histogram)查找相似图像的原理与实现
测试环境:win10 | python 3.9.13 | OpenCV 4.4.0
实验时间:2023-10-27
实例名称:imgHistogram_v2.4_rgb_compareHist.py
"""import cv2
import osdef bgr_compareHist(img1_path, img2_path):img1 = cv2.imread(img1_path)img2 = cv2.imread(img2_path)img1_hist = cv2.calcHist([img1], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])img2_hist = cv2.calcHist([img2], [0, 1, 2], None, [8, 8, 8], [0, 256, 0, 256, 0, 256])# 计算直方图相似度# cv2.HISTCMP_BHATTACHARYYA: 巴氏距离比较,值越接近 0 表示颜色分布越相似similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_BHATTACHARYYA)print(f"图像 {os.path.basename(img2_path)} 与目标图像 {os.path.basename(img1_path)} 的相似度(HISTCMP_BHATTACHARYYA/巴氏距离):", similarity)# cv2.HISTCMP_CHISQR: 卡方比较,值越接近 0 表示颜色分布越相似similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_CHISQR)print(f"图像 {os.path.basename(img2_path)} 与目标图像 {os.path.basename(img1_path)} 的相似度(HISTCMP_CHISQR/卡方比较):", similarity)# cv2.HISTCMP_CORREL: 相关性比较,值越接近 1 表示颜色分布越相似similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_CORREL)print(f"图像 {os.path.basename(img2_path)} 与目标图像 {os.path.basename(img1_path)} 的相似度(HISTCMP_CORREL/相关性):", similarity)# cv2.HISTCMP_INTERSECT: 直方图交集比较,值越大表示颜色分布越相似similarity = cv2.compareHist(img1_hist, img2_hist, cv2.HISTCMP_INTERSECT)print(f"图像 {os.path.basename(img2_path)} 与目标图像 {os.path.basename(img1_path)} 的相似度(HISTCMP_INTERSECT/交集比较):", similarity)return similarity# 目标图像素材库文件夹路径
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'bgr_compareHist(img1_path, img2_path)

输出打印:

图像 car-102.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_BHATTACHARYYA/巴氏距离): 0.0
图像 car-102.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_CHISQR/卡方比较): 0.0
图像 car-102.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_CORREL/相关性): 1.0
图像 car-102.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_INTERSECT/交集比较): 1232154.0图像 car-103.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_BHATTACHARYYA/巴氏距离): 0.25780152883475765
图像 car-103.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_CHISQR/卡方比较): 981578.8189641015
图像 car-103.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_CORREL/相关性): 0.8933747646918704
图像 car-103.jpg 与目标图像 car-101.jpg 的相似度(HISTCMP_INTERSECT/交集比较): 911172.0

对比 讨论2:直方图相似度函数 的输出结果,可以看到,相同测试图像,彩色直方图的相似度 与 灰度直方图的相似度 有一点差异,原因就是,通过单通道的灰度直方图,可以捕捉到图像的整体亮度和对比度信息,而不受颜色的影响。在相似图片查找中,通常更关注图像的结构和纹理,因此灰度信息更具代表性。

第四步:相似度评估

根据直方图比较的结果(似度得分),进行目标图像相似度评估。
案例场景:图像测试素材库中,查找所有图像,找出与目标图像相似值小于等于0.5的图像。

    ......for similarity in similarities:if (similarity[1] <= 0.5):print(f"图像名称:{similarity[0]},与目标图像 {os.path.basename(img_org_path)} 的近似值:{similarity[1]}")

 

4.2 测试

实验场景

通过 opencv,使用直方图算法查找目标图像素材库中所有符合期望值的相似图像。

实验素材

这里,我准备了45张素材图像,其中14张图像为水果,其余为不同类型的汽车,但形态不一。
ImageHistogram-0005

实验代码

"""
以图搜图:图像直方图(Image Histogram)查找相似图像的原理与实现
测试环境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1 | matplotlib 3.7.1
实验场景:图像测试素材库中,查找所有图像,找出与目标图像相似值小于等于0.7的图像
实验时间:2023-10-27
实例名称:imgHistogram_v3.2_gray_show.py
"""import os
import time
import cv2
import matplotlib.pyplot as pltdef get_calcHist(org_img_hist, img_path):# 读取图像:通过OpenCV的imread加载RGB图像img = cv2.imread(img_path)# img = cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2GRAY)img_hist = cv2.calcHist([img], [0], None, [256], [0, 256])# 计算直方图相似度# cv2.HISTCMP_CORREL: 相关性比较,值越接近 1 表示颜色分布越相似# cv2.HISTCMP_CHISQR: 卡方比较,值越接近 0 表示颜色分布越相似# cv2.HISTCMP_BHATTACHARYYA: 巴氏距离比较,值越接近 0 表示颜色分布越相似# cv2.HISTCMP_INTERSECT: 直方图交集比较,值越大表示颜色分布越相似similarity = cv2.compareHist(org_img_hist, img_hist, cv2.HISTCMP_BHATTACHARYYA)return similaritydef show_similar_images(similar_images, images_per_column=3):# 计算总共的图片数量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:.4f}")# 关闭坐标轴axes[row, col].axis('off')# 显示整个图plt.show()# ------------------------------------------------ 测试 ------------------------------------------------
if __name__ == '__main__':time_start = time.time()# 指定测试图像库目录img_dir = '../../P0_Doc/img_data/'# 指定测试图像文件扩展名img_suffix = ['.jpg', '.jpeg', '.png', '.bmp', '.gif']# 获取当前执行脚本所在目录script_dir = os.path.dirname(__file__)# 获取目标测试图像的全路径img_org_path = os.path.join(script_dir, img_dir, 'apple-101.jpg')# 加载要查询的图像query_image = cv2.imread(img_org_path)# query_image = cv2.cvtColor(cv2.imread(img_org_path), cv2.COLOR_BGR2GRAY)# 计算查询图像的直方图:灰度直方图算法img_org_hist = cv2.calcHist([query_image], [0], None, [256], [0, 256])print(f"目标图像:{os.path.relpath(img_org_path)}")# 获取测试图像库中所有文件all_files = os.listdir(os.path.join(script_dir, img_dir))# 筛选出指定后缀的图像文件img_files = [file for file in all_files if any(file.endswith(suffix) for suffix in img_suffix)]# 存储相似度值和对应的图像路径img_search_results = []# 遍历测试图像库中的每张图像for img_file in img_files:# 获取相似图像文件路径img_path = os.path.join(script_dir, img_dir, img_file)# 获取相似图像可识别哈希值(图像指纹)similarity = get_calcHist(img_org_hist, img_path)# print(f"图像名称:{img_path},与目标图像 {os.path.basename(img_org_path)} 的近似值:{similarity}")if (similarity <= 0.7):# 存储相似度值和对应的图像路径img_search_results.append((os.path.relpath(img_path), similarity))# 按相似度升序排序img_search_results.sort(key=lambda item: item[1])for img_similarity in img_search_results:print(f"图像名称:{img_similarity[0]},与目标图像 {os.path.basename(img_org_path)} 的相似值:{img_similarity[1]}")time_end = time.time()print(f"耗时:{time_end - time_start}")# 显示目标相似图像show_similar_images(img_search_results)

多图相似查找效果显示,实验代码使用的是巴氏距离比较,值越接近 0 表示颜色分布越相似:
ImageHistogram-0006

输出打印:

目标图像:..\..\P0_Doc\img_data\apple-101.jpg
图像名称:..\..\P0_Doc\img_data\apple-101.jpg,与目标图像 apple-101.jpg 的相似值:0.0
图像名称:..\..\P0_Doc\img_data\apple-104.jpg,与目标图像 apple-101.jpg 的相似值:0.0
图像名称:..\..\P0_Doc\img_data\car-109.jpg,与目标图像 apple-101.jpg 的相似值:0.6158102157213413
图像名称:..\..\P0_Doc\img_data\car-103.jpg,与目标图像 apple-101.jpg 的相似值:0.662176197294615
图像名称:..\..\P0_Doc\img_data\car-101.jpg,与目标图像 apple-101.jpg 的相似值:0.6813075243521007
图像名称:..\..\P0_Doc\img_data\car-102.jpg,与目标图像 apple-101.jpg 的相似值:0.6813075243521007
图像名称:..\..\P0_Doc\img_data\Q3-09.jpg,与目标图像 apple-101.jpg 的相似值:0.6844184531149912
图像名称:..\..\P0_Doc\img_data\car-108.jpg,与目标图像 apple-101.jpg 的相似值:0.6861940450661771
图像名称:..\..\P0_Doc\img_data\X3-09.jpg,与目标图像 apple-101.jpg 的相似值:0.692340714053627
图像名称:..\..\P0_Doc\img_data\apple-114.jpg,与目标图像 apple-101.jpg 的相似值:0.6932278615425139
图像名称:..\..\P0_Doc\img_data\apple-112.jpg,与目标图像 apple-101.jpg 的相似值:0.6959175186621991
图像名称:..\..\P0_Doc\img_data\pear-201.jpg,与目标图像 apple-101.jpg 的相似值:0.6997766670329476
耗时:1.0362038612365723

 

5. 总结

总体来说,直方图算法属于一种传统外观相似算法,适用于一些简单的图像相似性比较问题,但直方图反应的是图像灰度值得概率分布,并没有图像的空间位置信息在里面,因此,可能会出现误判。比如纹理结构相同,但明暗不同的图像,应该相似度很高,但实际结果是相似度很低,而纹理结构不同,但明暗相近的图像,相似度却很高。

优点

  1. 简单直观: 直方图是一种简单直观的图像表达方式,易于理解和实现。
  2. 快速计算: 直方图的计算相对快速,特别是对于小尺寸的图像。
  3. 颜色不变性: 直方图在某种程度上对颜色的变化具有不变性,因此可以在一定程度上应对图像的轻微变形。
  4. 对光照变化有一定的鲁棒性: 直方图可以在一定程度上处理图像的光照变化。

缺点

  1. 不考虑空间信息: 直方图方法忽略了图像的空间信息,对于图像的排列、结构等方面的变化较为敏感。
  2. 受噪声影响: 如果图像受到噪声的影响,直方图会受到一定程度的干扰。
  3. 灰度信息有限: 灰度直方图只考虑了像素的灰度信息,对于颜色信息较为有限。
  4. 无法处理形状变化: 直方图方法难以处理图像中物体的形状变化。

 

6. 系列书签

OpenCV书签 #均值哈希算法的原理与相似图片搜索实验
OpenCV书签 #感知哈希算法的原理与相似图片搜索实验
OpenCV书签 #差值哈希算法的原理与相似图片搜索实验
OpenCV书签 #直方图算法的原理与相似图片搜索实验

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

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

相关文章

电脑录屏软件大比拼,哪个最适合你?

现如今&#xff0c;电脑录屏软件成为了许多用户记录、分享和教学的重要工具。从游戏玩家到专业制作人员&#xff0c;都需要高效的录屏软件。本文将介绍三款优秀的电脑录屏软件&#xff0c;通过详细的步骤和简洁的介绍&#xff0c;帮助用户轻松掌握这些工具的使用方法。 电脑录屏…

附1:k8s服务器初始化

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 关联文章&#xff1a; 《RKE快速搭建离线k8s集群并用rancher管理界面》 1.创建普通用户sre并赋予sudo权限 # adduser sre # ec…

【动态规划】879. 盈利计划

作者推荐 【动态规划】【广度优先搜索】【状态压缩】847 访问所有节点的最短路径 本文涉及知识点 动态规划汇总 LeetCode879. 盈利计划 集团里有 n 名员工&#xff0c;他们可以完成各种各样的工作创造利润。 第 i 种工作会产生 profit[i] 的利润&#xff0c;它要求 group[…

大模型独立解答30道国际奥数难题,能力接近金牌选手!

谷歌旗下的AI研究机构DeepMind和纽约大学的研究人员联合开发了一个AI模型——AlphaGeometry。 AlphaGeometr是一种神经符号模型,内置了大语言模型和符号推理引擎等功能,主要用于解决各种超难几何数学题&#xff0c;同时可以自动生成易于查看的解题原理。 为了验证AlphaGeomet…

React Router v6 改变页面Title

先说正事再闲聊 1、在路由表加个title字段 2、在index包裹路由 3、在App设置title 闲聊&#xff1a; 看到小黄波浪线了没 就是说默认不支持title字段了 出来的提示&#xff0c; 所以我本来是像下面这样搞的&#xff0c;就是感觉有点难维护&#xff0c;就还是用上面的方法了 …

Linux配置yum源以及基本yum指令

文章目录 一、yum介绍二、什么是软件包三、配置yum源四、一键配置yum源【三步走】五、yum指令搜索软件安装软件卸载软件 六、其他yum指令更新内核更新软件更新指定软件显示所有可更新的软件清单卸载指定包并自动移除依赖包删除软件包&#xff0c;以及软件包数据和配置文件 一、…

快速上手MyBatis Plus:简化CRUD操作,提高开发效率!

MyBatisPlus 1&#xff0c;MyBatisPlus入门案例与简介1.1 入门案例步骤1:创建数据库及表步骤2:创建SpringBoot工程步骤3:勾选配置使用技术步骤4:pom.xml补全依赖步骤5:添加MP的相关配置信息步骤6:根据数据库表创建实体类步骤7:创建Dao接口步骤8:编写引导类步骤9:编写测试类 1.2…

Redis常见类型及常用命令

目录 常见的数据类型 一、String类型 1、简介 2、常用命令 &#xff08;1&#xff09;新建key &#xff08;2&#xff09;设值取值 ​编辑 &#xff08;3&#xff09;批量操作 &#xff08;4&#xff09;递增递减 3、原子性操作 4、数据结构 二、list类型 1、list常…

Pytest中conftest.py的用法

Pytest中conftest.py的用法 ​ 在官方文档中&#xff0c;描述conftest.py是一个本地插件的文件&#xff0c;简单的说就是在这个文件中编写的方法&#xff0c;可以在其他地方直接进行调用。 注意事项 只能在根目录编写conftest.py 插件加载顺序在搜集用例之前 基础用法 这里…

centos 启动nacos pg版本

背景&#xff1a;支持国产化需求&#xff0c;不再使用mysql 1.修改插件 git clone https://github.com/wuchubuzai2018/nacos-datasource-extend-plugins.git cd nacos-datasource-extend-plugins/nacos-postgresql-datasource-plugin-ext mvn package编译成功后&#xff0c;…

原来岳云鹏背后的女人竟然是她?有她,岳云鹏红遍大江南北。

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 岳云鹏&#xff0c;一个出身于农村的普通孩子&#xff0c;曾经…

springboot小白入门

创建启动 省略。。。 第二章 springboot接口 本章学习&#xff1a; 1.接口定义 2.接收数据 3.返回数据 RestController注解&#xff0c;相当于ResponseBody &#xff0b; ControllerController负责接收用户的请求ResponseBody把数据写入到HTTP响应体的body部分RequestMappin…

【网络】传输层TCP协议

目录 一、概述 2.1 运输层的作用引出 2.2 传输控制协议TCP 简介 2.3 TCP最主要的特点 2.4 TCP连接 二、TCP报文段的首部格式 三、TCP的运输连接管理 3.1 TCP的连接建立(三次握手) 3.2 为什么是三次握手&#xff1f; 3.3 为何两次握手不可以呢&#xff1f; 3.4 TCP的…

docker 安装手册

docker 安装手册 第一步卸载旧的docker (如果安装过Docker否则跳过此步) 以防万一最好执行一遍 yum -y remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 第二步&#xff0c;安装相关…

网络安全概述---笔记总结

网络安全概述 网络安全---Cyberspace security 2003年美国提出网络空间的概念 --- 一个由信息基础设施组成的互相依赖的网络。我国官方文件定义&#xff1a;网络空间为继海&#xff0c;陆&#xff0c;空&#xff0c;天以外的第五大人类活动领域 发展阶段&#xff1a; 通信保…

Yolov8不废话!参考手册!

Yolov8使用 yolo taskdetect modetrain modelyolov8n.pt args...classify predict yolov8n-cls.yaml args...segment val yolov8n-seg.yaml args...export yolov8n.pt formatonnx args...使用Ultralytics YOLO进行模型训练 …

2024年安全员-C证证考试题库及安全员-C证试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年安全员-C证证考试题库及安全员-C证试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大纲随机出的…

力扣第92题——反转链表 II(C语言题解)

题目描述 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], left 2, right 4 输出&#xff1…

Linux的一些快捷键(hot keyboard)

Ctrl Alt t&#xff1a;打开bash&#xff08;就是命令框窗口&#xff09; Ctrl Alt F3~F6&#xff1a;打开tty终端&#xff08;纯命令行终端&#xff0c;每个Linux发行版不相同&#xff0c;我的是Ubuntu20版&#xff09; Alt F4&#xff1a;关闭当前窗口&#xff08;Windo…

知识图谱的广泛应用与价值

目录 前言1 语义搜索2 知识问答2.1 问答对的深度关联2.2 文本挖掘与答案精准性2.3 知识图谱问答的全面服务 3 辅助推荐4 辅助大数据分析4.1 知识图谱推理的应用4.2 知识图谱的数据分析4.3 动态本体技术的引入 5 故障诊断5.1 故障诊断系统的应用5.2 知识图谱在语言理解中的作用5…