Python OpenCV实现图像相似度计算的三种哈希算法详解

叶初
叶初
发布时间:2026-10-13| 4人浏览过
原创

本文详细解析利用Python和OpenCV计算图像相似度的多种方法。内容涵盖基于颜色直方图的对比,以及三种主流感知哈希算法:平均哈希(aHash)、感知哈希(pHash)和差值哈希(dHash)。通过具体代码示例,介绍如何获取图像指纹并计算汉明距离,以评估图片间的差异与相似度,适用于图像检索、去重及目标识别等场景。

引言与图像相似度概述

本文深入探讨使用Python结合OpenCV库进行图像相似度计算的技术实现。文中通过详细的代码示例,展示了从基础概念到具体算法的应用过程,为开发者在图像识别、检索或分类任务中提供具有实际参考价值的技术路径。

一、相关概念

人类在区分个体或给物品分类时,主要依赖各类显著特征,例如发型、身材比例、面部细节等。即便两个人外貌相似,细微的差别(如痣的位置)也能帮助准确辨识。对于物体,我们依据其结构特征(如桌子的腿、镜子的反光)进行归纳和识别。这种基于特征的学习与归纳能力,使人类能迅速对新物品进行分类。

相比之下,未经过专门训练或学习的机器无法直接具备这种直观的特征识别能力。

然而,图像本质上是由像素点构成的矩阵,我们可以通过分析不同图像间像素值的差异来量化它们的相似度。在众多特征中,颜色特征是最常用且有效的指标(其他常用特征还包括纹理、形状及空间关系等)。具体实现上,颜色特征的提取主要有以下几种方式:

  • 直方图
  • 颜色集
  • 颜色矩
  • 聚合向量
  • 相关图

基于直方图的图像相似度计算

1、直方图

在Python环境中,可以利用OpenCV库中的calcHist()函数来获取图像的直方图数据。该函数返回一个列表形式的统计数据。借助matplotlib库,可以将这两张图的直方图数据可视化绘制出来,以便直观对比。


import cv2
import numpy
from matplotlib import pyplot
if __name__ == '__main__':
  imgobj1 = cv2.imread('pho.jpg')
  imgobj2 = cv2.imread('ph1.jpg')
  hist1 = cv2.calcHist([imgobj1], [0], None, [256], [0.0, 255.0])
  hist2 = cv2.calcHist([imgobj2], [0], None, [256], [0.0, 255.0])
  pyplot.plot(range(256), hist1, 'r')
  pyplot.plot(range(256), hist2, 'b')
  pyplot.show()
  cv2.imshow('img1',imgobj1)
  cv2.imshow('img2',imgobj2)
  cv2.waitKey(0)

1.2 灰度图及作用

灰度图仅包含黑白两色信息,对应0至255的亮度等级。由于灰度图存储占用小,且其亮度值直接对应256色调色板的索引号,从整体和局部的色彩及亮度分布特征来看,灰度图所描述的信息与彩色图是一致的。因此,在许多真彩色图像的分析流程中,第一步通常是将图像转换为灰度图,再进行后续处理。

真彩色图像由于采用24位深度,颜色总数为2^8 * 2^8 * 2^8 = 16777216种,若使用调色板需占用16777216 * 4字节(即64MB)的空间,因此真彩色图像通常不使用调色板。

例如在视频目标跟踪和识别任务中,第一步往往也是将图像转换为灰度图。目前许多成熟的分析算法都是基于灰度图像设计的,因为灰度图像综合了真彩色位图中红、绿、蓝(RGB)各通道的信息。

(一):单通道图,

通常被称为灰度图。在单通道图中,每个像素点仅由一个数值表示颜色,该数值范围在0到255之间。其中,0代表黑色,255代表白色,中间的数值表示不同等级的灰色。(注:也存在3通道的灰度图,但其特点是一个通道有数值,其余两个通道数值均为零)。

(二):三通道图,每个像素点由3个数值表示,因此称为3通道。此外还有4通道的图像格式。例如常见的RGB图片即为三通道图像。RGB色彩模式是工业界广泛采用的颜色标准,它通过红(R)、绿(G)、蓝(B)三个颜色通道的变化及其相互叠加来生成各种颜色。RGB标准几乎涵盖了人类视力所能感知的所有颜色,是目前应用最广泛的颜色系统之一。总之,每个像素点由三个值共同表示。

利用直方图判断相似度时,主要观察两张图直方图的重合程度即可。

图像指纹与汉明距离原理

1.3 图像指纹和汉明距离

图像指纹:

