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.rhkb.cn/news/243485.html

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

相关文章

【Java】--网络编程:基于TCP协议的网络通信

【Java】–网络编程&#xff1a;基于TCP协议的网络通信 文章目录 【Java】--网络编程&#xff1a;基于TCP协议的网络通信一、TCP协议1.1 概念1.2 三次握手1.2.1 文字描述1.2.2 画图演示 1.3 四次挥手1.3.1 文字描述1.3.2 画图演示 二、基于TCP的Socket网络编程2.1 概念2.2 服务…

Elasticsearch:介绍 kNN query,这是进行 kNN 搜索的专家方法

作者&#xff1a;来自 Elastic Mayya Sharipova, Benjamin Trent 当前状况&#xff1a;kNN 搜索作为顶层部分 Elasticsearch 中的 kNN 搜索被组织为搜索请求的顶层&#xff08;top level&#xff09;部分。 我们这样设计是为了&#xff1a; 无论分片数量多少&#xff0c;它总…

为什么 HTTPS 协议能保障数据传输的安全性?

HTTP 协议 在谈论 HTTPS 协议之前&#xff0c;先来回顾一下 HTTP 协议的概念。 HTTP 协议介绍 HTTP 协议是一种基于文本的传输协议&#xff0c;它位于 OSI 网络模型中的应用层。 HTTP 协议是通过客户端和服务器的请求应答来进行通讯&#xff0c;目前协议由之前的 RFC 2616 拆…

JS进阶-函数进阶(一)

• 函数提升 函数提升与变量提升比较类似&#xff0c;是指函数在声明之前即可被调用。 总结&#xff1a; 1. 函数提升能够使函数的声明调用更灵活 2. 函数表达式不存在提升的现象 3. 函数提升出现在相同作用域当中 • 函数参数 1. 动态参数 arguments 是函数内部内置的伪…

Jmeter 配置元件

Jmeter 配置元件 CSV 数据集配置HTTP Cookie 管理器HTTP Header 信息头管理器增加多个用户案列 使用Jmeter发送请求的时候&#xff0c;需要配置元件&#xff0c;配置请求Header、Cookie、数据集合等。可以模拟多个在线用户登录&#xff0c;修改请求头数据。 CSV 数据集配置 C…

java遍历(for和forEach)

