[171103] 基於縮略圖哈希值比較的圖像相似性檢索
原創內容,禁止轉載!
導讀:這是 Python OpenCV 圖像處理 專欄的第3篇文章,主要目的是 介紹一種基於縮略圖哈希值比較的圖像相似性檢索的方法,並給出了簡單代碼實現。關於 Python OpenCV 處理的基礎知識,可以參考這篇文章 [171102] Python3 OpenCV3 圖像處理基礎(Python3 + Numpy + Matplotlib + OpenCV3 + ...)。更多文章,請查看 [171101] Python OpenCV 圖像處理專欄目錄。
除了使用文本搜索,還可以使用圖片搜索,也就是以圖搜圖。各大搜索廠家都有提供,還是喜歡用 Google 家的圖像搜索。不管進行任何方式的搜索,歸結起來都是按照資料庫中「詞」和查詢「詞」的相似性排序並返回 TopK 個 或所有結果。所以關鍵點至少有三個:
(1) 以何種方式表示「詞」?(2) 以何種方式度量「詞」的相似性?(3) 以何種方式進行「詞」的相似性排序?
這裡介紹一種基於縮略圖哈希值比較的圖像相似性檢索,大致原理如下:
學過信號處理/圖像處理或相關課程的同學都知道,信號的高頻表示細節,而低頻部分表示大概的結構。進行相似性檢索的預處理時,可以拋棄高頻細節部分,而使用低頻結構信息進行操作。而圖像縮小(shrik)是一種快速的降低高頻信息的方式,同時保留了原始圖像結構信息。對灰度縮略圖進行二值化,得到二值圖像。將二值圖像視為哈希值的二進位位,也就是將其一維化後得到二進位位組,即原圖的哈希指紋,也就是「詞」。對資料庫中所有的圖像進行上述操作,得到了圖像的哈希資料庫。當進行檢索(也就是進行相似性比較時),採用漢明距離作為相似性(距離)度量。如果數據量較小,使用快排進行排序即可;如果數據量較大,使用優先隊列topK排序獲取一定數量的結果。
下午去開會,困死了,剛補個覺回來。繼續。。。
大致原理就就上面說的,這是使用上述原理對4個圖像生成哈希指紋並進行相似度排序的一個小栗子。(第一幅圖是待檢索圖像,所有的四幅圖是四個小樣本數據集。。。)
實驗中,發現二值化方式(也就是生成哈希的方式)對漢明距離度量有很大的影響。這裡使用的是以平均值作為閾值進行二值化。
核心代碼如下:
#!/usr/bin/python3#! 2017.11.03 09:12:18 CST#! 2017.11.03 21:22:50 CSTimport cv2import numpy as npfrom functools import reduce """基於縮略圖哈希值比較的圖像相似性檢索"""def getHash(img, N=8): """ @src: 文件名/灰度圖/BGR @N: 縮略圖(thumbnail)的大小 """ ## (1) 圖像轉化為灰度圖 if img.ndim == 3 and img.shape[2] == 3: img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ## (2) 使用雙線性差值縮小圖像 img = cv2.resize(img, (N,N), 0, 0, cv2.INTER_CUBIC) ## (3) 以均值為閾值進行二值化 thresh, threshed = cv2.threshold(img, thresh = int(np.mean(img)), maxval=255, type=cv2.THRESH_BINARY) ## (4) 將二值圖像轉化為二進位位序列 lst = threshed.ravel().tolist() ## (5) 為序列求值(注意此處的lambda函數寫法) xhash = reduce(lambda res,x: (res<<1)|(x>0 and 1 or 0), lst, 0) return xhashdef countOne(x): """統計十進位數的二進位位中1的個數(不計符號位) assert countOne(0b1101001) == 4 """ x = int(x) cnt = 0 while x: cnt +=1 x &= x-1 return cntdef hammingDist(x1,x2): """計算兩個值的漢明距離,即求異或值的二進位位中1的個數 assert hammingDist(0b001,0b110) == 3 assert hammingDist(0b111,0b110) == 1 """ return countOne(x1 ^ x2)if __name__ == "__main__": ## 讀取圖像 img1 = cv2.imread("firefox.png") img2 = cv2.imread("chrome.png") ## 計算哈希 xhash1 = getHash(img1) xhash2 = getHash(img2) ## 進行漢明距離度量 dist = hammingDist(xhash1, xhash2) print("xhash1: {}
xhash2: {}
dist: {}".format(xhash1, xhash2, dist))
就這樣吧
完結,手動撒花。。。
參考:
http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html
推薦閱讀:
※元旦贈書 | 18本紙質書:OpenCV、Python和機器學習,總有一本適合你
※【小林的OpenCV基礎課 0】一切為了學習!
※如何在CLion上配置使用OpenCV?