讀古今文學網 > 刷臉背後:人臉檢測 人臉識別 人臉檢索 > 7.9 用於圖像快速檢索的KD-Tree索引 >

7.9 用於圖像快速檢索的KD-Tree索引

在圖像和視頻處理領域中,數據通常是高維的,此時,最相似K近鄰的查找非常費時。圖像處理領域的研究人員經常使用KD-Tree查找與輸入圖像的特徵相似的圖像。KD-Tree能夠大大節省K近鄰查找的運行時間,是高維度特徵相似性檢索不可或缺的利器。本書中使用FLANN庫,它是最完整的近鄰查詢算法的開源庫,包含KD-Tree的實現。在本章中,我們僅使用了flann::Index_::radiusSearch,其根據給定的查詢數據,執行基於半徑的最近鄰檢索。

7.9.1 FLANN算法的使用

該算法的運行環境是在Linux下的Ubuntu系統,使用命令行來運行。從https://github.com/jlblancoc/nanoflann中下載FLANN算法的源碼[9],按照下載文檔中的readme.txt文檔編譯.cpp文件。其中pointcloud_kdd_radius.cpp是關鍵,我們已經將所想實現功能的代碼放入pointcloud_kdd_radius.cpp中。打開命令窗口,進入「/nanoflann-master/nanoflann-master/build/bin」路徑,運行pointcloud_kdd_ radius.cpp文件即可。

7.9.2 KD-Tree的創建與查詢處理

KD-Tree的創建:找出數據集中方差最高的維度ki,在ki維度上選擇中值並將本維度上的數據劃分為兩部分,此時我們得到兩個子集合,同時創建了一個樹節點,接著再對兩個子集重複上述過程,直到所有子集合都不能再劃分為止,此時子集中的數據保存在葉子節點。

但是我們為什麼會選中數據集中方差最大的維度呢?我們舉個簡單的例子。現在要切一根躺著的木條,按照「輪著來」的方法先豎著切一刀,木條一分為二,接下來就是橫著切一刀,這時候就有點考驗刀法了,如果木條的直徑(橫截面)較大,還可以輕鬆下手;如果木條的直徑很小,就沒有辦法切了。因此,如果k維數據的分佈像一塊正方體的豆腐一樣,「輪著來」的切分法可能還是奏效的,但是如果k維度的數據分佈像木條一樣,「輪著來」就不好用了。我們想像一下,k維數據集合的分佈像木條一樣,也就是說這些數據在木條較長方向上的維度比較大,在該方向維度上的方差比較大,數據分散得比較開,因此我們就更容易在這個數據維度上將它們劃分開。於是,這就引出了我們選擇維度的另一種方法——最大方差法,即每次我們選擇方差最大的維度進行劃分。

在OpenCV中,KeyPoint Matching的方法有Brute-force matcher(簡單粗暴匹配),用暴力方法找到點集中每一個descriptor(描述符)與已知點距離最近的descriptor(描述符);而Flann-based matcher 使用快速近似最近鄰檢索方法查詢。

KD-Tree的查詢基於深度檢索。首先從根開始,進行深度檢索並不斷記錄、更新當前最近節點,並將錯過的節點置於優先隊列中,直到遍歷到葉子節點,此時再從隊列中取出目前ki維度上距離最小的節點,然後重複上述過程,遍歷至葉子節點,直到優先隊列為空,或迭代次數超過200遍時停止。

7.9.3 FLANN中KD-Tree的算法實現

下面給出了FLANN中實現的KD-Tree算法。確定K近鄰的個數時,它主要依據的是查詢半徑參數,即radiusSearch函數。

7.9.4 FLANN算法的實驗數據、實驗結果及分析

image圖像集的說明:以其中一些圖像的名稱為例,「s001-001.jpg」就代表第一個人的第一幅圖像,「s001-002.jpg」就表示第一個人的第二幅圖像,「s002-001.jpg」代表第二個人的第一幅圖像,以此類推。

1.實驗數據

圖像集image文件中的497幅圖像經過深度學習提取得到的圖像特徵(保存在.txt文件中,其中每一行代表一幅圖像的特徵)。

2.實驗結果

下面的圖片是我們所做實驗的截圖(見圖7-9、圖7-10)和代碼運行結果顯示(見圖7-11)。其中運行結果顯示中,每一行的三個參數分別代表索引號、圖像文件名、與檢索圖像之間的距離。

查詢圖像如圖7-9所示。

圖7-9 查詢圖像(5)

檢索出的部分相似圖像如圖7-10所示。

圖7-10 檢索出的部分相似圖像(5)

圖7-11 代碼運行結果顯示

3.實驗分析

我們可以從實驗結果的截圖中看到,我們使用的radius(半徑)的閾值為77.6,匹配到38幅圖像,其中匹配到的圖像中有35幅是我們想要查找到的,有3幅不是我們想要的,另外還有7幅圖像沒有匹配出來。因此,查准率為35/38×100%=92.1%,查全率為35/42×100%=83.3%。