哈希相似度算法(Hash algorithm)

用一个快速算法,就达到基本的效果。哈希算法(Hash algorithm),它的作用是对每张图片生成一个固定位数的Hash 值(指纹 fingerprint)字符串,然后比较不同图片的指纹,结果越接近,就说明图片越相似。一般有如下三种生成Hash 值方法:
差值DHash

  • 缩小尺寸:将图片缩小到8x9的尺寸,总共72个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。
  • 简化色彩:将缩小后的图片,转为64级灰度(或者256级也行)。
  • 计算平均值:计算所有64个像素的灰度平均值。
  • 比较:同行相邻间对比,像素值大于后一个像素值记作1,相反记作0。每行9个像素,8个差值,有8行共64位
  • 计算哈希值:将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。

均值AHash

  • 缩小尺寸:将图片缩小到8x8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。
  • 简化色彩:将缩小后的图片,转为64级灰度。
  • 计算平均值:计算所有64个像素的灰度平均值。
  • 比较:像素值大于平均值记作1,相反记作0,总共64位。
  • 计算哈希值:将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。

感知 PHash
感知哈希算法可以获得更精确的结果,它采用的是DCT(离散余弦变换)来降低频率。

  • 缩小尺寸
    为了简化了DCT的计算,pHash以小图片开始(建议图片大于8x8,32x32)。
  • 简化色彩
    与aHash相同,需要将图片转化成灰度图像,进一步简化计算量(具体算法见aHash算法步骤)。
  • 计算DCT
    DCT是把图片分解频率聚集和梯状形,将空域的信号转换到频域上,具有良好的去相关性的性能。变换后DCT系数能量主要集中在左上角,其余大部分系数接近于零,DCT具有适用于图像压缩的特性。
  • 缩小DCT
    DCT的结果为32x32大小的矩阵,但只需保留左上角的8x8的矩阵,这部分呈现了图片中的最低频率。
  • 计算平均值
    同均值哈希一样,计算8x8的DCT矩阵的均值
  • 计算Phash值
    根据8x8的DCT矩阵进行比较,大于等于DCT均值的设为”1”,小于DCT均值的设为“0”。组合成64个bit位生成hash值,顺序随意但前后保持一致性即可。

计算相似度(距离)
得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算汉明距离(Hamming distance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。

具体的代码实现python语言。

import cv2
import numpy as np# 均值哈希算法
def aHash(img):# 缩放为8*8img = cv2.resize(img, (8, 8))# 转换为灰度图gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# s为像素和初值为0,hash_str为hash值初值为''s = 0hash_str = ''# 遍历累加求像素和for i in range(8):for j in range(8):s = s + gray[i, j]# 求平均灰度avg = s / 64# 灰度大于平均值为1相反为0生成图片的hash值for i in range(8):for j in range(8):if gray[i, j] > avg:hash_str = hash_str + '1'else:hash_str = hash_str + '0'return hash_str
# 差值感知算法
def dHash(img):img = cv2.resize(img, (9, 8))gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)hash_str = ''# 每行前一个像素大于后一个像素为1,相反为0,生成哈希for i in range(8):for j in range(8):if gray[i, j] > gray[i, j + 1]:hash_str = hash_str + '1'else:hash_str = hash_str + '0'return hash_str
# 感知哈希算法(pHash)
def pHash(img):img = cv2.resize(img, (32, 32))  # , interpolation=cv2.INTER_CUBICgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 将灰度图转为浮点型,再进行dct变换dct = cv2.dct(np.float32(gray))# opencv实现的掩码操作dct_roi = dct[0:8, 0:8]hash = []avreage = np.mean(dct_roi)for i in range(dct_roi.shape[0]):for j in range(dct_roi.shape[1]):if dct_roi[i, j] > avreage:hash.append(1)else:hash.append(0)return hash
# Hash值对比
def cmpHash(hash1, hash2):n = 0# hash长度不同则返回-1代表传参出错if len(hash1)!=len(hash2):return -1# 遍历判断for i in range(len(hash1)):# 不相等则n计数+1,n最终为相似度if hash1[i] != hash2[i]:n = n + 1return nif __name__ == '__main__':img1 = cv2.imread('./1.png')  img2 = cv2.imread('./2.png')hash1 = aHash(img1)hash2 = aHash(img2)n = cmpHash(hash1, hash2)print('均值哈希算法相似度:', n)hash1 = dHash(img1)hash2 = dHash(img2)n = cmpHash(hash1, hash2)print('差值哈希算法相似度:', n)hash1 = pHash(img1)hash2 = pHash(img2)n = cmpHash(hash1, hash2)print('感知哈希算法相似度:', n)

