[計算機視覺]基於內容的圖像搜索實現

圖像搜索引擎一般有三種實現方式:

(1)Search By Metadata,這種方式不會考慮圖片本身內容(圖片包含物體,以及圖像像素分佈等),純粹根據圖像標籤來進行檢索。如果某個網頁中有一張賽馬的圖片,並且網頁文本內容中包含“賽馬”(或者相關詞彙)的文字,當用戶搜索“賽馬”、“馬”、“horse”等關鍵字時,搜索引擎就會把這張圖當作檢索結果返回給用戶。換句話說,此時的圖像搜索引擎乾的事情跟普通搜索引擎差不多,匹配關鍵詞,並將對應圖片返回給用戶。這種工作方式的優點是速度快,在普通搜索引擎的技術基礎之上很容易改進去實現。缺點也很明顯,它完全依賴於描述圖片的文字(標籤),如果描述圖片的文字不對或者相關性不大時,搜索準確性可想而知,比如我這篇博客中如果插入一張“貓”的照片,但是整篇博客文章對“貓”隻字不提,那麼基於Search By Metadata的搜索引擎很難找到博客中貓的圖片。有一類圖片分享網站要求用戶在上傳圖片時,人工用幾個詞彙描述圖片中有什麼(標籤),便於後面基於Metadata的搜索。當然也不排除一些基於深度學習的圖片分類自動打標籤的方式。

(2)Search By Example,這種方式考慮圖片本身內容(圖片包含物體,以及圖片像素分佈等等),用戶輸入圖片,搜索引擎根據圖片內容,返回與該圖片相似的圖片結果。這種方式相比Search By Metadata要複雜一些,當然如果實現恰當,準確性也更能得到保障。如果用戶上傳一張包含“馬”的圖片,那麼搜索引擎會返回包含馬的其他圖片,或者,當用戶上傳一張“沙灘”的風景圖片,搜索引擎會返回一堆海邊沙灘的圖片,這些圖片包含類似的內容:沙灘、天空、大海、遊客。Search By Example的方式就是我們熟知的“以圖搜圖”,通過一張圖找出網上相似的其他圖片。實現方式有很多,有基於深度學習的方式,也有傳統的圖像分析算法,後者也是本篇文章後面會詳細介紹的部分。

(3)第三種就是前兩種的結合體,具體就不多說了,技術互補,到達最佳效果。

本篇文章主要介紹利用傳統圖像分析算法如何實現Search By Example的搜索引擎(以圖搜索)。

源碼地址:https://github.com/sherlockchou86/cbir-image-search

 

圖像指紋

人類有指紋,通過指紋對比可以判斷兩個人是否是同一個人,換句話說,指紋可以當作人類獨一無二的標識符。圖片也有類似的概念,成千上萬的圖片中,每張都有自己的特點,通過某種方式提取它的特徵,可以作爲圖像對比時的關鍵依據。

圖像指紋提取通常稱爲“特徵提取”,在程序代碼中,提取到的圖像特徵通常用一個多維向量或者一串64/126位二進制數字表示。特徵提取的方式有很多種(後面會介紹三類),不管通過哪種方式提取圖像特徵,都應該保證:通過特徵對比,我們可以反推原始圖片的相似度。

 

通過圖像特徵評價圖片相似度

假設我們已經爲兩張圖片提取到了合適的圖像特徵,如何操作我們可以通過特徵來反應原始圖片的相似度呢?一般我們計算兩個特徵之前的距離,通過距離反映原始圖像的相似度,如果距離越近,兩張原始圖片相似度更高,反之亦然。

計算距離的方式有很多,需要根據特徵提取的方式來選擇不同的距離計算方法,通常有以下幾個距離計算方法:

(1)歐氏距離。就是歐幾里德距離,這個距離應該是我們最熟悉的,在小學就接觸了。我們在計算直線上兩點的距離就是指歐式距離,上初中時計算平面座標系中兩點的直線距離也是指歐式距離,上高中時計算三維座標系中兩點的直線距離同樣指歐式距離,四維、五維甚至更高維都是這種計算方式。每個點的座標用多維向量表示(a1, a2,..., an)和(b1,b2,...,bn),那麼兩個向量之間的歐式距離爲:(a1-b1)**2 + (a2-b2)**2 + ... + (an -bn)**2,然後開方。

