作者|a1131825850狂人来源|Python爬虫scrapy1.背景判断两张图片是否相似,首先我们可以区分两张图片是人像还是风景等等…………对应的风景照片是蓝天还是大海……做一系列的分类.从机器学习的角度来看,首先需要提取图片的特征,对这些特征进行分类,训练建立模型,然后进行识别。但是计算机不容易区分这些图片是哪种类型,但是计算机可以知道图像的像素值。因此在图像识别的过程中,常用来通过颜色特征来识别相似图片(当然还有纹理特征、形状特征、空间关系特征等特征。这些又分为直方图、颜色集、颜色局、聚合向量、相关图等来计算颜色特征)。为了得到两张相似的图片,这里通过以下简单的计算方法来计算图片的相似度:通过哈希值计算图片相似度的直方图,通过图片结构度量计算通过图片余弦距离计算汉明距离1.直方图计算图片上面三张图分别是img1.png、img2.jpg、img.png:可以看出上面三张图还是比较像的,而且颜色也差不多。哪两个最像?大家可以猜一猜,看看是不是和我们计算的一样。在python中,使用opencv中的calcHist()方法获取其直方图数据,返回结果为列表:#计算img1的直方图H1=cv2.calcHist([img1],[1],None,[256],[0,256])H1=cv2.normalize(H1,H1,0,1,cv2.NORM_MINMAX,-1)#对图像进行归一化先计算img1的直方图,然后归一化,最后计算img2并归一化和img3,然后使用python自带的compareHist()比较相似度:使用compareHist()比较相似度1=cv2.compareHist(H1,H2,0)最后三张图片的直方图如下:图像的x轴是指图片在0到255之间的像素变化,y轴是指0到255像素的比例。我们可以清楚的看到img2和img3的直方图的变化趋势是一致的,重合的。运行结果如下:通过运行结果我们知道img2和img3的值最相似(代码calcImage.py)上面是直接调用opencv中的方法实现的,有下面还有一个自己写的方法:首先将图片转成RGB格式,这里使用pillow中的Image对图片进行处理:#ConverttheimagetoRGBdefmake_regalur_image(img,size=(64,64)):gray_image=img.resize(size).convert('RGB')returngray_image正在计算两幅图像的直方图:#计算直方图defhist_similar(lh,rh):assertlen(lh)==len(rh)hist=sum(1-(0ifl==relsefloat(abs(l-r))/max(l,r))forl,rinzip(lh,rh))/len(lh)returnhist正在计算itssimilarity:#计算相似度defcalc_similar(li,ri):calc_sim=hist_similar(li.histogram(),ri.histogram())returncalc_sim得到最终的运行结果:两种方法的结果还是有点区别的。可以看出img1和img3的结果比较相似。但是两者相似度的计算方法是:gi和si分别指的是两条曲线的第i个点。总结:使用直方图计算图片相似度时,是根据颜色的全局分布来看的,无法分析局部颜色。如果将同一张图片转换成灰度图,计算其直方图时的差距就更大了。为了解决这个问题,可以对图片进行均分,然后计算图片的相似度。不过这里就不描述了,大家可以自行探索!!!2.哈希算法计算图片的相似度。在计算之前,先了解一下图像指纹和汉明距离:图像指纹:图像指纹与人的指纹一样,是身份的象征。简单来说,图像指纹就是将图像按照一定的哈希算法运算后得到的一组二进制数。汉明距离:如果一组二进制数据是101,另一组是111,那么显然把第一组数据的第二位0变成1就可以变成第二组数据111,所以两组数据的汉明距离data的距离为1,简单来说,汉明距离就是一组二进制数据变成另一组数据所需要的步数。显然,这个值可以衡量两张图片之间的差异。汉明距离越小,相似度越高。汉明距离为0,说明两张图片完全一样。感知哈希算法是一类算法的总称,包括aHash、pHash和dHash。顾名思义,感知哈希并不是严格地计算哈希值,而是用一种更相对的方式来计算哈希值,因为“相似”与否是一种相对判断。几个哈希值的比较:aHash:平均哈希。更快,但通常不太准确。pHash:感知哈希。准确率比较高,但是速度比较差。dHash:差值哈希。精度高,速度也很快1.平均哈希算法(aHash):该算法是基于将灰度图像的每个像素点与平均值进行比较来实现的。aHash的汉明距离步骤:先将图像压缩成8*8的小图,将图像转成灰度图,计算图像的Hash值,其中hash值为64位,或者一个32位01字符串并将上述哈希值转换为16位哈希值计算汉明距离#均值哈希算法defahash(image):#将图像缩放为8*8image=cv2.resize(image,(8,8),interpolation=cv2.INTER_CUBIC)#将图像转换为灰度图像gray=cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)#s为像素点和初始灰度值,hash_str为哈希值的初始值s=0#遍历像素的累积和foriinrange(8):forjinrange(8):s=s+gray[i,j]#计算像素平均值avg=s/64#灰度大于平均值为1,相反为0,取图片的平均值得到哈希值,此时得到的哈希值为一个64位的01字符串ahash_str=''foriinrange(8):forjinrange(8):ifgray[i,j]>avg:ahash_str=ahash_str+'1'else:ahash_str=ahash_str+'0'result=''foriinrange(0,64,4):结果+=''。join('%x'%int(ahash_str[i:i+4],2))#print("ahashvalue:",result)returnresult2.感知哈希算法(pHash):平均哈希虽然简单,但受平均影响很大。如果对图像进行伽马校正或者对直方图进行平均,都会影响平均值,从而影响哈希值的计算。于是有人提出了一种更鲁棒的方法,通过离散余弦(DCT)提取低频。离散余弦变换(DCT)是一种图像压缩算法,可将图像从像素域变换到频域。那么,一般图像中存在大量的冗余和相关性,所以转换到频域后,只有一小部分频率分量的系数不为0,大部分系数为0(或接近0).pHash的计算步骤:缩小图片:32*32是比较好的尺寸,这样方便将DCT计算转换为灰度图计算DCT:使用Opencv中提供的dct()方法,注意输入图像必须是32位浮点型,所以先用numpy中的float32进行DCT转换和收缩:DCT计算后的矩阵为3232,左上角的88保留,这些中频率最低的representativepicturesusedtocalculateaveragevalue:计算所有像素点收缩DCT平均值后的值。进一步降低DCT:大于平均值记为1,否则记为0。获取信息指纹:组合64个信息位,顺序随机,保持一致性。最后比较两幅图像的指纹,得到汉明距离。#phashdefphash(path):#加载并调整图像为32*32的灰度图img=cv2.imread(path)img1=cv2.resize(img,(32,32),cv2.COLOR_RGB2GRAY)#创建两个-dimensionalListh,w=img.shape[:2]vis0=np.zeros((h,w),np.float32)vis0[:h,:w]=img1#DCT二维变换#离散余弦变换,getdct系数矩阵img_dct=cv2.dct(cv2.dct(vis0))img_dct.resize(8,8)#将列表转为一维列表img_list=np.array().flatten(img_dct.tolist())#计算平均值img_mean=cv2.mean(img_list)avg_list=['0'ifi
