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

这篇具有很好参考价值的文章主要介绍了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.]]

像素分布可视化效果(直方图):
OpenCV书签 #直方图算法的原理与相似图片搜索实验,OpenCV,Python,算法,opencv,直方图算法,python,图搜索算法,相似图片搜索,以图搜图
对于彩色图像,可以分别计算各个通道(如红、绿、蓝)的直方图。对图像中的每个像素进行像素值的统计,以确定每个像素值的频率或数量。这通常包括遍历图像的每个像素,并将其像素值归类到相应的像素值区间(通常是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):
OpenCV书签 #直方图算法的原理与相似图片搜索实验,OpenCV,Python,算法,opencv,直方图算法,python,图搜索算法,相似图片搜索,以图搜图
示图代码:

"""
以图搜图:图像直方图(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,绘画出来的直方图灰度像素分布效果如下:
OpenCV书签 #直方图算法的原理与相似图片搜索实验,OpenCV,Python,算法,opencv,直方图算法,python,图搜索算法,相似图片搜索,以图搜图
可以看到,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] 单通道合成一张直方图:
OpenCV书签 #直方图算法的原理与相似图片搜索实验,OpenCV,Python,算法,opencv,直方图算法,python,图搜索算法,相似图片搜索,以图搜图
可以清楚看到,合成后的直方图,只剩下 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 cv2

def 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 = 0
    for 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 + 1
    degree = 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 os

def get_degreeHist(img1_hist, img2_hist):
    # 计算直方图的重合度
    degree = 0
    for 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 + 1
    degree = degree / len(img1_hist)
    return degree


def 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 os

def 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张图像为水果,其余为不同类型的汽车,但形态不一。
OpenCV书签 #直方图算法的原理与相似图片搜索实验,OpenCV,Python,算法,opencv,直方图算法,python,图搜索算法,相似图片搜索,以图搜图

实验代码

"""
以图搜图:图像直方图(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 plt

def 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 similarity

def 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 表示颜色分布越相似:
OpenCV书签 #直方图算法的原理与相似图片搜索实验,OpenCV,Python,算法,opencv,直方图算法,python,图搜索算法,相似图片搜索,以图搜图

输出打印:

目标图像:..\..\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书签 #直方图算法的原理与相似图片搜索实验文章来源地址https://www.toymoban.com/news/detail-817666.html

到了这里,关于OpenCV书签 #直方图算法的原理与相似图片搜索实验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于直方图相似性的图像分类算法FPGA实现,包括tb测试文件和MATLAB辅助验证

    目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 MATLAB测试结果: FPGA测试结果: 上述仿真图中,红色XX表示图像读取完毕。因此输出XX。当图像输出完成之后,最下面的相似性指标 same1输出为11226,same2输出为67584.即图1和图

    2024年04月09日
    浏览(43)
  • 【OpenCV学习笔记30】- OpenCV 中的直方图 - 直方图 - 4:直方图反投影

    这是对于 OpenCV 官方文档中 图像处理 的学习笔记。学习笔记中会记录官方给出的例子,也会给出自己根据官方的例子完成的更改代码,同样彩蛋的实现也会结合多个知识点一起实现一些小功能,来帮助我们对学会的知识点进行结合应用。 如果有喜欢我笔记的请麻烦帮我关注

    2024年03月26日
    浏览(55)
  • OpenCV10-图像直方图:直方图绘制、直方图归一化、直方图比较、直方图均衡化、直方图规定化、直方图反射投影

    图像直方图就是统计图像中每个灰度值的个数,之后将灰度值作为横轴,以灰度值个数或者灰度值所占比率作为纵轴的统计图。通过直方图,可以看出图像中哪些灰度值数目较多,哪些较少,可以通过一定的方法将灰度值较为集中的区域映射到较为稀疏的区域,从而使图像在

    2024年01月16日
    浏览(52)
  • 【OpenCV • c++】自定义直方图 | 灰度直方图均衡 | 彩色直方图均衡

      直方图广泛应用于很多计算机视觉处理当中。通过标记帧与帧之间显著的边缘和颜色的变化,可以检测视频中的场景变化。在每个兴趣点设置一个有相似特征的直方图所构成的“标签”,可以用来标记各种不同的事情,比如图像的色彩分布,物体边缘梯度模板等等。是计

    2024年02月08日
    浏览(52)
  • 【OpenCV • c++】直方图计算 | 绘制 H-S 直方图 | 绘制一维直方图 | 绘制 RGB 三色直方图

      直方图广泛应用于很多计算机视觉处理当中。通过标记帧与帧之间显著的边缘和颜色的变化,可以检测视频中的场景变化。在每个兴趣点设置一个有相似特征的直方图所构成的“标签”,可以用来标记各种不同的事情,比如图像的色彩分布,物体边缘梯度模板等等。是计

    2024年02月09日
    浏览(54)
  • Baumer工业相机堡盟工业相机如何联合BGAPISDK和OpenCV实现图像的直方图算法增强(C++)

    Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度可扩

    2024年02月01日
    浏览(96)
  • 【opencv】教程代码 —Histograms_Matching(2)计算直方图、直方图比较、直方图均衡、模板匹配...

    计算直方图 直方图比较 图像进行直方图均衡化处理 模板匹配 1. calcHist_Demo.cpp 计算直方图 这段代码的功能是加载图像,分离图像的三个颜色通道,然后分别计算这三个通道的直方图,绘制出来并显示结果。直方图是图像中像素值分布的图形表示,可以用于图像分析或图像处

    2024年04月11日
    浏览(51)
  • opencv-2D直方图

    cv2.calcHist() 是 OpenCV 中用于计算直方图的函数。它可以计算一维或多维直方图,用于分析图像中像素值的分布。 基本的语法如下: 参数说明: images : 输入图像, 可以是单通道或多通道图像 。在计算多通道图像的直方图时,要将通道分别传递给 channels 参数。 channels : 要考虑

    2024年02月20日
    浏览(40)
  • opencv直方图

    在OpenCV中,直方图是一个重要的图像分析工具,它可以提供关于图像亮度分布的详细信息。OpenCV提供了多种方法来计算和操作图像的直方图。 基本概念 直方图是一个离散函数,它将图像中的像素值映射到一个连续的区间上,并计算每个区间内像素的数量。对于灰度图像,直

    2024年04月28日
    浏览(41)
  • 【OpenCV--直方图】

    目录 一、直方图是什么? 1.描述: 2.相关术语: 二、直方图的计算和绘制 三、掩膜的应用 四、直方图均衡化: 五、自适应的直方图均衡化 1.描述: 1直方图是对数据进行统计的一种方法,并且将统计值组织到一系列实现定义好的bin(直条/组距)当中。bin的数值可以是梯度、方

    2024年02月05日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包