由於相機正面白攝物體時,相機的光軸方向可能發生變化,帶來扭曲。而SIFT算法雖具有完全的尺度不變性,但不具有完全的仿射不變性,對拍攝角度發生大角度空間變化的圖像特征提取有一定的局限性。ASift通過模擬經度與緯度實現完全的仿射不變,然后用SIFT算法把模擬圖像進行比較,最后實現特征匹配。
ASIFT算法的具體步驟如下:
1.選取采樣參數,模擬不同經度與緯度的圖像。
2.計算模擬圖像的特征。
3.結合所有的模擬圖像的特征,進行特征匹配。
注意:ASIFT提供的一種框架,其核心思想是模擬不同的經度與緯度的圖像,具體模擬圖像的特征提取和匹配,可選擇SIFT、SURF等特征。
ASIFT算法代碼資源:
http://www.ipol.im/pub/art/2011/my-asift/
https://github.com/Itseez/opencv/blob/master/samples/python2/asift.py
OpenCV只提供python實現的asift,如果需要在C++中使用asift,主要有兩種方法可參考。
1.利用作者提供的C++代碼,具體使用方法可參考作者提供的文檔。
2.將asift.py翻譯成C++代碼。
asift.py代碼相對清晰,轉換成基於OpenCV的C++代碼比較容易,我主要參用方法2,實現ASIFT算法。
遇到的問題:
1.處理分辨率較大圖片時,出現OpenCV Error: Insufficient memory的錯誤。
經分析,計算過程需要保存多張模擬圖片的特征點和特征描述子,需要大量內存,導致OpenCV分配內存時,沒有連續可用的內存塊,從而出現OpenCV Error: Insufficient memory的錯誤。
解決方法:降低待處理圖片的分辨率,並計算高分辨率到低分辨率轉換的單應性矩陣scaleH。利用ASift算法計算低分辨率圖片的匹配的單應性矩陣matchH。最終待處理圖片的單應矩陣H=matchH*scaleH。
2.計算復雜度問題。
由於需要處理多幅模擬圖片的特征點檢測,計算復雜度高。目前,主要有兩種思路:1).降低分辨率,減少計算量。2).利用硬件特性進行硬件計算。
ASift作者在文中提到的Two-Resolution Procedure.
(1).采用系數K*K二次采樣查詢圖片u和待搜索圖片v。u = SkGku,v=SkGkv,Gk是反走樣高斯離散濾波器,SK為K*K二次采樣。
(2).低分辨率下的ASIFT算法:對查詢圖片u和搜索圖片應用ASIFT算法;
(3).確定u和v中可能產最多匹配對的M種仿射變換;
(4).高分辨率下的ASIFT算法:在原始圖像u和v上使用ASIFT算法,但模擬傾科時只使用這M種仿射變換。
經實驗測試,發現Two-Resolution Procedure雖然可以在一定降低復雜度,但其對匹配精度會有一定的影響,對於匹配精度要求高的應用不太合適。
Asift.py中,利用線程池加速多幅圖像的特征點檢測,使得多幅圖像的特征點檢測同時進行。
結合多線程的思想,我利用每個線程,計算每幅圖像的特征點的檢測,結果遇到內存不足的問題。
主要原因:特征點檢測過程需要內存空間存儲部分中間結果,當多線程同時計算時,所需內存增大,出現內存不足的問題。
解決方法:可以根據待處理圖片的分辨率大小和系統提供內存資源的多少,自適應確定多線程的數目。
利用GPU加速ASIFT計算,具體步驟如下:
(1).將待處理圖片傳輸到GPU端。
(2).將待處理圖片模擬變換,得到模擬圖片,AffineImage_Kernel。
(3).計算模擬圖片的特征點,KeyPointsDetect_Kernel。
(4).將計算所得的特征點數據傳輸到CPU端。
(5).循環處理(2)、(3)、(4)步驟,直到所有模擬變換處理完。
(6).在CPU端完成特征點匹配計算。
注意:(4)與(5)可以異步執行,重疊計算與特征點數據傳輸的時間。
基於GPU特征點計算主要參考:
SiftGPU: http://cs.unc.edu/~ccwu/siftgpu/
CudaSift: https://github.com/Celebrandil/CudaSift
注意:經測試,發現SiftGPU和CudaSift檢測出的特征點數目與OpenCV的SiftFeatureDetector檢測出特征點數目差異較大。