类似于人的指纹,图像指纹是图像身份的唯一象征。简单来说,图像指纹是将图像通过特定的哈希算法进行运算后,得到的一组二进制数字序列。

汉明距离:

假设有两组二进制数据,一组为101,另一组为111。要将第一组变为第二组,只需将第二位的0改为1,因此这两组数据的汉明距离为1。

简而言之,汉明距离是指将一组二进制数据转换为另一组数据所需改变的位数。该数值可用于衡量两张图片的差异:汉明距离越小,代表相似度越高;若汉明距离为0,则表明两张图片完全一致。

平均哈希(aHash)算法实现

1.3.1 平均哈希

该算法通过比较灰度图中每个像素值与图像平均像素值来实现。

一般步骤:

  • 缩放图片,通常将图像大小调整为8*8像素,共64个像素值。
  • 转化为灰度图
  • 计算平均值:计算经过灰度处理后的图片所有像素点的平均值,可直接使用numpy库中的mean()函数进行计算。
  • 比较像素灰度值:遍历灰度图像的每一个像素,如果像素值大于平均值,则记录为1,否则记录为0。
  • 得到信息指纹:将64个比特位组合起来,顺序需保持一致性。
  • 最后,通过比对两张图片生成的指纹,计算并获取汉明距离。

import cv2
import numpy as np

img1 = cv2.imread("/absPath.png")
img2 = cv2.imread("./x.png")

#调整到8*8
img1 = cv2.resize(img1,(8,8))
img2 = cv2.resize(img2,(8,8))

#转化为灰度图
gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

#获取哈希
hash1 = getHash(gray1)
hash2 = getHash(gray2)

ret = Hamming_distance(hash1,hash2)


# 输入灰度图,返回hash
def getHash(image):
  avreage = np.mean(image) #计算像素平均值
  hash = []
  for i in range(image.shape[0]):
    for j in range(image.shape[1]):
      if image[i, j] > avreage:
        hash.append(1)
      else:
        hash.append(0)
  return hash
# 计算汉明距离
def Hamming_distance(hash1, hash2):
  num = 0
  for index in range(len(hash1)):
    if hash1[index] != hash2[index]:
      num += 1
  return num

感知哈希(pHash)算法实现

1.3.2 感知哈希及d哈希

感知哈希算法(pHash)

平均哈希算法(aHash)要求较为严格,精度相对不足,更适合用于缩略图的快速搜索。为了获得更精确的匹配结果,可以选择感知哈希算法,它采用离散余弦变换(DCT)来降低频率分量。

一般步骤:

  • 缩小图片:将图像尺寸调整为32 * 32像素,这是一个较为适宜DCT计算的大小。
  • 转化为灰度图
  • 计算DCT:利用OpenCV提供的dct()方法,注意输入图像必须转换为32位浮点型,因此需先利用numpy中的float32进行类型转换。
  • 缩小DCT:DCT计算后的矩阵尺寸为32 * 32,我们仅保留左上角的8 * 8区域,这些区域代表了图像的最低频率信息。
  • 计算平均值:计算缩小后的DCT矩阵中所有像素点的平均值。
  • 进一步减小DCT:若像素值大于平均值,记录为1,反之记录为0。
  • 得到信息指纹:将64个信息位组合起来,顺序需保持一致性。
  • 最后,通过比对两张图片的指纹,计算并获取汉明距离。

差值哈希(dHash)算法实现

dHash算法

与pHash相比,dHash的计算速度更快;与aHash相比,在效率相近的情况下,dHash的效果更佳。dHash是基于像素渐变实现的。

步骤:

缩小图片:将图像收缩至9*8像素大小,以便获得72个像素点。

转化为灰度图

计算差异值:dHash算法作用于相邻像素之间。每行9个像素产生8个差异值,共8行,总计产生64个差异值。 获得指纹:如果左侧像素比右侧像素更亮,则记录为1,否则记录为0。 最后,通过比对两张图片的指纹,计算并获取汉明距离。

dHash:


#差值感知算法
def dhash(image1,image2):
  image1 = cv2.resize(image1,(9,8))
  image2 = cv2.resize(image2,(9,8))
  gray1 = cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY) #切换至灰度图
  gray2 = cv2.cvtColor(image2,cv2.COLOR_BGR2GRAY)
  hash1 = dhashcaulate(gray1)
  hash2 = dhashcaulate(gray2)
  return Hamming_distance(hash1,hash2)
 
def dhashcaulate(gray):
  hash_str = ''
  for i in range(8):
    for j in range(8):
      if gray[i, j] > gray[i, j + 1]:
        hash_str = hash_str + '1'
      else:
        hash_str = hash_str + '0'
  return hash_str

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。