計算機視覺(八)——基於BOW的圖像檢索

Bag Of Word原理簡述

Bag Of Word(詞袋)模型,是現在一種用於圖像檢索的一種方法。它最早用於對於文章內容的檢索,原理是將文本看作是單詞的集合,不考慮其中的語法,上下文等等。通過建立詞典,對每個單詞出現次數進行統計,以便得到文本內容的分類。計算機視覺的專家從中獲得靈感,將其用於圖像的檢索中,就有了Bag Of Features(原理類似Bag of word)。

Bag Of Features實現圖像檢索的簡單步驟

1.特徵提取
2.學習“視覺詞典”(visual vocabulary)
3.針對輸入特徵集,根據視覺詞典進行量化
4.把輸入圖像,根據TF-IDF轉化成視覺單詞( visual words)的頻率直方圖
5.構造特徵到圖像的倒排表,通過倒排表快速 索引相關圖像
6.根據索引結果進行直方圖匹配

1.特徵提取

之前的課程之中學習了關於特徵提取的幾個方式,例如sift,Harris腳點。這裏我們通過sift來提取圖像的特徵點。類似BOW,我們將圖像看成一個由各種圖像塊組成的集合,通過特徵提取,獲得圖像的關鍵圖像特徵。如圖
在這裏插入圖片描述

2.學習“視覺詞典”(visual vocabulary)

通過步驟1,我們獲得了多張圖像的特徵點。這些特徵提取出來,並沒有通過分類處理,其中有的特徵點之間是極其相似,所以這一步驟通過K-means聚類算法,將我們提取出來的特徵點進行分類處理。
算法的簡單流程:

  • 隨機初始化 K 個聚類中心
  • 重複下述步驟直至算法收斂:
    • 對應每個特徵,根據距離關係賦值給某個中心/類別
    • 對每個類別,根據其對應的特徵集重新計算聚類中心

聚類是學習視覺詞典的重點操作。將聚類出來的聚類中心稱爲視覺單詞(codevector)。而將視覺單詞組成的集合稱爲視覺詞典/碼本(codebook)
這裏我們需要注意一個問題,關於碼本的大小。

  • 如果我們做出來的碼本規模太小, 就會出現,我們的視覺單詞不能包括所有可能的情況。
  • 相反的,如果我們做出來的碼本規模過大,會使得計算量增加,且有過擬合現象出現。

例如,這張圖像表示通過特徵提取出來的特徵集合,涵蓋了所有的特徵。
在這裏插入圖片描述
通過學習之後,就剩下了幾個特徵作爲視覺單詞
在這裏插入圖片描述

3.針對輸入特徵集,根據視覺詞典進行量化

這一步驟將我們輸入的特徵集合,映射到上一步做來的碼本之中。通過計算輸入特徵到視覺單詞的距離,然後將其映射到距離最近的視覺單詞中,並計數。

4.把輸入圖像,根據TF-IDF轉化成視覺單詞( visual words)的頻率直方圖

這一步驟通過對圖像特徵提取,然後將提取出來的特徵點,根據第三步,轉換爲頻率直方圖。如圖所示
在這裏插入圖片描述
這裏在轉換爲頻率直方圖時候,有使用到TF-IDF,即詞頻(Term Frequency,TF)與逆文檔頻率(Inverse Document Frequency,IDF)乘積作爲權值。引入這個權值的目的是爲了降低一些重複特徵所帶來的影響。比如在BOW中,一些常用詞彙譬如the,it,do等等詞彙,不能體現文本內容特徵,但是出現頻率卻很高,利用tf-idf可以降低這種不必要詞彙的影響。同理,在BOF圖像搜索中,圖像之間也會有這樣的無意義的特徵出現,所以需要降低這類特徵的權值。
在這裏插入圖片描述
其中分子表示某個特徵在總的特徵出現的次數,分母表示總特徵的數量,所以tf表示某個特徵出現的頻率。
在這裏插入圖片描述
其中的分子表示全部的圖像數量,分母表示某個特徵在總的圖像下出現的次數。再對其取對數,就是IDF。

5.構造特徵到圖像的倒排表,通過倒排表快速 索引相關圖像

