图片相似度方法

图像相似度方法调研

date: 2022-03-22

一、测试数据

  1. 五组相互对应相似图片
  2. 五组相互部分相似图片
  3. 五组相互不相似图片

二、可用算法

算法名称计算距离方法度量规则优缺点
感知哈希(pHash)汉明距离[0,10]汉明距离越小图片越相似效率较低,但误报率在哈希方法中最低
差异哈希(dHash)汉明距离[0,10]汉明距离越小图片越相似效率较高,误报率比phash方法高
余弦距离(cosin)余弦距离[0,1]图片越相似,余弦值越接近1算法简单,效率较慢,准确率不错
结构相似度(ssim)ssim[0,1]图片越相似,值越接近1大多用于考量同一张图片的失真率

三、算法步骤

  1. 感知哈希(pHash)

    1.缩放图片:图片缩放为32*32,利于DCT(离散余弦变换)计算;

    2.灰化:将图片转化为256阶灰度图;

    3.计算DCT:DCT把图片分离成分率的集合;

    4.缩小DCT:DCT计算后的矩阵是3 *32,保留左上角的8 * 8,代表图片最低频率;

    5.计算平均值:计算缩小DCT后的所有像素点的平均值;

    6.比较平均值:大于平均值记录为1,反之记录为0,得到phash值;

  2. 差异哈希(dHash)

    1.图片缩放为9*8,保留结构;

    2.灰化:将图片转化为256阶灰度图;

    3.求平均值:计算灰度图所有像素的平均值;

    4.比较:像素值大于后一个像素记作1,相反记作0;

    5.生成哈希值;

  3. 余弦距离(cosin)

    1.图片处理:将图片设置为统一大小如64*64

    2.灰化:将图片转化为灰度图

    3.计算图片的余弦相似度

  4. 结构相似度(ssim)

    1.图片滑窗:将图形分块,方块数为N;

    2.计算计算窗口均值、方差以及协方差;

    3.计算对应块的结构相似度;

    4.计算全图结构相似度:将对应块结构相似度求平均值;

四、算法结果比较

  1. 相似图片对比结果
算法名称度量规则结果运行时间
感知哈希(pHash)[0,10]汉明距离越小图片越相似[0.87, 0.90, 0.96, 0.90, 0.81]0.9s
差异哈希(dHash)[0,10]汉明距离越小图片越相似[0.78, 0.93, 0.96, 0.95, 0.85]0.9s
余弦距离(cosin)[0,1]图片越相似,余弦值越接近1[0.9,0.87,0.85,0.94,0.76 ]1.2s
结构相似度(ssim)[0,1]图片越相似,值越接近1[0.68, 0.50, 0.69, 0.50, 0.57]1.4s
  1. 部分相似图片对比结果
算法名称度量规则结果运行时间
感知哈希(pHash)[0,10]汉明距离越小图片越相似[0.81, 0.781, 0.85, 0.56, 0.53]0.6s
差异哈希(dHash)[0,10]汉明距离越小图片越相似[0.82, 0.84, 0.85, 0.625, 0.51]0.1s
余弦距离(cosin)[0,1]图片越相似,余弦值越接近1[0.675,0.737,0.685,0.537,0.76 ]0.7s
结构相似度(ssim)[0,1]图片越相似,值越接近1[0.34, 0.40, 0.405, 0.45, 0.38]0.2s
  1. 不相似图片对比结果
算法名称度量规则结果运行时间
感知哈希(pHash)[0,10]汉明距离越小图片越相似[0.562, 0.531, 0.562, 0.468, 0.468]0.6 s
差异哈希(dHash)[0,10]汉明距离越小图片越相似[0.43, 0.45, 0.57, 0.59, 0.546]0.2 s
余弦距离(cosin)[0,1]图片越相似,余弦值越接近1[0.412,0.327,0.57,0.317,0.488 ]0.7 s
结构相似度(ssim)[0,1]图片越相似,值越接近1[0.23, 0.52, 0.53, 0.32, 0.44]0.6s

五、算法代码示例

python代码示例:

 ###读取文件名
def file_name(file_dir):
    file_name = []
    file_dan = []
    file_shuang = []
    for root,dirs,files in os.walk(file_dir):
        file_name.append(files) 
    file_dan.append(file_name[1])
    file_shuang.append(file_name[2])
    return file_dan[0],file_shuang[0]

