一.利用直方图距离计算图片相似度
计算公式:
其中,G和S为两张图片的图像颜色分布直方图,N为颜色空间样点数。这里使用分块的方法计算相似度,用以提高各部分的特征,防止图片颜色相似导致计算的相似度高。
import matplotlib.pyplot as plt
# 正则化图像
def regularizeImage(img, size = (256, 256)):
return img.resize(size).convert('RGB')
# 画出直方图图像
def drawHistogram(hg1, hg2):
plt.plot(range(len(hg1)), hg1, color='blue', linewidth=1.5, label='img1')
plt.plot(range(len(hg2)), hg2, color='red', linewidth=1.5, label='img2')
plt.legend(loc='upper left')
plt.title('Histogram Similarity')
plt.show()
# 分块图像4x4
def splitImage(img, part_size = (64, 64)):
w, h = img.size
pw, ph = part_size
data = []
for i in range(0, w, pw):
for j in range(0, h, ph):
data.append(img.crop((i, j, i + pw, j + ph)).copy())
return data
# 利用单块图片的直方图距离计算相似度
def calSingleHistogramSimilarity(hg1, hg2):
if len(hg1) != len(hg2):
raise Exception('样本点个数不一样')
sum = 0
for x1, x2 in zip(hg1, hg2):
if x1 != x2:
sum += 1 - float(abs(x1 - x2) / max(x1, x2))
else:
sum += 1
return sum / len(hg1)
# 利用分块图片的直方图距离计算相似度
def calMultipleHistogramSimilarity(img1, img2):
answer = 0
for sub_img1, sub_img2 in zip(splitImage(img1), splitImage(img2)):
answer += calSingleHistogramSimilarity(sub_img1.histogram(), sub_img2.histogram())
return float(answer / 16.0)
—————————————————————————————————————————————————————————————————
二.利用平均哈希算法计算图片相似度
计算步骤:
1.缩放图片:一般大小为8*8,64个像素值
2.简化色彩,转化为灰度图:可以使用Image的convert('L')方法
3.计算平均值:计算出灰度图所有像素点的像素值的平均值
4.比较像素灰度值:遍历灰度图的每一个像素值与上一步计算的平均值,大于平均值记录为1,否则为0
5.得到64位图像指纹
6.记录两张图片的图像指纹的汉明距离,计算图片相似度
# 正则化图像
def regularizeImage(img, size = (8, 8)):
return img.resize(size).convert('L')
# 计算hash值
def getHashCode(img, size = (8, 8)):
pixel = []
for i in range(size[0]):
for j in range(size[1]):
pixel.append(img.getpixel((i, j)))
mean = sum(pixel) / len(pixel)
result = []
for i in pixel:
if i > mean:
result.append(1)
else:
result.append(0)
return result
# 比较hash值
def compHashCode(hc1, hc2):
cnt = 0
for i, j in zip(hc1, hc2):
if i == j:
cnt += 1
return cnt
# 计算平均哈希算法相似度
def calaHashSimilarity(img1, img2):
img1 = regularizeImage(img1)
img2 = regularizeImage(img2)
hc1 = getHashCode(img1)
hc2 = getHashCode(img2)
return compHashCode(hc1, hc2)
__all__ = ['calaHashSimilarity']
—————————————————————————————————————————————————————————————————
三.利用感知哈希算法计算图片相似度
计算步骤:
3.1 缩放图片:一般大小为32*32,这样方便DCT计算
3.2 简化色彩,转化为灰度图:可以使用Image的convert('L')方法
3.3 计算DCT【离散余弦变换】
3.3.1 获得图像的二维数据矩阵f(x,y)
3.3.2 求离散余弦变换的系数矩阵[A]
3.3.3 求系数矩阵对应的转置矩阵[A]T
3.3.4 根据公式[F(u,v)]=[A][f(x,y)][A]T 计算离散余弦变换
3.4 缩小DCT:DCT计算后的矩阵是3232,保留左上角的88,这些代表的图片的最低频率
3.5 计算平均值:计算缩小DCT后的所有像素点的平均
3.6 进一步减小DCT:大于平均值记录为1,否则为0
3.7 得到64位信息指纹
3.8 记录两张图片的图像指纹的汉明距离,计算图片相似度
import math
import unittest
# 正则化图像
def regularizeImage(img, size = (32, 32)):
return img.resize(size).convert('L')
# 获得图像像素矩阵
def getMatrix(img):
matrix = []
size = img.size
for i in range(size[1]):
pixel = []
for j in range(size[0]):
pixel.append(img.getpixel((j, i)))
matrix.append(pixel)
return matrix
# 计算系数矩阵
def getCoefficient(length):
matrix = []
sqr = 1.0 / math.sqrt(length)
value = []
for i in range(length):
value.append(sqr)
matrix.append(value)
for i in range(1, length):
value = []
for j in range(0, length):
value.append(math.sqrt(2.0 / length) * math.cos(i * math.pi * (j + 0.5) / length))
matrix.append(value)
return matrix
# 计算矩阵转秩
def getTranspose(matrix):
new_matrix = []
for i in range(len(matrix)):
value = []
for j in range(len(matrix[i])):
value.append(matrix[j][i])
new_matrix.append(value)
return new_matrix
# 计算矩阵乘法
def getMultiply(matrix1, matrix2):
new_matrix = []
for i in range(len(matrix1)):
value = []
for j in range(len(matrix2[i])):
ans = 0.0
for h in range(len(matrix1[i])):
ans += matrix1[i][h] * matrix2[h][j]
value.append(ans)
new_matrix.append(value)
return new_matrix
# 计算DCT
def DCT(matrix):
length = len(matrix)
A = getCoefficient(length)
AT = getTranspose(A)
temp = getMultiply(A, matrix)
DCT_matrix = getMultiply(matrix, AT)
return DCT_matrix
# 计算左上角8*8并转化为list
def submatrix_list(matrix, size = (8, 8)):
value = []
for i in range(size[0]):
for j in range(size[1]):
value.append(matrix[i][j])
return value
# 计算hash值
def getHashCode(sub_list):
length = len(sub_list)
mean = sum(sub_list) / length
result = []
for i in sub_list:
if i > mean:
result.append(1)
else:
result.append(0)
return result
# 比较hash值
def compHashCode(hc1, hc2):
cnt = 0
for i, j in zip(hc1, hc2):
if i == j:
cnt += 1
return cnt
# 计算感知哈希算法相似度
def calpHashSimilarity(img1, img2):
img1 = regularizeImage(img1)
img2 = regularizeImage(img2)
matrix1 = getMatrix(img1)
matrix2 = getMatrix(img2)
DCT1 = DCT(matrix1)
DCT2 = DCT(matrix2)
sub_list1 = submatrix_list(DCT1)
sub_list2 = submatrix_list(DCT2)
hc1 = getHashCode(sub_list1)
hc2 = getHashCode(sub_list2)
return compHashCode(hc1, hc2)
# 单元测试
class TestpHash(unittest.TestCase):
def test_getHashCode(self):
self.assertEqual(getHashCode([1, 2, 3]), [0, 0, 1])
if __name__ == '__main__':
unittest.main()
__all__ = ['calpHashSimilarity']
—————————————————————————————————————————————————————————————————
四.利用差异哈希算法计算图片相似度
计算步骤:
4.1 缩放图片:一般大小为9*8,以留下多一行的像素数据进行差异计算
4.2 简化色彩,转化为灰度图:可以使用Image的convert('L')方法
4.3 计算差异值:dHash算法工作在相邻像素之间,这样每行9个像素之间产生了8个不同的差异,一共8行,则产生了64个差异哈希值
4.4 得到64位信息指纹:如果左边的像素比右边的更亮,则记录为1,否则为0
4.5 记录两张图片的图像指纹的汉明距离,计算图片相似度
# 正则化图像
def regularizeImage(img, size = (9, 8)):
return img.resize(size).convert('L')
# 计算hash值
def getHashCode(img, size = (9, 8)):
result = []
for i in range(size[0] - 1):
for j in range(size[1]):
current_val = img.getpixel((i, j))
next_val = img.getpixel((i + 1, j))
if current_val > next_val:
result.append(1)
else:
result.append(0)
return result
# 比较hash值
def compHashCode(hc1, hc2):
cnt = 0
for i, j in zip(hc1, hc2):
if i == j:
cnt += 1
return cnt
# 计算差异哈希算法相似度
def caldHashSimilarity(img1, img2):
img1 = regularizeImage(img1)
img2 = regularizeImage(img2)
hc1 = getHashCode(img1)
hc2 = getHashCode(img2)
return compHashCode(hc1, hc2)
__all__ = ['caldHashSimilarity']
转自另一位大佬,忘记地址了