1.dade文件 package model;public class dade {private int id;private String name;public dade() {}public dade(int id, String name) {this.id id;this.name name;}public int getId() {return id;}public void setId(int id) {this.id id;}public String getName() {r…

书法AI全自动切字+识别算法2.0版发布,草书篆书行书楷书识别准确率超过90%,覆盖书法单字30万张

我们开发的业界识别最准覆盖作品最全的书法AI小程序上线了 书法AI全自动切字识别算法2.0版发布&#xff0c;草书篆书行书楷书识别准确率超过90%&#xff0c;准确率甩百度OCR一条街&#xff0c;覆盖书法单字30万张&#xff0c;遥遥领先同行 我们还可为客户提供书法AI全自动切字a…

C# wpf利用Clip属性实现截屏框

wpf截屏系列 第一章 使用GDI实现截屏 第二章 制作截屏框&#xff08;本章&#xff09; ______第一节 使用DockPanel制作截屏框 ______第二节 利用Clip属性实现截屏框(本节) 第三章 实现截屏框热键截屏 第四章 实现截屏框实时截屏 第五章 使用ffmpeg命令行实现录屏 文章目录 wp…

Git--基本操作介绍(2)

Git 常用的是以下 6 个命令&#xff1a;git clone、git push、git add 、git commit、git checkout、git pull. 说明&#xff1a; workspace&#xff1a;工作区staging area&#xff1a;暂存区/缓存区local repository&#xff1a;版本库或本地仓库remote repository&#xf…

69.使用Go标准库compress/gzip压缩数据存入Redis避免BigKey

文章目录 一&#xff1a;简介二&#xff1a;Go标准库compress/gzip包介绍ConstantsVariablestype Headertype Reader 三&#xff1a;代码实践1、压缩与解压工具包2、单元测试3、为何压缩后还要用base64编码 代码地址&#xff1a; https://gitee.com/lymgoforIT/golang-trick/t…

搜索与图论第六期 最短路问题

前言 最短路问题真的很重要很重要希望大家都能够完全掌握所有最短路算法&#xff01;&#xff01; 一、最短路问题的分类 Dijkstra&#xff1a; Dijkstra算法是一种著名的图算法&#xff0c;主要用于求解有权图中的单源最短路径问题。它由荷兰计算机科学家艾兹赫尔戴克斯特…

vue2(Vuex)、vue3(Pinia)、react(Redux)状态管理

vue2状态管理Vuex Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它使用集中式存储管理应用的所有组件的状态&#xff0c;以及规则保证状态只能按照规定的方式进行修改。 State&#xff08;状态&#xff09;:Vuex 使用单一状态树&#xff0c;即一个对象包含全部的应用层…

线性代数的学习和整理23:用EXCEL和python 计算向量/矩阵的:内积/点积,外积/叉积

目录 1 乘法 1.1 标量乘法(中小学乘法) 1.1.1 乘法的定义 1.1.2 乘法符合的规律 1.2 向量乘法 1.2.1 向量&#xff1a;有方向和大小的对象 1.2.2 向量的标量乘法 1.2.3 常见的向量乘法及结果 1.2.4 向量的其他乘法及结果 1.2.5 向量的模长&#xff08;长度&#xff0…

【极数系列】Flink环境搭建(02)

【极数系列】Flink环境搭建&#xff08;02&#xff09; 引言 1.linux 直接在linux上使用jdk11flink1.18.0版本部署 2.docker 使用容器部署比较方便&#xff0c;一键启动停止&#xff0c;方便参数调整 3.windows 搭建Flink 1.18.0版本需要使用Cygwin或wsl工具模拟unix环境…

RAMROM

RAM&#xff08;Random Access Memory&#xff09;&#xff0c;随机存取存储器&#xff0c;也叫主存&#xff0c;又称内存&#xff08;动态ROM&#xff09;&#xff0c;是与CPU直接交换数据的内部存储器。它可以随时读写&#xff08;刷新时除外&#xff09;&#xff0c;而且速度…

Flutter 自定义AppBar实现滚动渐变

1、使用ListView实现上下滚动。 2、使用Stack&#xff1a;允许将其子部件放在彼此的顶部&#xff0c;第一个子部件将放置在底部。所以AppBar&#xff0c;写在ListView下面。 3、MediaQuery.removePadding&#xff1a;当使用ListView的时候发现&#xff0c;顶部有块默认的Padd…

服务器数据恢复—服务器进水导致阵列中磁盘同时掉线的数据恢复案例

服务器数据恢复环境&#xff1a; 数台服务器数台存储阵列柜&#xff0c;共上百块硬盘&#xff0c;划分了数十组lun。 服务器故障&检测&#xff1a; 外部因素导致服务器进水&#xff0c;进水服务器中一组阵列内的所有硬盘同时掉线。 北亚数据恢复工程师到达现场后发现机房内…

链路聚合原理与配置

链路聚合原理 随着网络规模不断扩大&#xff0c;用户对骨干链路的带宽和可靠性提出了越来越高的要求。在传统技术中&#xff0c;常用更换高速率的接口板或更换支持高速率接口板的设备的方式来增加带宽&#xff0c;但这种方案需要付出高额的费用&#xff0c;而且不够灵活。采用…

【GitHub项目推荐--一个语音机器人项目】【转载】

推荐一个腾讯大佬开源的语音对话机器人&#xff1a;wukong-robot &#xff0c;悟空机器人在 GitHub 上斩获 3.2K 的 Star。 这是一个简单灵活的中文语音对话机器人项目&#xff0c;目的是让中国的开发者也能快速打造个性化的智能音箱&#xff0c;同时&#xff0c;该项目还是第…

JMeter 设置请求头信息的详细步骤

在使用 JMeter 的过程中&#xff0c;我们会遇到需要设置请求头信息的场景。比如&#xff1a; POST 传过去的 Body 数据是 json 格式的。需要填添加头信息&#xff1a;Content-Type&#xff1a;application/json。在 header 中用 token 来传用户的认证信息。 下面&#xff0c;…