基于BOW模型的图像检索
我們知道,百度在圖像方面有一個強大功能——百度識圖,其基本操作就是你輸入一張圖像,百度會幫你檢索到與它相似的圖像。百度識圖其實是相同物體圖像檢索,即從圖像庫中找出包含該物體的圖像。用戶感興趣的是圖像中包含特定物體或目標,并檢索到包含該物體的那些圖像。相同物體檢索不論是在研究還是在商業圖像搜索產業中都具有重大的價值,比如做為還是學生的我,看見專賣店好看的衣服都會先拍拍照,然后取淘寶找同款,也是非常機智啦~所以,這個技術對于我們現在生活還是非常有幫助的。今天就來給大家講講基于BOW的圖像檢索技術吧,大家一起來體會一下其中的奧秘!!!
一、BOW模型
二、基于BOW的圖像檢索
1.特征提取(SIFT算法)
2.學習“視覺詞典”(K-means算法)
3.針對輸入的特征集,根據視覺詞典進行量化
4.把輸入圖像轉化成視覺單詞(visual words)的頻率直方圖
5.構造特征到圖像的倒排表,通過倒排表快速索引相關圖像
6.根據索引結果進行直方圖匹配
三、實現
1.特征提取和學習“視覺詞典”
2.創建索引,建立數據庫
?3.查詢圖像
4.web應用
四、結果分析
一、BOW模型
首先,我們就先了解一下什么是BOW模型吧!
BOW其實是Bag of words的縮寫,也叫做詞袋。BOW模型最早出現在自然語言處理和文本檢索領域。該模型忽略掉文本的語法、語序等要素,吧文檔看做若干詞匯的集合,文檔中的單詞是獨立出現的,使用一組無序的單詞(words)表達一個文檔,根據文檔中單詞的統計信息完成對文本的分類。
比如,有如下兩個文檔:
? ? ? ? ?1:Bob?likes?to?play?basketball,?Jim?likes?too.
? ? ? ? ?2:Bob?also?likes?to?play?football?games.
根據這兩個文檔,我們可以構造一個詞典:
? ? ? ? Dictionary?=?{1:”Bob”,?2.?“like”,?3.?“to”,?4.?“play”,?5.?“basketball”,?6.?“also”,?7.?“football”,?8.?“games”,?9.?“Jim”,?10.?“too”}。
這個詞典中包含10個不同的單詞,利用單詞的索引號,我們可以將上面的每個文檔都用一個10維向量表示(用0~n表示某個單詞在文檔中出現的次數,其中n為正整數):
? ? ? ? ? ? ? ? ? ? ?1:[1,?2,?1,?1,?1,?0,?0,?0,?1,?1]
? ? ? ? ? ? ? ? ? ? ?2:[1,?1,?1,?1?,0,?1,?1,?1,?0,?0]
該向量的維度是單詞的個數,值是每個單詞在文本中出現的頻率。以上的向量也可以用單詞的直方圖表示,詞表相當于直方圖的基,要表述的是文檔向這個基上映射。
并非所有的單詞都用來構建詞表,相似的單詞用一個單詞表示。例如“walk, walking,walks” 都用 “walk” 表示。一個單詞如果在所有文檔中出現,比如is,a,an等詞,那么個單詞其實對區分文檔就沒有那么重要了。反之,如果一個單詞只在一個文檔值出現,那么只要輸入的文檔有這個單詞,那么一定是屬于這個單詞所在的文檔,就是唯一的,這對于區分文檔非常重要。單詞對區分文檔的重要性通過計算單詞TF-IDF(term frequency–inverse document frequency, 詞頻-逆向文檔頻率)實現。
單詞在文檔中出現的詞頻是:
? ? ? ? ? ? ? ? ? ? ? ? ??
是單詞在文檔中出現的次數。為了歸一化,將除以整個文檔中單詞的總數。
逆向文檔頻率為:
是在語料庫中的文檔數目,分母是語料庫中包含單詞在文檔數
? ? ? ? ? ? ?
就是單詞的TF-IDF權重了,用這個來表示單詞對區分文檔的重要性。
BOW模型用于文本分類包括詞表的建立、樣本訓練、新來樣本識別三個步驟。
二、基于BOW的圖像檢索
對于兩張圖片,我們可以利用sift算法來進行特征匹配。但是面對大規模圖像特征匹配,我們不可能一個個特征匹配,因為這樣計算量是在過于龐大。比如,25000張圖像約有310億個圖相對,即使每個圖匹配只需要兩秒,也需要500臺并行計算機工作一年才可以完成,所以我們不能使用這種一個個特征匹配的暴力匹配法,需要尋找其他更快速有效的方法。
我們發現,面對大場景數據集,其實只有少于0.1%的圖像具有匹配關系,所以我們可用圖像整體特征實現匹配/檢索,而非局部特征點。所以,我們找到那個快速有效的方法——BOW模型。將BOW模型應用于圖像領域,即把圖像視為與位置無關的局部特征集合,局部特征就相當于文本中的單詞,稱為“視覺單詞”,視覺單詞的集合稱為“視覺詞典”(也叫碼本)。
圖像檢索的基本流程是:
①特征提取(SIFT算法)
②學習“視覺詞典(visual vocabulary)”(k-means算法)
③針對輸入的特征集,根據視覺詞典進行量化
④把輸入圖像轉化成視覺單詞(visual words)的頻率直方圖
⑤構造特征到圖像的倒排表,通過倒排表快速索引相關圖像
⑥根據索引結果進行直方圖匹配
接下來,我們來具體了解一下每一步做什么吧!!!
1.特征提取(SIFT算法)
特征提取就是從圖像中提取出關鍵點(或特征點、角點)等,我們在這里采用的SIFT算法。SIFT算法用來偵測與描述影像中的局部特征,它在空間尺度中尋找極值點,并提取出其位置、尺度、旋轉不變量。此算法由David Lowe 在1999 年所發表,2004 年完善總結。SIFT 算法的實質是在不同的尺度空間上查找關鍵點( 特征點),并計算出關鍵點的方向。SIFT 所查找到的關鍵點是一些十分突出,不會因光照,仿射變換和噪音等因素而變化的點,如角點、邊緣點、暗區的亮點及亮區的暗點等。SIFT 算法在構建好的尺度空間的基礎上搜索尺度空間中的極值點( 特征點),然后確定極值點的尺度信息以及位置,再確定極值點的方向( 其鄰域梯度的主方向),最終可以得到具有魯棒性的128 維(4*4*8) 的特征向量。SIFT具體原理和實現參見我另一篇博客,這里我就不再重復贅述啦。傳送門https://blog.csdn.net/qq_40369926/article/details/88597406
利用SIFT算法提取出訓練圖片的示意圖如下:
舉個例子,假如現在有3 張訓練圖片:人臉、自行車、小提琴,如下圖所示:
對每一張訓練圖片都提取SIFT 的128 維特征,那么最終可以得到 M = N1+N2+N3 個128 維的特征,Ni 代表第i 張圖特征點的個數,如下圖所示:
2.學習“視覺詞典”(K-means算法)
前面已經說過了,面對大場景數據集,只憑特征匹配,由于計算時間過長,是不可能實現圖像檢索的。所以我們想到了將相似的特征向量聚到一起,用一個視覺單詞來表示這些特征,就像文本中用“walk”來表示“walk, walking,walks” 一樣。我們采用的算法是K-means算法。
k-means算法是一種基于樣本間相似性度量的間接聚類方法,屬于非監督學習方法。
? ? ? ? 輸入:聚類個數k,圖像的特征集合。
? ? ? ? 輸出:滿足方差最小標準的k個聚類。
最小化每個特征 與其相對應的聚類中心 之間的歐式距離。
算法流程是:
① 隨機初始化 K 個聚類中心?
②重復下述步驟直至算法收斂
? ? ? ? 對應每個特征,根據距離關系賦值給某個中心/類別(計算每個特征點到聚類中心的距離,將特征點分給離其最近的聚類中心,視為屬于類,這里采用的距離是歐式距離。)
? ? ? ? 對每個類別,根據其對應的特征集重新計算聚類中心
k-means算法的流程示意圖如下:
k-means算法是實現視覺詞典(碼本)的關鍵,我們將K-means 算法獲取的聚類中心作為視覺單詞(碼本向量)。當訓練集準備足夠充分是,訓練出的碼本將具有普適性。
需要注意的是如何選擇視覺詞典/碼本的規模,太少會出現視覺單詞無法覆蓋所有可能出現的情況;太多又會計算量大,容易過擬合。
就之前的例子而言就是將下述這特征向量進行聚類,將之前的特征向量轉化為4個視覺單詞,以此來作為視覺詞典。
3.針對輸入的特征集,根據視覺詞典進行量化
對于文本而言,當一個單詞在所有文本都出現那么這個單詞就不能區分文本。同理,如果一個視覺單詞在每個圖像中都出現,那么這個視覺單詞就不能區分圖像了。類比文本,我們這里也采用TF-IDF權重來表示視覺單詞對區分圖像的重要程度。
4.把輸入圖像轉化成視覺單詞(visual words)的頻率直方圖
統計詞表中每個單詞在圖像中出現的次數,將圖像表示為K 維數值向量。上例中,可以將圖像表示成為一個K=4 維數值向量:
人臉:[3,30,3,20]
自行車:[20,3,3,2]
小提琴:[8,12,32,7]
每幅圖的視覺單詞與詞頻直方圖如圖下圖所示:
5.構造特征到圖像的倒排表,通過倒排表快速索引相關圖像
前幾步是通過圖像來提取視覺單詞,用視覺單詞的詞頻直方圖來表示圖像,是通過圖像映射視覺單詞。而倒排表是通過視覺單詞映射圖像。
比如,對于下述兩個文本而言:
? ? ? ? 1:Bob?likes?to?play?basketball,?Jim?likes?too.
? ? ? ? ?2:Bob?also?likes?to?play?football?games.
之前是:
? ? ? ? ?1:[? “Jim”, “too”]
? ? ? ? ?2:[“also”,?“football”,?“games”,]
經過倒排后是:
? ? ? ? “Jim”:[1]
? ? ? ? “too”:[1]
? ? ? ?“also”:[2]
? ? ? ?“football”:[2]
? ? ? ?“games”:[2]
對于圖像來說,經過倒排后,就是視覺單詞:[視覺單詞所出現的圖像集合]。倒排表可以快速使用反轉文件來計算新圖像與數據庫中所有圖像之間的相似性,僅考慮其分檔與查詢圖像重疊的數據庫圖像,大大減少了匹配次數,優化了算法。
常規查詢是利用歐氏距離對結果排序,但是實際上這樣容易出現偶然現象,所以我們用RANSAC模型進行優化,該模型的具體介紹可以參考我另一篇博客,傳說門:https://blog.csdn.net/qq_40369926/article/details/88918489
6.根據索引結果進行直方圖匹配
根據索引結果建立直方圖,就可以得出最后的匹配結果了。
三、實現
1.特征提取和學習“視覺詞典”
# -*- coding: utf-8 -*- import pickle from PCV.imagesearch import vocabulary from PCV.tools.imtools import get_imlist from PCV.localdescriptors import sift ###創建詞匯#獲取圖像列表 imlist = get_imlist('D:/test/first1000/') nbr_images = len(imlist) #獲取特征列表 featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]#提取文件夾下圖像的sift特征 for i in range(nbr_images):sift.process_image(imlist[i], featlist[i])#生成詞匯 voc = vocabulary.Vocabulary('ukbenchtest')#創建詞匯類 voc.train(featlist, 1000, 10)#單詞數為1000,進行k-means訓練#保存詞匯 with open('D:/test/first1000/vocabulary.pkl', 'wb') as f:pickle.dump(voc, f) print ('vocabulary is:', voc.name, voc.nbr_words)上述代碼是先對圖像集進行SIFT特征提取,然后再用K_means算法生成視覺單詞,這里設置的K=1000,也就是說會生成1000個視覺單詞。
2.創建索引,建立數據庫
# -*- coding: utf-8 -*- import pickle from PCV.imagesearch import imagesearch from PCV.localdescriptors import sift from sqlite3 import dbapi2 as sqlite from PCV.tools.imtools import get_imlist###圖像索引#獲取圖像列表 imlist = get_imlist('D:/test/first1000/') nbr_images = len(imlist) #獲取特征列表 featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]#載入詞匯 with open('D:/test/first1000/vocabulary.pkl', 'rb') as f:voc = pickle.load(f) #創建索引 indx = imagesearch.Indexer('testImaAdd.db',voc)#創建索引器Indexer類 indx.create_tables()#遍歷所有的圖像,并將它們的特征投影到詞匯上 for i in range(nbr_images)[:1000]:locs,descr = sift.read_features_from_file(featlist[i])indx.add_to_index(imlist[i],descr)#提交到數據庫 indx.db_commit()con = sqlite.connect('testImaAdd.db') print (con.execute('select count (filename) from imlist').fetchone()) print (con.execute('select * from imlist').fetchone())?3.查詢圖像
# -*- coding: utf-8 -*- import pickle from PCV.localdescriptors import sift from PCV.imagesearch import imagesearch from PCV.geometry import homography from PCV.tools.imtools import get_imlist#載入圖像列表 imlist = get_imlist('D:/test/first1000/') nbr_images = len(imlist) #載入特征列表 featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]#載入詞匯 with open('D:/test/first1000/vocabulary.pkl', 'rb') as f:voc = pickle.load(f)src = imagesearch.Searcher('testImaAdd.db',voc)#查詢圖像索引和查詢返回的圖像數 q_ind = 0 nbr_results = 20# 常規查詢(按歐式距離對結果排序) res_reg = [w[1] for w in src.query(imlist[q_ind])[:nbr_results]] print ('top matches (regular):', res_reg)#載入查詢圖像特征 q_locs,q_descr = sift.read_features_from_file(featlist[q_ind]) fp = homography.make_homog(q_locs[:,:2].T)#用單應性進行擬合建立RANSAC模型 model = homography.RansacModel() rank = {}#載入候選圖像的特征 for ndx in res_reg[1:]:locs,descr = sift.read_features_from_file(featlist[ndx]) # because 'ndx' is a rowid of the DB that starts at 1#獲取匹配數matches = sift.match(q_descr,descr)ind = matches.nonzero()[0]ind2 = matches[ind]tp = homography.make_homog(locs[:,:2].T)# 計算單應性,對內點計數,若果沒有足夠的匹配數則返回空列表try:H,inliers = homography.H_from_ransac(fp[:,ind],tp[:,ind2],model,match_theshold=4)except:inliers = []# 存儲內點數rank[ndx] = len(inliers)#將字典排序,以有限獲取最內層的內點數 sorted_rank = sorted(rank.items(), key=lambda t: t[1], reverse=True) res_geom = [res_reg[0]]+[s[0] for s in sorted_rank] print ('top matches (homography):', res_geom)# 顯示查詢結果 imagesearch.plot_results(src,res_reg[:8]) #常規查詢 imagesearch.plot_results(src,res_geom[:8]) #重排后的結果這里我們用常規查詢和優化查詢進行對比。
4.web應用
除了在python里顯示查詢結果,我們還可以利用CherryPy將圖像傳遞到URL中,在網頁中查詢圖像并顯示結果。
# -*- coding: utf-8 -*- import cherrypy import pickle import urllib import os from numpy import * #from PCV.tools.imtools import get_imlist from PCV.imagesearch import imagesearch import random""" This is the image search demo in Section 7.6. """class SearchDemo:def __init__(self):# 載入圖像列表self.path = 'D:/test/first1000/'#self.path = 'D:/python_web/isoutu/first500/'self.imlist = [os.path.join(self.path,f) for f in os.listdir(self.path) if f.endswith('.jpg')]#self.imlist = get_imlist('./first500/')#self.imlist = get_imlist('E:/python/isoutu/first500/')self.nbr_images = len(self.imlist)print (self.imlist)print (self.nbr_images)self.ndx = list(range(self.nbr_images))print (self.ndx)# 載入詞匯# f = open('first1000/vocabulary.pkl', 'rb')with open('D:/test/first1000/vocabulary.pkl','rb') as f:self.voc = pickle.load(f)#f.close()# 顯示搜索返回的圖像數self.maxres = 10# header and footer htmlself.header = """<!doctype html><head><title>Image search</title></head><body>"""self.footer = """</body></html>"""def index(self, query=None):self.src = imagesearch.Searcher('testImaAdd.db', self.voc)html = self.headerhtml += """<br />Click an image to search. <a href='?query='> Random selection </a> of images.<br /><br />"""if query:# query the database and get top images#查詢數據庫,并獲取前面的圖像res = self.src.query(query)[:self.maxres]for dist, ndx in res:imname = self.src.get_filename(ndx)html += "<a href='?query="+imname+"'>"html += "<img src='"+imname+"' alt='"+imname+"' width='100' height='100'/>"print (imname+"################")html += "</a>"# show random selection if no query# 如果沒有查詢圖像則隨機顯示一些圖像else:random.shuffle(self.ndx)for i in self.ndx[:self.maxres]:imname = self.imlist[i]html += "<a href='?query="+imname+"'>"html += "<img src='"+imname+"' alt='"+imname+"' width='100' height='100'/>"print (imname+"################")html += "</a>"html += self.footerreturn htmlindex.exposed = True#conf_path = os.path.dirname(os.path.abspath(__file__)) #conf_path = os.path.join(conf_path, "service.conf") #cherrypy.config.update(conf_path) #cherrypy.quickstart(SearchDemo())cherrypy.quickstart(SearchDemo(), '/', config=os.path.join(os.path.dirname(__file__), 'service.conf'))通過這個代碼,就可以在網頁中顯示圖像,但是需要注意的是,我們需要鞋業個配置文件,用于開啟CherryPy Web服務器。配置文件內容如下:
[global] server.socket_host = "127.0.0.1" server.socket_port = 8080 server.thread_pool = 50 tools.sessions.on = True [/] tools.staticdir.root = "D:/test/first1000" tools.staticdir.on = True tools.staticdir.dir = ""四、結果分析
實驗采用的是100張500x500的jpg圖像,一共有20類,包括人像、動物、植物、風景、物品等,背景也有簡單和復雜的。
實驗結果如下:
從實驗結果可以看出,第一組、第五組和第六組的檢索結果最為理想,前五張圖像均是輸入圖像的相似圖像,而第二組、第三組的檢索結果前三張是相似圖像,其他相似圖像則排在五張以后,什么前十張之外。而第六組結果最不理想,只有第一張屬于相似圖像,剩下的全是與之不相似的圖像。分析其原因是第一組圖像的毛毛蟲構圖相對簡單,提取出來的視覺單詞數量少。在倒排表中,該視覺單詞所包含的圖像集合的元素少,區分度大。而第六組圖像的阿拉蕾構圖復雜,提取出來的視覺單詞較多。在倒排表中,視覺單詞包含的圖像集合元素多,而且視覺單詞數量多,因而在最后形成的直方圖中,與其完全不相關的圖像會因為視覺單詞重合度大,而被排在前面,造成了輸入阿拉蕾,檢測出埃菲爾鐵塔的結果。實驗出現這樣效果的根本原因是數據庫圖像數目不夠多,因而類間差距不夠大,類內聯系不夠緊密,如果擴大圖像庫規模,會效果更好。
參考:[1]汪弋琛.基于BOW模型的相似圖像分類檢索方法[J].電子技術與軟件工程,2017(21):64-65.
總結
以上是生活随笔為你收集整理的基于BOW模型的图像检索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 快播
- 下一篇: 实现QQ主界面效果[图]