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

您所在的位置:网站首页 哈希相似度算法 OpenCV书签 #均值哈希算法的原理与相似图片搜索实验

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

2024-03-28 21:57| 来源: 网络整理| 查看: 265

1. 介绍

均值哈希算法(Average Hash Algorithm,简称aHash) 是哈希算法的一种,主要用来做相似图片的搜索工作。

 

2. 原理

均值哈希算法(aHash)首先将原图像缩小成一个固定大小的像素图像,然后将图像转换为灰度图像,通过缩小图像的每个像素与平均灰度值的比较,生成一组哈希值。最后,利用两组图像的哈希值的汉明距离来评估图像的相似度。

魔法: 概括地讲,均值哈希算法一共可细分六步:

缩小图像: 将目标图像缩小为一个固定的大小,通常为8x8像素,总共64个像素。作用是去除各种图像尺寸和图像比例的差异,只保留结构、明暗等基本信息,目的是确保图像的一致性,降低计算的复杂度。图像灰度化: 将缩小的图像转换为灰度图像。灰度平均值: 计算灰度图像的平均灰度值。减少计算量。比较平均值: 遍历灰度图像的每个像素,比较每个像素的灰度值是否大于或小于平均值。对于大于等于平均值的像素,将其表示为1,对于小于平均值的像素,将其表示为0。最后,得到一个64位的二进制值(8x8像素的图像)。生成哈希值: 由于64位二进制值太长,所以按每4个字符为1组,由2进制转成16进制。这样就转为一个长度为16的字符串。这个字符串也就是这个图像可识别的哈希值,也叫图像指纹,即这个图像所包含的特征。哈希值比较: 通过比较两个图像的哈希值的汉明距离(Hamming Distance),就可以评估图像的相似度,距离越小表示图像越相似。

 

3. 实验 第一步:缩小图像

将目标图像缩小为一个固定的大小,通常为8x8像素,总共64个像素。作用是去除各种图像尺寸和图像比例的差异,只保留结构、明暗等基本信息,目的是确保图像的一致性,降低计算的复杂度。

1)读取原图 # 测试图片路径 img_path = 'img_test/apple-01.jpg' # 通过OpenCV加载图像 img = cv2.imread(img_path) # 通道重排,从BGR转换为RGB img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

aHash-0001

2)缩小原图 # 缩小图像:使用OpenCV的resize函数将图像缩放为8x8像素,采用Cubic插值方法进行图像重采样 img_resize = cv2.resize(img, (8, 8), cv2.INTER_CUBIC)

aHash-0002 OpenCV 的 cv2.resize() 函数提供了4种插值方法,以根据图像的尺寸变化来进行图像重采样。

cv2.INTER_NEAREST: 最近邻插值,也称为最近邻算法。它简单地使用最接近目标像素的原始像素的值。虽然计算速度快,但可能导致图像质量下降。cv2.INTER_LINEAR: 双线性插值,通过对最近的4个像素进行线性加权来估计目标像素的值。比最近邻插值更精确,但计算成本略高。cv2.INTER_CUBIC: 双三次插值,使用16个最近像素的加权平均值来估计目标像素的值。通常情况下,这是一个不错的插值方法,适用于图像缩小。cv2.INTER_LANCZOS4: Lanczos插值,一种高质量的插值方法,使用Lanczos窗口函数。通常用于缩小图像,以保留图像中的细节和纹理。 第二步:图像灰度化

将缩小的图像转换为灰度图像。也就是说,所有像素点总共只有64种灰度颜色。

# 图像灰度化:将彩色图像转换为灰度图像。 img_gray = cv2.cvtColor(img_resize, cv2.COLOR_BGR2GRAY) print(f"缩放8x8的图像中每个像素的颜色=\n{img_gray}")

输出打印:

缩放8x8的图像中每个像素的颜色= [[253 253 253 253 253 253 253 253] [253 253 253 148 253 253 253 253] [253 253 253 215 178 253 253 253] [253 253 119 93 132 176 253 253] [253 253 61 61 53 130 253 253] [253 253 112 67 66 142 253 253] [253 253 252 54 54 253 253 253] [253 253 236 63 146 249 253 253]]

aHash-0003

第三步:灰度平均值

计算灰度图像的平均灰度值。减少计算量。

img_average = np.mean(img_gray) print(f"灰度图像中所有像素的平均值={img_average}")

输出打印:

灰度图像中所有像素的平均值=209.890625 第四步:比较平均值

遍历灰度图像的每个像素,比较每个像素的灰度值是否大于或小于平均值。对于大于等于平均值的像素,将其表示为1;对于小于平均值的像素,将其表示为0。最后,得到一组长64位的二进制字符串(8x8像素的图像)。因为对于机器而言,只认识0和1,所以这组64位的二进制就可以表示这张图像的结构和亮度分布。

# 遍历图像像素:嵌套循环遍历图像的所有像素,对比灰度图像的平均灰度值,转换为二进制的图像哈希值 img_hash_binary = [] for i in range(img_gray.shape[0]): for j in range(img_gray.shape[1]): if img_gray[i,j] >= img_average: img_hash_binary.append(1) else: img_hash_binary.append(0) print(f"对比灰度图像的平均像素值降噪(图像的二进制哈希值)数组={img_hash_binary}") # 将列表中的元素转换为字符串并连接起来,形成一组64位的图像二进制哈希值字符串 img_hash_binary_str = ''.join(map(str, img_hash_binary)) print(f"对比灰度图像的平均像素值降噪(图像的二进制哈希值)={img_hash_binary_str}")

代码分解和含义如下:

初始化空列表:创建一个空的列表 img_hash_binary,用于存储图像的哈希值。遍历图像像素:嵌套循环遍历图像的所有像素,其中 img_gray 是输入的灰度图像,img_gray.shape[0] 和 img_gray.shape[1] 分别表示图像的高度和宽度。计算平均值:代码中使用变量 img_average 存储了一个平均值,用于与图像像素的灰度值进行比较。根据亮度值生成哈希值:对于每个像素,代码比较像素的灰度值与平均值 (img_gray[i, j] >= img_average)。如果像素的灰度值大于或等于平均值,就将数字1添加到 img_hash_binary 列表中,表示该像素是亮的。如果像素的灰度值小于平均值,就将数字0添加到 img_hash_binary 列表中,表示该像素是暗的。最终哈希值:完成循环后,img_hash_binary 列表将包含图像的二进制哈希值,其中每个元素代表一个像素的明暗情况。

输出打印:

对比灰度图像的平均像素值降噪(图像的二进制形式)数组=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1] 对比灰度图像的平均像素值降噪(图像的二进制形式)=1111111111101111111101111100001111000011110000111110011111100111

或者,使用等价的 lambda 表达式。效果一样。

# lambda表达式 img_hash_binary_str = "" for i in range(8): img_hash_binary_str += ''.join(map(lambda i: '0' if i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3