使用的时候,第一个参数是基准图片,第二个参数是用来比较的其他图片所在的目录,返回结果是两张图片之间不相同的数据位数量(汉明距离)。

这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。
  
比较三种方法

  • 均值Hash比感知显著地要快。如果你找一些明确的东西,均值Hash能算法快速地找到它,所以,它的最佳用途是根据缩略图,找出原图。
  • 如果图片有些修改,如过都添加了一些内容或头部叠加在一起,均值Hash就无法处理,虽然感知Hash比较慢,但它能很好地容忍一些小的变型(变型度小于25%的图片)。
  • 相比感知Hash,差值Hash的速度更快,
  • 相比均值Hash,差值Hash在效率几乎相同的情况下的效果要更好

结构性相似度SSIM

在两幅图的距离时,更偏重于两图的结构相似性,而不是逐像素计算两图的差异。提出了基于 structural similarity 的度量,声称其比 MSE 更能反映人类视觉系统对两幅图相似性的判断。把两幅图 x, y 的相似性按三个维度进行比较:
 亮度(对应均值)(luminance)l(x,y),
               
 对比度(对应方差)(contrast)c(x,y),
               
 结构(对应协方差)(structure)s(x,y),
                
  令C3=C2/2,c(x,y)的分子和s(x,y)的分母可以约分,最终 x 和 y 的相似度为这三者的函数,默认每个项的重要性最后是相等的:
          
上述中μx,μy,σx,σy,σxy\mu{x},\mu{y},\sigma{x},\sigma{y},\sigma{xy}μx,μy,σx,σy,σxy分别为x图像均值,y图像均值,x图像方差,y图像方差,两图像协方差,C1,C2C1,C2C1,C2为非零的小的常数避免分母为零。
   通常, SSIM 不能用于一整幅图, 因为在整幅图的跨度上,均值和方差往往变化剧烈;同时,图像上不同区块的失真程度也有可能不同,不能一概而论;此外类比人眼睛每次只能聚焦于一处的特点。作者采用 sliding window 以步长为 1 计算两幅图各个对应 sliding window 下的 patch 的 SSIM,然后取平均值作为两幅图整体的 SSIM,称为 Mean SSIM。简写为 MSSIM(不同于multi-scale SSIM:MS-SSIM )。
    如下为计算MSSIM的一种c++代码,使用了11*11的对称高斯加权函数作为加权窗口,标准差为1.5,C1 = 6.5025, C2 = 58.5225。

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>using namespace std;
using namespace cv;Scalar CalcMSSIM(Mat  inputimage1, Mat inputimage2)
{Mat i1 = inputimage1;Mat i2 = inputimage2;const double C1 = 6.5025, C2 = 58.5225;int d = CV_32F;Mat I1, I2;i1.convertTo(I1, d);i2.convertTo(I2, d);Mat I2_2 = I2.mul(I2);Mat I1_2 = I1.mul(I1);Mat I1_I2 = I1.mul(I2);Mat mu1, mu2;GaussianBlur(I1, mu1, Size(11, 11), 1.5);GaussianBlur(I2, mu2, Size(11, 11), 1.5);Mat mu1_2 = mu1.mul(mu1);Mat mu2_2 = mu2.mul(mu2);Mat mu1_mu2 = mu1.mul(mu2);Mat sigma1_2, sigma2_2, sigma12;GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);sigma1_2 -= mu1_2;GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);sigma2_2 -= mu2_2;GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);sigma12 -= mu1_mu2;Mat t1, t2, t3;t1 = 2 * mu1_mu2 + C1;t2 = 2 * sigma12 + C2;t3 = t1.mul(t2);t1 = mu1_2 + mu2_2 + C1;t2 = sigma1_2 + sigma2_2 + C2;t1 = t1.mul(t2);Mat ssim_map;divide(t3, t1, ssim_map);Scalar mssim = mean(ssim_map);return mssim;
}int main( int argc, char** argv )
{src_1 = imread("./1.jpg");src_2 = imread("./2.jog");Scalar result = CalcMSSIM(src_1,src_2);cout<<"the r g b channles similarity is :"<<result<<endl;
}

直方图相似度函数compareHist

图像处理之相似图片识别函数compareHist包含了如下四种方法;

1;Correlation 相关性比较 [1,0] 越大越相似
2;Chi-Square 卡方比较 [0,+200] 越小越相似
3;Intersection 十字交叉性 [+50,0] 越大越相似
4;Bhattacharyya distance 巴氏距离 [0, 1] 越小越相似