倒排表是一種逆向的查找方式,在BOW中大體的思路是通過已經提取出來的詞彙,反向查找出現過這個詞彙的文章。如圖,查找多個詞彙,就形成了一個倒排表。
在這裏插入圖片描述
BOF中倒排表也是同理。通過對視覺詞彙的反向查找,就會得到擁有同一視覺詞彙的圖像集合,反覆多次就能得到一張倒排表。倒排表可以快速的得到新的圖像與數據庫裏相似的圖像。

6.根據索引結果進行直方圖匹配

當我們做完上面的步驟,就需要對直方圖進行匹配。直方圖的匹配給出輸入圖像的頻率直方圖,在數據庫中查找K個最近鄰的圖像,根據這K個近鄰來投票圖像的分類結果。

代碼實現

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('E:/BaiduNetdiskDownload/PCV-book-data/data/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)
#保存詞彙
# saving vocabulary
with open('E:/BaiduNetdiskDownload/PCV-book-data/data/first1000/vocabulary.pkl', 'wb') as f:
    pickle.dump(voc, f)
print 'vocabulary is:', voc.name, voc.nbr_words

這裏的圖像使用的是first1000(肯塔基大學物體識別數據集前1000幅圖像)。生成了圖像的sift文件和碼本
在這裏插入圖片描述

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('./first1000/')
nbr_images = len(imlist)
#獲取特徵列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]

# load vocabulary
#載入詞彙
with open('./first1000/vocabulary.pkl', 'rb') as f:
    voc = pickle.load(f)
#創建索引
indx = imagesearch.Indexer('testImaAdd.db',voc)
indx.create_tables()
# go through all images, project features on vocabulary and insert
#遍歷所有的圖像,並將它們的特徵投影到詞彙上
for i in range(nbr_images)[:500]:
    locs,descr = sift.read_features_from_file(featlist[i])
    indx.add_to_index(imlist[i],descr)
# commit to database
#提交到數據庫
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

# load image list and vocabulary
#載入圖像列表
imlist = get_imlist('./first1000/')
nbr_images = len(imlist)
#載入特徵列表
featlist = [imlist[i][:-3]+'sift' for i in range(nbr_images)]

#載入詞彙
with open('./first1000/vocabulary.pkl', 'rb') as f:
    voc = pickle.load(f)

src = imagesearch.Searcher('testImaAdd.db',voc)

# index of query image and number of results to return
#查詢圖像索引和查詢返回的圖像數
q_ind = 0
nbr_results = 20

# regular query
# 常規查詢(按歐式距離對結果排序)
res_reg = [w[1] for w in src.query(imlist[q_ind])[:nbr_results]]
print('top matches (regular):', res_reg)

# load image features for query image
#載入查詢圖像特徵
q_locs,q_descr = sift.read_features_from_file(featlist[q_ind])
fp = homography.make_homog(q_locs[:,:2].T)

# RANSAC model for homography fitting
#用單應性進行擬合建立RANSAC模型
model = homography.RansacModel()
rank = {}

# load image features for result
#載入候選圖像的特徵
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
    # get matches
    matches = sift.match(q_descr,descr)
    ind = matches.nonzero()[0]
    ind2 = matches[ind]
    tp = homography.make_homog(locs[:,:2].T)
    # compute homography, count inliers. if not enough matches return empty list
    try:
        H,inliers = homography.H_from_ransac(fp[:,ind],tp[:,ind2],model,match_theshold=4)
    except:
        inliers = []
    # store inlier count
    rank[ndx] = len(inliers)

# sort dictionary to get the most inliers first
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]) #重排後的結果

通過常規查詢和用單應性進行擬合建立RANSAC模型進行查詢的結果如下

  • 常規查詢
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 用單應性進行擬合建立RANSAC模型進行查詢
    在這裏插入圖片描述
    在這裏插入圖片描述
    可以看出這兩種的查詢結果並不完全一致,但是在查詢出來的前幾張圖像都是一致的。

實驗小結

在運行第三個代碼出現這樣的錯誤,一直沒有解決,當時不影響結果的產生,希望有知道的大佬,能告知解決方法
在這裏插入圖片描述

如果您在閱讀之中發現文章錯誤之處或者出現疑問,歡迎在評論指出
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章