(2)漢明距離。這個距離其實普通程序員應該也比較熟悉,它指兩個字符串(或者兩個位數相同的二進制數)對應位置不相同的字符個數,漢明距離越大,代表兩個串不相同的字符越多,兩個串相似度越低,反之亦然。如果是兩個二進制串計算漢明距離(1001010110)和(1001010100),非常簡單,直接使用XOR(異或運算符)即可,1001010110 xor 1001010100,然後計算結果中1的個數。

(3)餘弦距離。餘弦距離一般程序員可能用不到,它指兩個向量之間夾角的餘弦值。二維平面座標系中,向量(a1,a2)和向量(b1,b2)之間的夾角餘弦值很好計算,同理,三維、四維也一樣。餘弦距離代表兩個向量中各個分量的佔比程度,比如(3,3)和(5,5)兩個向量的餘弦距離爲0,因爲每個向量中各個分量佔比都爲50%(3/6,3/6 和 5/10,5/10)。同理三維向量(2,3,4)和(4,6,8)之間的餘弦距離也是0。兩個向量的餘弦距離爲零,不代表它們之間的歐式距離爲零。但是反過來卻成立。

(4)卡方距離。卡方距離主要用於衡量兩個概率分佈的相似性。可以假設兩個多維向量中的每個分量都代表概率(分量的和爲1),那麼卡方距離就是計算這兩個概率分佈的相似度。具體內容請網絡搜索。

 

以圖搜圖實現原理

以圖搜圖的過程其實很簡單,跟普通的檢索流程差不多。關鍵有兩個:

(1)一個是特徵提取方法,這個是重點,如何合理提取圖像特徵是保證準確性的第一要素;

(2)二個就是如何提高特徵對比的速度,成千上萬張圖片源,如何快速從中找出相同/相似的圖片?

下面介紹三種傳統圖像特徵提取的方式。

 

圖像特徵點

任何一張數字圖片,微觀上看,像素之前總是能找到一些規律的,像素分佈、像素值、像素密度等等。OpenCV內置很多特徵點提取算法,比如ORB、SURF以及SIFT等等。以SIFT舉例,輸入圖片,輸出該圖片中具有某些特徵的點(可以存在多個),從一定程度上講,這些點可以被當作圖片的標識,每個特徵點用一個128維的向量表示。如果要比較兩張圖片的相似度,先分別提取兩張圖片的SIFT特徵點,然後進行特徵點匹配,看有多少對特徵點能夠匹配上,如果能匹配的點超過一定數量,那麼認爲這兩張圖片相似。這個匹配的過程可能採用前面提到的各種距離比較。下面兩張圖通過特徵點提取、特徵點匹配後得到的結果,可以判斷兩張圖片相似:

 

可以看到,雖然圖片拍攝角度不一樣,但是包含的物體一致、場景類似,通過特徵點匹配,可以找到很多匹配到的特徵點。

這裏的圖像特徵用128維向量表示,可以包含多個,如果一張圖找到了100個特徵點,那麼每張圖有128*100個float數據需要存儲。

 

圖像感知哈希

哈希算法、哈希函數我們經常聽說,對於不同長度的輸入,哈希算法可以產生固定長度的輸出。那麼我們能否直接通過計算圖片文件的哈希值來判斷圖片是否相似/相同呢?答案是不能。這種方式計算出來的哈希值對評價原始圖片相似度沒有任何參考價值,因爲即使是相似的圖片通過這種方式計算出來的哈希值之間並不相似(可能相差十萬八千里),換句話說,我們不能通過哈希值之間的距離來反推原始圖片的相似度是多少。假如在一張圖片上修改了一點點,最後生成的哈希值跟原來的哈希值相差很遠。

