基于平均哈希算法(aHash)+汉明距离的相似图片识别方案

# demo示例

import
cv2 import numpy as np from PIL import Image # 计算平均哈希值 def ahash(image): # 缩放为8*8 image = cv2.resize(image, (8, 8), interpolation=cv2.INTER_CUBIC) # 转换为灰度图像 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 计算像素平均值 avg = gray.mean() # 二值化 hash = (gray > avg).astype(np.uint8) # 转换为整数 hash = hash.flatten().tolist() hash = int(''.join(map(str, hash)), 2) return hash # 计算汉明距离 def hamming_distance(hash1, hash2): return bin(hash1 ^ hash2).count('1') # 加载图像 img1 = cv2.imread('image1.jpg') img2 = cv2.imread('image2.jpg') # 计算哈希值 hash1 = ahash(img1) hash2 = ahash(img2) # 计算汉明距离 distance = hamming_distance(hash1, hash2) # 判断相似度 if distance <= 5: print('两张图片相似') else: print('两张图片不相似')

 

上述代码中,首先定义了一个计算平均哈希值的函数ahash(),该函数将图像缩放为8*8大小,转换为灰度图像,计算像素平均值,然后进行二值化,最后将二进制码转换为整数。然后,定义了一个计算汉明距离的函数hamming_distance(),该函数使用异或运算和计数函数实现。最后,加载两张图像,计算哈希值和汉明距离,根据距离判断两张图像是否相似。
需要注意的是,平均哈希算法和汉明距离虽然简单,但是对图像的旋转、缩放、裁剪等变换不太敏感,可能会导致误判。因此,在实际应用中,需要根据具体情况选择合适的相似度计算方法,以提高准确性和鲁棒性。

 

实际图片是url格式的链接,需要从url里面读取图片,这里参考博客:https://blog.csdn.net/xuezhangjun0121/article/details/120451534

用PIL+requests读取

import requests as req
from PIL import Image
from io import BytesIO

url = "https://img14.360buyimg.com/pop/jfs/t1/22587/13/20118/88676/63749dabE14cae977/7894c80d44c5d336.jpg"

response = req.get(url)
image = Image.open(BytesIO(response.content))
image.show()

 

但是此时image虽然读取了,并不能直接丢进上面定义的ahash()函数去计算,因为

img1 = cv2.imread('Wechat1.jpeg')

response = req.get(url)
image = Image.open(BytesIO(response.content))
这两种方法读取的图片格式是不同的。

1.cv2.imread()函数读取的图像格式是numpy数组,其中每个元素表示图像中的一个像素。numpy数组的形状是(height, width, channels),其中height表示图像的高度,width表示图像的宽度,channels表示图像的通道数,通常是3(表示RGB颜色空间)或1(表示灰度颜色空间)。

 

2.PIL库中的Image.open()函数读取的图像格式是PIL库中的Image对象,其中包含了图像的各种属性和方法。Image对象可以使用numpy库中的frombuffer()函数将其转换为numpy数组,也可以使用PIL库中的save()函数将其保存为图像文件。

 

需要注意的是,cv2.imread()函数读取的图像格式是BGR格式,而不是RGB格式。因此,在使用cv2.imread()函数读取图像后,需要使用cv2.cvtColor()函数将图像从BGR格式转换为RGB格式,才能正确地显示图像。

PIL库中的Image.open()函数读取的图像格式是RGB格式,因此不需要进行额外的转换。

 

那么如何将Image图像转换成cv2.imread()读取的格式呢?

可以使用numpy库中的asarray()函数将PIL库中的Image对象转换为numpy数组,然后使用cv2.cvtColor()函数将图像从RGB格式转换为BGR格式,最后使用cv2.imwrite()函数将图像保存为文件。

import requests
from io import BytesIO
import numpy as np
from PIL import Image
import cv2

# 读取图像数据
url = 'https://img14.360buyimg.com/pop/jfs/t1/22587/13/20118/88676/63749dabE14cae977/7894c80d44c5d336.jpg'
response = requests.get(url)
image = Image.open(BytesIO(response.content))

# 将图像数据转换为numpy数组
img_array = np.asarray(image)

# 将图像从RGB格式转换为BGR格式
img = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)

# 保存图像
cv2.imwrite('image.jpg', img)

 

 

np.asarray(image)和img_array = np.frombuffer(image.tobytes(), dtype=np.uint8) 有什么区别?

1.np.asarray(image)img_array = np.frombuffer(image.tobytes(), dtype=np.uint8)这两种方法都可以将PIL库中的Image对象转换为numpy数组,但是它们的实现方式是不同的。

2.np.asarray(image)函数将PIL库中的Image对象转换为numpy数组,其中每个元素表示图像中的一个像素。numpy数组的形状是(height, width, channels),其中height表示图像的高度,width表示图像的宽度,channels表示图像的通道数,通常是3(表示RGB颜色空间)或1(表示灰度颜色空间)。np.asarray()函数会自动根据图像的类型(RGB或灰度)创建相应的numpy数组。

3.image.tobytes()函数将PIL库中的Image对象转换为字节串,其中每个字节表示图像中的一个像素。np.frombuffer()函数将字节串转换为numpy数组,其中每个元素表示一个字节。np.frombuffer()函数需要指定数组的数据类型,通常是np.uint8(表示无符号8位整数)。

4.需要注意的是,np.asarray()函数和np.frombuffer()函数的返回值都是numpy数组,但是它们的形状和数据类型可能不同。np.asarray()函数返回的数组形状是(height, width, channels),数据类型是np.uint8np.uint16,而np.frombuffer()函数返回的数组形状是(height * width * channels,),数据类型是np.uint8

5.总之,这两种方法都可以将PIL库中的Image对象转换为numpy数组,需要根据具体的应用场景选择合适的方法。如果需要保留图像的形状和数据类型,则可以使用np.asarray()函数;如果只需要获取图像的字节串,则可以使用image.tobytes()函数;如果需要将字节串转换为numpy数组,则可以使用np.frombuffer()函数。

 

posted @ 2023-04-25 17:11  阿井井w  阅读(173)  评论(0编辑  收藏  举报