算法概述:

首先对源图像与要筛选的图像进行直方图数据采集,对采集的各自图像直方图进行归一化;然后使用compareHist函数对直方图数据进行计算,最终得出图像相似度值。

第一步:直方图计算

直方图分为灰度直方图与RGB直方图,对于灰度图像直方图计算十分简单,只要初始化一

个大小为256的直方图数组H,然后根据像素值完成频率分布统计,假设像素值为124,则

H[124] += 1, 而对于彩色RGB像素来说直方图表达有两种方式,一种是单一直方图,另外一

种是三维直方图,三维直方图比较简单明了,分别对应RGB三种颜色,定义三个直方图HR,

HG, HB, 假设某一个像素点P的RGB值为(4, 231,129), 则对于的直方图计算为HR[4] += 1,

HG[231] += 1, HB[129] += 1, 如此对每个像素点完成统计以后,RGB彩色直方图数据就生成了。

而RGB像素的单一直方图SH表示稍微复杂点,每个颜色的值范围为0 ~ 255之间的,假设

可以分为一定范围等份,当8等份时,每个等份的值范围为32, 16等份时,每个等份值范

围为16,当4等份时候,每个等份值的范围为64,假设RGB值为(14, 68, 221), 16等份之

后,它对应直方图索引值(index)分别为: (0, 4, 13), 根据计算索引值公式:index = R + G16 + B16*16

对应的直方图index = 0 + 4*16 + 13 * 16 * 16, SH[3392] += 1

如此遍历所有RGB像素值,完成直方图数据计算。

