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

对于彩色图像,可以分别计算各个通道(如红、绿、蓝)的直方图。对图像中的每个像素进行像素值的统计,以确定每个像素值的频率或数量。这通常包括遍历图像的每个像素,并将其像素值归类到相应的像素值区间(通常是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):

示图代码:
"""
以图搜图:图像直方图(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,绘画出来的直方图灰度像素分布效果如下:

可以看到,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,

1223

被折叠的 条评论
为什么被折叠?



