
作者 | a1131825850瘋子
來源 | Python爬蟲scrapy
1.背景
要識別兩張圖片是否相似,首先我們可能會區(qū)分這兩張圖是人物照,還是風(fēng)景照等......對應(yīng)的風(fēng)景照是藍天還是大海......做一系列的分類。
從機器學(xué)習(xí)的的角度來說,首先要提取圖片的特征,將這些特征進行分類處理,訓(xùn)練并建立模型,然后在進行識別。
但是讓計算機去區(qū)分這些圖片分別是哪一類是很不容易的,不過計算機可以知道圖像的像素值的,因此,在圖像識別過程中,通過顏色特征來識別是相似圖片是我們常用的(當(dāng)然還有其特征還有紋理特征、形狀特征和空間關(guān)系特征等,這些有分為直方圖,顏色集,顏色局,聚合向量,相關(guān)圖等來計算顏色特征),
為了得到兩張相似的圖片,在這里通過以下幾種簡單的計算方式來計算圖片的相似度:
直方圖計算圖片的相似度
通過哈希值,漢明距離計算
通過圖片的余弦距離計算
通過圖片結(jié)構(gòu)度量計算
一、直方圖計算圖片的相似度
上三張圖片,分別是img1.png, img2.jpg,img.png:
可以看出上面這三張圖是挺相似的,在顏色上是差不多的,最相似的是哪兩張大家可以猜猜看,看和我們計算的是否一樣。
在python中利用opencv中的calcHist()方法獲取其直方圖數(shù)據(jù),返回的結(jié)果是一個列表:
# 計算圖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()進行比較相似度similarity1 = cv2.compareHist(H1, H2, 0)
最后得到三張圖片的直方圖如下:
圖像的x軸是指的圖片的0~255之間的像素變化,y軸指的是在這0~255像素所占的比列。
我們可以明顯的看出img2與img3的直方圖的變化趨勢是相符的有重合態(tài)的,運行結(jié)果如下:
通過運行結(jié)果知道img2和img3是值是最為相似的(代碼calcImage.py)
上面的是直接調(diào)用opencv中的方法來實現(xiàn)的,下面還有自己寫的方法:
首先是將圖片轉(zhuǎn)化為RGB格式,在這里是用的pillow中的Image來對圖片做處理的:
# 將圖片轉(zhuǎn)化為RGBdef make_regalur_image(img, size=(64, 64)): gray_image = img.resize(size).convert('RGB') return gray_image
在計算兩圖片的直方圖:
# 計算直方圖def hist_similar(lh, rh): assert len(lh) == len(rh) hist = sum(1 - (0 if l == r else float(abs(l - r)) / max(l, r)) for l, r in zip(lh, rh)) / len(lh) return hist
在計算其相似度:
# 計算相似度def calc_similar(li, ri): calc_sim = hist_similar(li.histogram(), ri.histogram())returncalc_sim
得到最終的運行結(jié)果:
兩種方法的的結(jié)果還是有點差距的,可以看到img1和img3的結(jié)果相似度高些。
不過兩者的相似度計算方法如下:
gi和si分別指的是兩條曲線的第i個點。
總結(jié):
利用直方圖計算圖片的相似度時,是按照顏色的全局分布情況來看待的,無法對局部的色彩進行分析,同一張圖片如果轉(zhuǎn)化成為灰度圖時,在計算其直方圖時差距就更大了。
為了解決這個問題,可以將圖片進行等分,然后在計算圖片的相似度。不過在這里我就不敘述了,大家自行探討?。。?/span>
二、哈希算法計算圖片的相似度
在計算之前我們先了解一下圖像指紋和漢明距離:
圖像指紋:
圖像指紋和人的指紋一樣,是身份的象征,而圖像指紋簡單點來講,就是將圖像按照一定的哈希算法,經(jīng)過運算后得出的一組二進制數(shù)字。
漢明距離:
假如一組二進制數(shù)據(jù)為101,另外一組為111,那么顯然把第一組的第二位數(shù)據(jù)0改成1就可以變成第二組數(shù)據(jù)111,所以兩組數(shù)據(jù)的漢明距離就為1。簡單點說,漢明距離就是一組二進制數(shù)據(jù)變成另一組數(shù)據(jù)所需的步驟數(shù),顯然,這個數(shù)值可以衡量兩張圖片的差異,漢明距離越小,則代表相似度越高。漢明距離為0,即代表兩張圖片完全一樣。
感知哈希算法是一類算法的總稱,包括aHash、pHash、dHash。顧名思義,感知哈希不是以嚴(yán)格的方式計算Hash值,而是以更加相對的方式計算哈希值,因為“相似”與否,就是一種相對的判定。
幾種hash值的比較:
aHash:平均值哈希。速度比較快,但是常常不太精確。
pHash:感知哈希。精確度比較高,但是速度方面較差一些。
dHash:差異值哈希。精確度較高,且速度也非常快
1. 平均哈希算法(aHash):
該算法是基于比較灰度圖每個像素與平均值來實現(xiàn)。
aHash的hanming距離步驟:
先將圖片壓縮成8*8的小圖
將圖片轉(zhuǎn)化為灰度圖
計算圖片的Hash值,這里的hash值是64位,或者是32位01字符串
將上面的hash值轉(zhuǎn)換為16位的
通過hash值來計算漢明距離
# 均值哈希算法def ahash(image): # 將圖片縮放為8*8的 image = cv2.resize(image, (8, 8), interpolation=cv2.INTER_CUBIC) # 將圖片轉(zhuǎn)化為灰度圖 gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) # s為像素和初始灰度值,hash_str為哈希值初始值 s = 0 # 遍歷像素累加和 for i in range(8): for j in range(8): s = s + gray[i, j] # 計算像素平均值 avg = s / 64 # 灰度大于平均值為1相反為0,得到圖片的平均哈希值,此時得到的hash值為64位的01字符串 ahash_str = '' for i in range(8): for j in range(8): if gray[i, j] > avg: ahash_str = ahash_str + '1' else: ahash_str = ahash_str + '0' result = '' for i in range(0, 64, 4): result += ''.join('%x' % int(ahash_str[i: i + 4], 2)) # print("ahash值:",result) return result
2.感知哈希算法(pHash):
均值哈希雖然簡單,但是受均值影響大。如果對圖像進行伽馬校正或者進行直方圖均值化都會影響均值,從而影響哈希值的計算。所以就有人提出更健壯的方法,通過離散余弦(DCT)進行低頻提取。
離散余弦變換(DCT)是種圖像壓縮算法,它將圖像從像素域變換到頻率域。然后一般圖像都存在很多冗余和相關(guān)性的,所以轉(zhuǎn)換到頻率域之后,只有很少的一部分頻率分量的系數(shù)才不為0,大部分系數(shù)都為0(或者說接近于0)。
pHash的計算步驟:
縮小圖片:32 * 32是一個較好的大小,這樣方便DCT計算轉(zhuǎn)化為灰度圖
計算DCT:利用Opencv中提供的dct()方法,注意輸入的圖像必須是32位浮點型,所以先利用numpy中的float32進行轉(zhuǎn)換
縮小DCT:DCT計算后的矩陣是32 * 32,保留左上角的8 * 8,這些代表的圖片的最低頻率
計算平均值:計算縮小DCT后的所有像素點的平均值。
進一步減小DCT:大于平均值記錄為1,反之記錄為0.
得到信息指紋:組合64個信息位,順序隨意保持一致性。
最后比對兩張圖片的指紋,獲得漢明距離即可。
# phashdef phash(path): # 加載并調(diào)整圖片為32*32的灰度圖片 img = cv2.imread(path) img1 = cv2.resize(img, (32, 32),cv2.COLOR_RGB2GRAY) # 創(chuàng)建二維列表 h, w = img.shape[:2] vis0 = np.zeros((h, w), np.float32) vis0[:h, :w] = img1 # DCT二維變換 # 離散余弦變換,得到dct系數(shù)矩陣 img_dct = cv2.dct(cv2.dct(vis0)) img_dct.resize(8,8) # 把list變成一維list img_list = np.array().flatten(img_dct.tolist()) # 計算均值 img_mean = cv2.mean(img_list) avg_list = ['0' if i<img_mean else '1' for i in img_list] return ''.join(['%x' % int(''.join(avg_list[x:x+4]),2) for x in range(0,64,4)])
3. 差異值哈希算法(dHash):
相比pHash,dHash的速度要快的多,相比aHash,dHash在效率幾乎相同的情況下的效果要更好,它是基于漸變實現(xiàn)的。
dHash的hanming距離步驟:
先將圖片壓縮成9*8的小圖,有72個像素點
將圖片轉(zhuǎn)化為灰度圖
計算差異值:dHash算法工作在相鄰像素之間,這樣每行9個像素之間產(chǎn)生了8個不同的差異,一共8行,則產(chǎn)生了64個差異值,或者是32位01字符串。
獲得指紋:如果左邊的像素比右邊的更亮,則記錄為1,否則為0.
通過hash值來計算漢明距離
# 差異值哈希算法def dhash(image): # 將圖片轉(zhuǎn)化為8*8 image = cv2.resize(image, (9, 8), interpolation=cv2.INTER_CUBIC) # 將圖片轉(zhuǎn)化為灰度圖 gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) dhash_str = '' for i in range(8): for j in range(8): if gray[i, j] > gray[i, j + 1]: dhash_str = dhash_str + '1' else: dhash_str = dhash_str + '0' result = '' for i in range(0, 64, 4): result += ''.join('%x' % int(dhash_str[i: i + 4], 2)) # print("dhash值",result)returnresult
4. 計算哈希值差異
#計算兩個哈希值之間的差異def campHash(hash1, hash2): n = 0 # hash長度不同返回-1,此時不能比較 if len(hash1) != len(hash2): return -1 # 如果hash長度相同遍歷長度 for i in range(len(hash1)): if hash1[i] != hash2[i]: n = n + 1 return n
最終的運行結(jié)果:
aHash:
dhash:
p_hsah:
通過上面運行的結(jié)果可以看出來,img1和img2的相似度高一些。
三、余弦相似度(cosin)
把圖片表示成一個向量,通過計算向量之間的余弦距離來表征兩張圖片的相似度。
1. 對圖片進行歸一化處理
# 對圖片進行統(tǒng)一化處理def get_thum(image, size=(64, 64), greyscale=False): # 利用image對圖像大小重新設(shè)置, Image.ANTIALIAS為高質(zhì)量的 image = image.resize(size, Image.ANTIALIAS) if greyscale: # 將圖片轉(zhuǎn)換為L模式,其為灰度圖,其每個像素用8個bit表示 image = image.convert('L') return image
2. 計算余弦距離
# 計算圖片的余弦距離def image_similarity_vectors_via_numpy(image1, image2): image1 = get_thum(image1) image2 = get_thum(image2) images = [image1, image2] vectors = [] norms = [] for image in images: vector = [] for pixel_tuple in image.getdata(): vector.append(average(pixel_tuple)) vectors.append(vector) # linalg=linear(線性)+algebra(代數(shù)),norm則表示范數(shù) # 求圖片的范數(shù)?? norms.append(linalg.norm(vector, 2)) a, b = vectors a_norm, b_norm = norms # dot返回的是點積,對二維數(shù)組(矩陣)進行計算 res = dot(a / a_norm, b / b_norm)returnres
最終運行結(jié)果:
結(jié)果顯示img1和img2的相似度高一些,和計算hash值的漢明距離得到的結(jié)果是相一致的。
四、圖片SSIM(結(jié)構(gòu)相似度量)
SSIM是一種全參考的圖像質(zhì)量評價指標(biāo),分別從亮度、對比度、結(jié)構(gòu)三個方面度量圖像相似性。SSIM取值范圍[0, 1],值越大,表示圖像失真越小。在實際應(yīng)用中,可以利用滑動窗將圖像分塊,令分塊總數(shù)為N,考慮到窗口形狀對分塊的影響,采用高斯加權(quán)計算每一窗口的均值、方差以及協(xié)方差,然后計算對應(yīng)塊的結(jié)構(gòu)相似度SSIM,最后將平均值作為兩圖像的結(jié)構(gòu)相似性度量,即平均結(jié)構(gòu)相似性SSIM。
ssim1 = compare_ssim(img1, img2, multichannel=True)
這個是scikit-image庫自帶的一種計算方法
運行結(jié)果:
可以看到img1和img2的相似度高。
好了,以上就是到目前為止我接觸到的圖片相似度的計算方法,肯定還有許多我沒有接觸到的計算方法,大家有需要的可以參考一下,有其他方法的大家可以留言一起探討!?。?/span>
數(shù)據(jù)分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
LSTM 模型輸入長度選擇技巧:提升序列建模效能的關(guān)鍵? 在循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)家族中,長短期記憶網(wǎng)絡(luò)(LSTM)憑借其解決長序列 ...
2025-07-11CDA 數(shù)據(jù)分析師報考條件詳解與準(zhǔn)備指南? ? 在數(shù)據(jù)驅(qū)動決策的時代浪潮下,CDA 數(shù)據(jù)分析師認(rèn)證愈發(fā)受到矚目,成為眾多有志投身數(shù) ...
2025-07-11數(shù)據(jù)透視表中兩列相乘合計的實用指南? 在數(shù)據(jù)分析的日常工作中,數(shù)據(jù)透視表憑借其強大的數(shù)據(jù)匯總和分析功能,成為了 Excel 用戶 ...
2025-07-11尊敬的考生: 您好! 我們誠摯通知您,CDA Level I和 Level II考試大綱將于 2025年7月25日 實施重大更新。 此次更新旨在確保認(rèn) ...
2025-07-10BI 大數(shù)據(jù)分析師:連接數(shù)據(jù)與業(yè)務(wù)的價值轉(zhuǎn)化者? ? 在大數(shù)據(jù)與商業(yè)智能(Business Intelligence,簡稱 BI)深度融合的時代,BI ...
2025-07-10SQL 在預(yù)測分析中的應(yīng)用:從數(shù)據(jù)查詢到趨勢預(yù)判? ? 在數(shù)據(jù)驅(qū)動決策的時代,預(yù)測分析作為挖掘數(shù)據(jù)潛在價值的核心手段,正被廣泛 ...
2025-07-10數(shù)據(jù)查詢結(jié)束后:分析師的收尾工作與價值深化? ? 在數(shù)據(jù)分析的全流程中,“query end”(查詢結(jié)束)并非工作的終點,而是將數(shù) ...
2025-07-10CDA 數(shù)據(jù)分析師考試:從報考到取證的全攻略? 在數(shù)字經(jīng)濟蓬勃發(fā)展的今天,數(shù)據(jù)分析師已成為各行業(yè)爭搶的核心人才,而 CDA(Certi ...
2025-07-09【CDA干貨】單樣本趨勢性檢驗:捕捉數(shù)據(jù)背后的時間軌跡? 在數(shù)據(jù)分析的版圖中,單樣本趨勢性檢驗如同一位耐心的偵探,專注于從單 ...
2025-07-09year_month數(shù)據(jù)類型:時間維度的精準(zhǔn)切片? ? 在數(shù)據(jù)的世界里,時間是最不可或缺的維度之一,而year_month數(shù)據(jù)類型就像一把精準(zhǔn) ...
2025-07-09CDA 備考干貨:Python 在數(shù)據(jù)分析中的核心應(yīng)用與實戰(zhàn)技巧? ? 在 CDA 數(shù)據(jù)分析師認(rèn)證考試中,Python 作為數(shù)據(jù)處理與分析的核心 ...
2025-07-08SPSS 中的 Mann-Kendall 檢驗:數(shù)據(jù)趨勢與突變分析的有力工具? ? ? 在數(shù)據(jù)分析的廣袤領(lǐng)域中,準(zhǔn)確捕捉數(shù)據(jù)的趨勢變化以及識別 ...
2025-07-08備戰(zhàn) CDA 數(shù)據(jù)分析師考試:需要多久?如何規(guī)劃? CDA(Certified Data Analyst)數(shù)據(jù)分析師認(rèn)證作為國內(nèi)權(quán)威的數(shù)據(jù)分析能力認(rèn)證 ...
2025-07-08LSTM 輸出不確定的成因、影響與應(yīng)對策略? 長短期記憶網(wǎng)絡(luò)(LSTM)作為循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)的一種變體,憑借獨特的門控機制,在 ...
2025-07-07統(tǒng)計學(xué)方法在市場調(diào)研數(shù)據(jù)中的深度應(yīng)用? 市場調(diào)研是企業(yè)洞察市場動態(tài)、了解消費者需求的重要途徑,而統(tǒng)計學(xué)方法則是市場調(diào)研數(shù) ...
2025-07-07CDA數(shù)據(jù)分析師證書考試全攻略? 在數(shù)字化浪潮席卷全球的當(dāng)下,數(shù)據(jù)已成為企業(yè)決策、行業(yè)發(fā)展的核心驅(qū)動力,數(shù)據(jù)分析師也因此成為 ...
2025-07-07剖析 CDA 數(shù)據(jù)分析師考試題型:解鎖高效備考與答題策略? CDA(Certified Data Analyst)數(shù)據(jù)分析師考試作為衡量數(shù)據(jù)專業(yè)能力的 ...
2025-07-04SQL Server 字符串截取轉(zhuǎn)日期:解鎖數(shù)據(jù)處理的關(guān)鍵技能? 在數(shù)據(jù)處理與分析工作中,數(shù)據(jù)格式的規(guī)范性是保證后續(xù)分析準(zhǔn)確性的基礎(chǔ) ...
2025-07-04CDA 數(shù)據(jù)分析師視角:從數(shù)據(jù)迷霧中探尋商業(yè)真相? 在數(shù)字化浪潮席卷全球的今天,數(shù)據(jù)已成為企業(yè)決策的核心驅(qū)動力,CDA(Certifie ...
2025-07-04CDA 數(shù)據(jù)分析師:開啟數(shù)據(jù)職業(yè)發(fā)展新征程? ? 在數(shù)據(jù)成為核心生產(chǎn)要素的今天,數(shù)據(jù)分析師的職業(yè)價值愈發(fā)凸顯。CDA(Certified D ...
2025-07-03