当前位置: 首页 > 后端技术 > Python

python图像识别的图像相似度计算

时间:2023-03-25 22:40:51 Python

作者|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'ifigray[i,j+1]:dhash_str=dhash_str+'1'else:dhash_str=dhash_str+'0'result=''foriinrange(0,64,4):result+=''.join('%x'%int(dhash_str[i:i+4],2))#print("散列值",结果)返回结果4。CalculateHashvaluedifference#计算两个hash值的差defcampHash(hash1,hash2):n=0#hash长度不同返回-1,此时无法比较iflen(hash1)!=len(hash2):return-1#如果hash长度相同,遍历长度foriinrange(len(hash1)):ifhash1[i]!=hash2[i]:n=n+1returnn最终运行结果:aHash:dhash:p_hsah:从上面运行的结果可以看出,img1和img2的相似度更高。3、余弦相似度(cosin)将图片表示为一个向量,通过计算向量之间的余弦距离来表征两张图片的相似度。1.归一化图像#统一图像defget_thum(image,size=(64,64),greyscale=False):#使用image重新设置图像大小,Image.ANTIALIAS为高质量image=image.resize(size,Image.ANTIALIAS)ifgreyscale:#将图像转换为L模式,即灰度图像,每个像素点用8位表示image=image.convert('L')returnimage2.Calculatecosinedistance#计算余弦距离图像定义image_similarity_vectors_via_numpy(image1,image2):image1=get_thum(image1)image2=get_thum(image2)images=[image1,image2]vectors=[]norms=[]forimageinimages:vector=[]forpixel_tupleinimage.getdata():vector.append(average(pixel_tuple))vectors.append(vector)#linalg=linear(线性)+algebra(代数),norm表示范数#求图像范数??norms.append(linalg.norm(vector,2))a,b=vectorsa_norm,b_norm=norms#dot返回一个点积,是在二维数组(矩阵)上计算的res=dot(a/a_norm,b/b_norm)returnres最终运行结果:结果表明img1和img2的相似度更高,这与计算hash值的汉明距离得到的结果一致。4.图片SSIM(StructuralSimilarityMeasure)SSIM是一种全参考图像质量评价指标,从亮度、对比度和结构三个方面衡量图像的相似性。SSIM的取值范围是[0,1]。该值越大,图像失真越小。在实际应用中,可以使用滑动窗口对图像进行分块,总分块数为N。考虑到窗口形状对分块的影响,采用高斯加权计算均值、方差和协方差每个窗口,然后计算对应块的两幅图像的结构相似度SSIM,最后取平均值作为两幅图像的结构相似度度量,即平均结构相似度SSIM。ssim1=compare_ssim(img1,img2,multichannel=True)这是scikit-image库自带的一种计算方法的结果:可以看到img1和img2相似度很高。好了,以上就是我目前遇到的图像相似度的计算方法。一定有很多计算方法是我没有接触过的。如果需要,可以参考。如果大家还有其他方法可以留言一起讨论!!!

猜你喜欢