判断图像近似度:使用汉明距离计算

判断图像近似度:使用汉明距离计算

汉明距离表示两个(相同长度)字符串对应位置的不同字符的数量。用于编码,简单来说,判断两个序列是否相似,则判断是否有不同的位数。举例:

A = [0, 0, 1, 0]
B = [0, 1, 1, 0]

AB 有一位不同,汉明距离为 1。

又比如:

A = [3,1,4,1,5,9]
B = [2,7,1,8,2,8]

每个对应位置上的元素都完全不一样,汉明距离为 6。

用汉明距离计算图片相似度的过程

  1. 缩小图片尺寸,例如缩小成 888*8 个像素的大小
  2. 对每个像素简化色彩,也就是把图像变灰,这样保留图片整体的结构明暗度,去除细节。最后会得到一个 64 个灰度值的串。
  3. 计算64个灰度值的平均值(差异哈希由于计算了差异值所以 不需要)。
  4. 对于每个灰度值,与平均值进行比较。大于等于平均值记为 1;小于平均值记为 0。
  5. 比较哈希值(也就是汉明距离)。

在实际实施算法时,有三种哈希算法,用于判断图像近似度:A,D 和 P
A 指的是平均:average
D 指的是差异:diff
P 是指感知:perceptual
最推荐的是 D 也就是差异哈希,A 仅计算平均值,误差很大。P 虽然更精确但是计算速度过慢。D 由于算的是差值,因此是基于渐变的实现。

计算灰度值的方法

R 是 red,G 是 green,B 是 blue,分别代表 rgb 图像中的三原色

浮点算法:R0.3+G0.59+B0.11R*0.3+G*0.59+B*0.11
整数方法:(R30+G59+B11)/100(R*30+G*59+B*11) /100
移位:(R76+G151+B28)>>8(R*76+G*151+B*28) >>8
平均值方法:(R+G+B)/3(R+G+B)/3
仅取绿色方法方法:GG

平均哈希(A)

  1. 缩小图片尺寸,例如缩小成 888*8 个像素的大小
  2. 对每个像素简化色彩,把图像变灰。
  3. 计算64个灰度值的平均值。
  4. 对于每个灰度值,与平均值进行比较。大于等于平均值记为 1;小于平均值记为 0。
  5. 比较哈希值(也就是汉明距离)。
from skimage import transform
import cv2

#aHash方法计算图片的指纹数据

img=cv2.imread('/Users/myname/Desktop/test/d.jpg')#读入图片
length = 8
height = 8
sum = 0.0
k = 0
grey = []
## 修改图像大小
dst=transform.resize(img, (length, height))

for i in range(length):
    for j in range(height):
        (b,g,r) = dst[i,j]
        # 计算灰度值
        grey.append(r*0.3+g*0.59+b*0.11)#浮点灰度值计算
        sum+=grey[k]
        k=k+1
average = sum/(length*height)#算出平均的灰度数据
fingerprint = []

for i in range(length*height):
    if grey[i] > average:
        fingerprint.append(1)#如果灰度数据大于平均值,填入元素1,否则填入元素0
    else:
        fingerprint.append(0)

print(fingerprint)

差异哈希(D)

基于渐变实现的差异算法,速度快。

  1. 缩小图片至 8 行 9 列,为什么是 8 和 9?因为在第三步要计算差值来获取 64 位编码。
  2. 转灰度图
  3. 计算差异值:每行相邻像素之间计算差值,这样就变成918=64(9-1)*8=64
  4. 根据差异值:获取 01 值,差异值为正数的,为1,否则为0。
from skimage import transform,data
import matplotlib.pyplot as plt
from skimage import io
import cv2
img=cv2.imread('/Users/myname/Desktop/test/d.jpg')#读入图片
length = 9
height = 8
sum = 0.0
k = 0
grey = []
dst=transform.resize(img, (length, height))
#灰度图转化
for i in range(length):
    for j in range(height):
        (b,g,r) = dst[i,j]
        grey.append(r*0.3+g*0.59+b*0.11)#浮点灰度值计算
        sum+=grey[k]
        k=k+1
## 获取每行的差值,为64位
differ = []
for i in range(length-1):#i 8
    for j in range(height):#j 8
        differ.append(grey[j*8+i+1]-grey[j*8+i])
#获取01值
fingerprint = []
for i in range((length-1)*height):#8*8
    if differ[i] > 0:
        fingerprint.append(1)
    else:
        fingerprint.append(0)

#print(fingerprint)

感知哈希(P)

对图像生成一个字符串代表他的“指纹”。通过比对“指纹”来比较图像的相似性。

缩小时建议 32*32,方便 DCT 计算:

  1. 转灰度图
  2. 计算 DCT
  3. 缩小 DCT,保留左上角 8*8 的像素。
  4. 计算平均值
  5. 判断各点,大于等于平均值为 1,小于为 0
  6. 得到 64 个信息位
import cv2
from skimage import transform
import numpy as np
#利用phash计算图像指纹
img=cv2.imread('/Users/myname/Desktop/test/d.jpg')#读入图片

length = 32
s_length = 8

dst=transform.resize(img, (length, length))
#print(type(dst))

#all 代表全图,建议32*32
matrix_all_grey = [[0 for i in range(length)] for i in range(length)]
#small 代表最低频率,8*8大小
matrix_small_grey = [[0 for i in range(s_length)] for i in range(s_length)]

## 灰度图转化
k = 0
for i in range(length):
    for j in range(length):
        (b,g,r) = dst[i,j]
        matrix_all_grey[i][j] = ( b + g + r )/3
## 缩小
fft_matrix_grey = np.fft.fft(matrix_all_grey)
for i in range(s_length):
    for j in range(s_length):
        matrix_small_grey[i][j] = fft_matrix_grey[i][j]
## 计算平均
sum_pixel = 0
for i in range(s_length):
    for j in range(s_length):
        sum_pixel += matrix_small_grey[i][j]
average = sum_pixel / (s_length*s_length)

bite = []

#赋予01值
for i in range(s_length):
    for j in range(s_length):
        if matrix_small_grey[i][j] > average :
            bite.append(1)
        else:
            bite.append(0)
print(bite)

判断图像近似度:使用汉明距离计算