第二步: 直接使用compareHist函数,选择合适参数计算即可
c++实现

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;int main( int argc, char** argv )
{src_1 = imread("./1.jpg");src_2 = imread("./2.jog");// 转换到 HSV , 图片是RGB格式用CV_RGB2HSVcvtColor( src_1 , src_1 , CV_BGR2HSV );cvtColor( src_12, src_12, CV_BGR2HSV );// 对hue通道使用30个bin,对saturatoin通道使用32个binint h_bins = 50; int s_bins = 60;int histSize[] = { h_bins, s_bins };// hue的取值范围从0到256, saturation取值范围从0到180float h_ranges[] = { 0, 256 };float s_ranges[] = { 0, 180 };const float* ranges[] = { h_ranges, s_ranges };// 使用第0和第1通道int channels[] = { 0, 1 };// 直方图MatND src_1_hist,src_2_hist;// 计算HSV图像的直方图calcHist( &src_1 , 1, channels, Mat(), src_1_hist, 2, histSize, ranges, true, false );normalize( src_1_hist, src_1_hist, 0, 1, NORM_MINMAX, -1, Mat() );calcHist( &src_2 , 1, channels, Mat(), src_2_hist, 2, histSize, ranges, true, false );normalize( src_2_hist, src_2_hist, 0, 1, NORM_MINMAX, -1, Mat() );//4种对比方法for( int i = 0; i < 4; i++ ){ int compare_method = i;double result = compareHist( src_1_hist, src_2_hist, compare_method );printf( " Method [%d] Perfect,result= %f \n", i, result );}return 0;}

python实现

from PIL import Imagedef make_regalur_image(img, size = (256, 256)):return img.resize(size).convert('RGB')def hist_similar(lh, rh):assert len(lh) == len(rh)return sum(1 - (0 if l == r else float(abs(l - r))/max(l, r)) for l, r in zip(lh, rh))/len(lh)def calc_similar(li, ri):return hist_similar(li.histogram(), ri.histogram())if __name__ == '__main__':img1 = Image.open('./1.jpg')img2 = Image.open('./2.jpg')img1 = make_regalur_image(img1)img2 = make_regalur_image(img2)print(calc_similar(img1, img2))

总结

  • 对比三种方法来说稳定性较好的是MSSIM方法,直方图过于简单,只能捕捉颜色信息的相似性,捕捉不到更多的信息。只要颜色分布相似,就会判定二者相似度较高,显然不合理。

  • 基于互信息(Mutual Information)
    如果两张图片尺寸相同,还是能在一定程度上表征两张图片的相似性的。但是,大部分情况下图片的尺寸不相同,如果把两张图片尺寸调成相同的话,又会让原来很多的信息丢失,应用中此种方法的确很难把握。

  • 哈希算法
    可以实现快速搜索简略图

图片相相似度计算(Hash、SSIM、compareHist)相关推荐

  1. java k均值相异度计算_K-NN算法与K-Means算法的原理与区别(附带源码示例)

    KNN算法 K-Means算法 目标 确定某个元素所属的分类 将已存在的一系列元素分类 算法类别 监督的分类算法 无监督的聚类算法 数据区别 训练数据中,有明确的标签. 如:一个数据集中有几万张图片, ...

  2. 图片(矩阵)相似度计算

    计算图片相似度 均方误差.SSIM 结构相似性度量.cosine余弦距离.直方图.互信息.指纹 import numpy as np import matplotlib.pyplot as pltfr ...

  3. R-数据挖掘 | 聚类分析中的各种相异(似)度计算

    目录 一.聚类的基本数据结构 二.不同数据类型的相异度计算方法 (一)区间标度变量 (二)二元变量 (三)标称变量 (四)顺序变量 (五)比例标度型变量 (六)混合类型 三.R相异(似)度计算总结 一 ...

  4. 如何在 R 中计算 Bray-Curtis 相异度

    Bray-Curtis Dissimilarity是一种衡量两个不同站点之间差异的方法. 它经常在生态学和生物学中用于量化两个地点在这些地点发现的物种的不同之处. 计算如下: BC ij = 1 – ...

  5. python 图像识别_python图像识别之图片相似度计算

    作者 | a1131825850疯子 来源 | Python爬虫scrapy 原文 | python图像识别---------图片相似度计算 1.背景 要识别两张图片是否相似,首先我们可能会区分这两张 ...

  6. Python图像识别,图片相似度计算!

    1.背景 要识别两张图片是否相似,首先我们可能会区分这两张图是人物照,还是风景照等......对应的风景照是蓝天还是大海......做一系列的分类. 从机器学习的的角度来说,首先要提取图片的特征,将这 ...

  7. python图像识别之图片相似度计算

    作者 | a1131825850疯子  来源 | Python爬虫scrapy 1.背景 要识别两张图片是否相似,首先我们可能会区分这两张图是人物照,还是风景照等-对应的风景照是蓝天还是大海-做一系列 ...

  8. 连连看不一样的玩法,利用python进行图片相似度计算

    先放制作好的游戏视频链接:(纯粹是兴趣分享) 连连看不一样的玩法-图像相似度识别-python_单机游戏热门视频 https://www.ixigua.com/7076826558106698253? ...

  9. python图片相似度计算_python Opencv计算图像相似度过程解析

    这篇文章主要介绍了python Opencv计算图像相似度过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.相关概念 一般我们人区分谁是谁 ...

最新文章

  1. mysql的连接leftjion,mysql的表连接(left|right)join
  2. java 监听 循环_java循环按键循环监听事件
  3. python3.7安装turtle步骤-Python turtle安装和使用教程
  4. iptables的地址取反操作
  5. 08 ORA系列:ORA-01861 文字与格式字符串不匹配
  6. yytextview多种格式_iOS YYText的使用笔记一(YYTextView图文编辑器)
  7. 忆阻器的matlab建模_忆阻器Simulink建模和图形用户界面设计.PDF
  8. javascript字典中添加数组_如何在 JavaScript 中更好地使用数组
  9. 路径获取文件名通用方法
  10. 大数据 ---(4)大数据驱动的金融业务创新(用户画像-数据架构-标签建模)
  11. SAP License:企业高管眼中的信息化是“万能”的
  12. 常用计算机的外部组成设备有哪些,9计算机外部设备..doc
  13. Visual Studio 2017在编译OpenCV 4.2.0时出现编译器错误C2001:常量中有换行符
  14. 6N137S周边电阻选择和传输速率(在开关特性中有描述,上升时间下降时间等参数)
  15. 计算机cpu操作ppt,CPU基础知识PPT课件
  16. vue中事件修饰符,stop,prevent,capture,self,once
  17. 会计信息质量可靠性的案例_论会计信息质量特征及其可靠性
  18. 网站图标开发指南(精)
  19. 初学5之坦克要求(做出坦克被子弹击中时的爆炸效果)
  20. 关于517coding的10月月赛

热门文章

  1. java 回调的原理与实现
  2. 【无标题】小游戏用户界面登录验证
  3. Docker中配置Oracle12c
  4. UML建模与软件开发设计(四)——包图设计
  5. 重新启动的老式喷墨打印机
  6. 收费最低的云存储_亿方云好不好?亿方云怎么收费?
  7. left join fetch 用法实例记录
  8. git 拉取远程分支到本地(两种方法)
  9. vue使用html2canvas合成图片
  10. Datawhale集成学习:Stacking 算法与实战