def image_similar_dhash(file_dir):
    '''
    dhash
    '''
    start = datetime.datetime.now()
    list_1,list_2 = file_name(file_dir)
    hash_dan = []
    hash_shuang  = []
    for i in list_1:
        figuredan_path = file_dir + 'one/'+i
        hash1 = dhash(Image.open(figuredan_path))
        hash_dan.append(hash1)
    for j in list_2:
        figures_path = file_dir +'two/' + j
        hash2 = dhash(Image.open(figures_path))
        hash_shuang.append(hash2)
    image_similar_dhash = list(map(lambda x : 1 - (x[0] - x[1]) / len(x[0].hash) ** 2,zip(hash_dan,hash_shuang)))
    end = datetime.datetime.now()
    run_time = end - start
    return image_similar_dhash,run_time


def image_similar_phash(file_dir):
    '''
    dhash
    '''
    start = datetime.datetime.now()
    list_1,list_2 = file_name(file_dir)
    hash_dan = []
    hash_shuang  = []
    for i in list_1:
        figuredan_path = file_dir + 'one/'+i
        hash1 = phash(Image.open(figuredan_path))
        hash_dan.append(hash1)
    for j in list_2:
        figures_path = file_dir +'two/' + j
        hash2 = phash(Image.open(figures_path))
        hash_shuang.append(hash2)
    image_similar_phash = list(map(lambda x : 1 - (x[0] - x[1]) / len(x[0].hash) ** 2,zip(hash_dan,hash_shuang)))
    end = datetime.datetime.now()
    run_time = end - start
    return image_similar_phash,run_time

def get_thum(img,size=(64,64),greyscale = False):
    '''
    图片变灰度
    '''
    im = Image.open(img)
    image = im.resize(size,Image.ANTIALIAS)
    if greyscale:
        image = image.convert('L')
    return image
def image_similar_cosin(file_dir):
    list_1,list_2 = file_name(file_dir)
    image_dan = []
    image_shuang = []
    result = []
    for i in list_1:
       figuredan_path = file_dir + 'one/'+ i 
       image1 = get_thum(figuredan_path)
       image_dan.append(image1)
    for j in list_2:
       figureshuang_path = file_dir + 'two/'+ j 
       image2 = get_thum(figureshuang_path)
       image_shuang.append(image2)
       image_list = list(map(lambda x : [x[0],x[1]] ,zip(image_dan,image_shuang))) 
    vectors = []
    norms = []
    for q in image_list[0]:###进入每个list[figure1,fiure2]\
        for pixel_tuple in q.getdata():
            vector = []
            vector.append(average(pixel_tuple))
        vectors.append(vector)
        norms.append(linalg.norm(vector,2))
    a,b = vectors
    a_norm,b_norm  = norms
    result = dot(a / a_norm , b / b_norm)
    return result

###ssim
import cv2
from skimage.measure import compare_ssim
def image_similar_ssim(file_dir):
    list_1,list_2 = file_name(file_dir)
    image_dan = []
    image_shuang = [] 
    shape_dan = []
    for i in list_1:
        figuredan_path = file_dir + 'one/'+ i
        image1 = cv2.imread(figuredan_path)
        image_dan.append(image1)
    for j in image_dan:
        shape_dan.append((j.shape[1],j.shape[0]))
    for q in list_2:
        figures_path = file_dir + 'two/' + q
        image2 = cv2.imread(figures_path)
        image_shuang.append(image2)
    v = list(map(lambda x : cv2.resize(x[0],x[1]),zip(image_shuang,shape_dan)))   
    res = list(map(lambda x : compare_ssim(x[0],x[1],full =False,multichannel=True),zip(image_dan,v) ))
    return res

扩展:基于直方图方法及PSNR方法

  1. 基于直方图方法:能描述一副图像中的颜色全局分布,但过于简单,捕捉不到更多的信息,只要颜色分布相似就判断为两张图片相似度较高。

    相似图片相似度:0.68 运行时间:0.4s;

    部分相似图片相似度:0.65 运行时间:0.5s;

    不相似图片相似度:0.52 运行时间:0.7;

  2. PSNR:峰值信噪比,基于对应像素点间误差的图像评价指标,但未考虑人眼对空间频率较低的对比差异敏感度较高的特性,且该方法多用于评价一张图片的失真情况。PSNR接近 50dB ,代表压缩后的图像仅有些许非常小的误差。PSNR介于 10dB 到 20dB 之间,人眼还是可以用肉眼看出这个图像原始的结构,且直观上会判断两张图像不存在很大的差异。

    相似图片相似度:17.38d 运行时间:0.5s

    部分相似图片相似度:12.49d 运行时间:0.5s

    不相似图片相似度:10.39d 运行时间:0.1s

六、总结

上述四种方法中,推荐使用差异哈希(dHash)方法,该方法在保证推理速度较高的同时能保证误报率低。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值