因此我們需要用到圖像感知哈希算法,這種方法將圖片內容(更準確地講,應該是像素)考慮進來了。通過這種方式計算得到的哈希值可以反推出原始圖片之間的相似度。圖像感知哈希算法常見分三類:ahash,phash,dhash。計算方式基本差不多,下面以ahash爲例說明如何計算:

(1)縮放圖片。直接將原始圖片縮小到8*8的尺寸,不用考慮原始圖片的長寬比;

(2)灰度化。將8*8的圖片灰度化,這樣處理後,這張圖片一共包含64個像素;

(3)計算平均值。計算這64個像素值的平均值;

(4)構建哈希。將64個像素值依次與(3)中的平均值進行比較,大於平均值爲1,否則爲0,這樣從左到右、從上到下就可以組合得到一個64位的二進制數(順序無所謂,只要保證都按這個順序即可)。這個二進制串就是原始圖片計算出來的ahash值,格式爲110010001...001001,一共64位,將其轉換成16進制,得到的格式爲8f373714acfcf4d0。

如何比較相似度?很簡單,計算兩張圖ahash值的漢明距離,如果距離(不相同的位數)超過10則認爲兩張原始圖片不相似,小於10表示相似,具體閾值需要調整。這種方式非常簡單並且很好實現,而且很湊效,尤其是在一堆圖片中找相同圖片的時候(縮放無所謂),非常適合用縮略圖查找原始圖。

三種感知哈希計算方式:https://github.com/JohannesBuchner/imagehash

三種感知哈希原理說明:http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html

http://www.hackerfactor.com/blog/index.php?/archives/529-Kind-of-Like-That.html

三種感知哈希區別和優劣勢請參照網絡。

這裏的圖像特徵用64位二進制表示,每張圖片的特徵需要8個字節存儲。

 

基於區域的顏色直方圖

顏色直方圖統計整張圖片中各種像素的佔比情況,嚴格來講它並不考慮顏色分佈在圖片中的位置。而基於區域的顏色直方圖在計算像素佔比時,先將整張圖片劃分成不同的子區域,然後依次計算子區域的顏色佔比情況,最後考慮子區域合併之後的結果。這種方式彌補了之前忽略顏色分佈位置的缺陷,通過直方圖數據評價圖片的相似度更加可靠。

如上圖,將原始圖片劃分成5個子區域,依次計算每個子區域的顏色直方圖數據。圖片是RGB三通道,每個通道依次分成(8,3,12)個區間,那麼每個子區域顏色直方圖就可以使用8*3*12=288維向量表示。而我們又將原始圖片劃分成了5個子區域,那麼整張圖的特徵就需要用 8*3*12*5 = 1440維向量來表示了。

這裏如何計算直方圖特徵距離呢?由於這裏288維向量中每個分量代表對應區間像素出現的概率,那麼距離計算就要用到前面提到過的卡方距離。通過卡方距離公式計算兩個288維特徵向量之間的距離,從而反推原始圖片之間的相似度。
注意:使用顏色直方圖的方式提取圖像特徵的前提是:接受“如果兩張圖片顏色分佈差不多,則認爲它們相似”這一假設,這一假設不考慮圖片中具體包含內容,比如包含馬、狗、人之類的目標,而只考慮顏色。事實上,經過實踐,大部分時候該假設確實成立。

 

如何提高查詢速度

給定一個圖像特徵,如何從一堆圖像特徵中快速找到與之相同、或者與之距離最近的N個、或者與之距離在M之內的所有特徵呢?一個個的比較肯定不可接受,我們需要提前給這些特徵創建索引,提高查找的速度。

VP-Tree是一種很好的數據結構,能夠解決緊鄰搜索的問題,這裏是它的Python實現:https://github.com/RickardSjogren/vptree,它能夠先用圖像特徵構建出一個二叉樹,提高查詢速度。具體原理請參照網絡。

 

感知哈希+基於區域的顏色直方圖demo

最後有一個demo,基於圖像感知哈希(ahash、phash以及dhash)和基於區域的顏色直方圖,完成了一個簡單的圖片搜索demo。服務端採用Python、Flask開發。

源碼地址:https://github.com/sherlockchou86/cbir-image-search

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章