從OpenCV源碼學習match()和knnMatch()進行雙目匹配

寫在前面的話:最近做雙目匹配,需要用到OpenCV的特徵識別匹配,但是對於低反射率物體即使投影了隨機散斑之後出來的效果依舊很差,於是乎看看特徵匹配的源碼,看看能不能從原理上有所發現(用的knnMatch並且已經極線對準,可是效果在有的圖上比較涼涼)。廢話不多說,這篇博文講的是看源碼學習OpenCV,彷彿沒找到比較好的文章,於是,自己看,寫一個。後續有發現的話在後面補充。環境:OpenCV3.2源碼,VS2013(爲什麼不用新的?公司要求啊。。。要求統一環境)

//其實很早就該寫了,但是考慮到科研可能要用這個改匹配算法,就先沒寫,後來改用了別的方案,匹配效果遠比這個方法好。這篇博文講的是這個算法的組織,以及可以根據學習結果改一改匹配函數用來針對性提升效果。所以默認讀者是會用的。事實證明只用OCV自己的庫只能滿足玩一玩的需求,距離應用還有很大距離。

先看看OpenCV的官方文檔

這裏用的OpenCV3.3的文檔,爲什麼不用3.2的文檔?因爲我之前用3.3後來被迫換3.2,於是乎懶得下3.2文檔,畢竟基本都一樣,發現不對的話再去查,這裏懶一下,其實這麼做是不對的。(反正是實習,隨便玩哈哈哈*2333)看文檔有助於看懂源碼,尤其是理清類之間的關係。

在這裏插入圖片描述

基類的方法,這裏主要要看的是箭頭標記的那倆,因爲這倆是我要用的。發現這個DescriptorMatcher是個抽象的基類,後面有倆子類,實際上我們在用的時候也是用的後面倆,分別是BFMatch和FlannBasedMatcher。

在這裏插入圖片描述

在這裏插入圖片描述

上面是match()的文檔,看不清可以去文檔官網一大把doc,各種版本都有哈,我習慣下下來看,比較方便,一樣的。

在這裏插入圖片描述

再看看knnMatch()的文檔,嗯。好了不解釋了,很簡單的英文。match()匹配點對,knnMatch()返回每個點的k個匹配點,所以感覺knnMatch給的選擇更多一點,而且給出候選點更可能包含真正的匹配點(事實就是這樣的,後面說)

在源碼裏找到match()的實現:
在這裏插入圖片描述

發現match()實際上調用就是knnMatch()把返回k個的匹配包了一層皮,設置返回一個最匹配的點。所以重點就一個knnMatch()就完了。我們轉到定義,去看看knnMatch()發現:
在這裏插入圖片描述

使用時候用的API:BFMatch和FlannBasedMatcher

看一眼源碼發現knnMatch()第一個調用的是第二個重載的knnMatch()(猜也猜得到)然後有調用的DescriptorMatcher: :knnMatchImpl()在兩個基類的實現,於是乎vs go to define時候有:BF還是FLANN,也就是說上面說過的兩個子類要分別實現父類:DescriptorMatcher的方法了(順便看一下大佬寫C++,學學經驗)我goto到了BFMatcher::knnMatchImpl()。這個方法分別在兩個子類裏面實現了。這個基類是沒有實現的。

忽略掉一堆爲了安全機制和指令集還有工程上的那堆雜七雜八的成熟的考慮,比如一堆宏和條件編譯。看重點,判斷兩個向量的匹配度還不是要算距離函數,什麼歐氏距離、餘弦距離、漢明距離…
在這裏插入圖片描述

找到了計算距離函數的地方,這裏默認歐氏距離了(看默認參數)。然後去找找文檔。文檔裏沒有給匹配函數指定距離函數的參數,其實在構造器構造函數裏:
在這裏插入圖片描述

也是默認構造用的歐氏距離,讀者有興趣可以試試別的距離函數,

enum NormTypes { NORM_INF       = 1,
                 NORM_L1        = 2,
                 NORM_L2        = 4,
                 NORM_L2SQR     = 5,
                 NORM_HAMMING   = 6,
                 NORM_HAMMING2  = 7,
                 NORM_TYPE_MASK = 7,
                 NORM_RELATIVE  = 8, //!< flag
                 NORM_MINMAX    = 32 //!< flag
               };

在這裏插入圖片描述

文檔裏有對NormTypes的公式定義,很清晰,宏分別對應什麼距離函數一清二楚。但是這是有問題的,一會看下面。

在這裏插入圖片描述
在core/stat.cpp裏實現的距離計算。(字體突然變了?換成了VS2017,2013版的go to def找不到,17版這些方面還有實時看資源佔用是真的方便。。想用17。。。)可以看到源碼對於CV_8U還是很友好的,實現了不少,對於CV_32F只實現了三種,說好的那麼多NormType。當然這裏我們看到的可能不一樣,我不記得我是不是改過源碼,印象中至少其他部分我改過,改完應該會有我的標記的,畢竟過去接近一年了,壞習慣。紅色剪頭是crosscheck的實現,一個自我調用,參數取false就完成了,這個操作天秀啊(對於當時我這個沒見過世面的菜雞來說。現在習慣了)。

如果想要修改匹配規則,按照源碼的佈局,在你的工程裏複製大部分BFMatch的源碼,照葫蘆畫瓢改就可以了,對於CV_32F,我嘗試了不同的距離函數,也可以自定義距離運算。這裏貼出來:
在這裏插入圖片描述

這樣就可以自己隨心所欲地修改匹配規則了。詳細的就不貼了,最後。我放棄了OpenCV的匹配規則(嘗試實現了源碼沒有實現的方法,發現還是NORM_L2穩定可靠,尷尬,因爲浮點數乘除太容易出現問題了),而是採用純數學計算和圖像處理的方法。如果文章錄的話,我把文章再貼這。不過文章也沒有描述的很詳細,領導不讓寫詳細,攤手。照葫蘆畫瓢,Flann也能自己看懂了。不過建議先找文章和文檔看,不然直接上手源碼還是有壓力的,看完文章和文檔可能還有不清楚的,這時候源碼描述的一清二楚。先寫到這裏,我寫博客真隨意。

補充內容(雙目視覺:提升點匹配的匹配效果(針對密集點匹配情況)):

原理說明

當圖像中同一點周圍有多個特徵向量時。比如座標點p(10,10)提取了特徵向量,同時座標點p2(10,11)和點p3(11,10)等附近點同樣提取到特徵向量。那麼原則上另一幅圖像的對應正確匹配點和上述點的計算“距離”,應當是相近的。

具體實現

這裏就用到了上面的內容,只有在源碼裏可以隨意修改。看源碼可以知道下圖的dist存儲的實際是排序好的特徵向量距離,以NORM_L2爲例:
在這裏插入圖片描述
然後最後得到的排序好的相似度排序可以得到:
(這裏是自己畫出來的展示圖,是行匹配時候,左圖一行在右圖對應的查找出來的匹配點。在ImageWatch裏面看,VS2017可用的ImageWatch可以在我上傳的資源找。下圖的一行就是對於某一個點,在右圖的候選點的計算結果,舉個例子:第一行就是對於左圖某一點,在右圖候選點的相關度計算結果,每個像素存儲的就是一個點的相關度)
在這裏插入圖片描述
再稍微解釋下:像素的第一個通道是匹配點所在列(雙目匹配,相機經過標定,且經過極線校正。我感覺這部分這裏就不說了,網上也挺多的,用OpenCV的stereoCalib相關的那堆)。第二行數據爲左圖右圖匹配點的行偏差。第三行就是真正的dist,計算公式在NormType也可以自己豐富。(其實寫這篇博客的目的就是要自己去修改它的匹配規則來優化)可以看到對於某個待匹配點,計算出來的候選點經過匹配計算,也都是相鄰的點(圖像局部相似性)。
Lowe進行特徵匹配篩選採用:最佳匹配點與次佳匹配點比值的形式,ratio
在這裏插入圖片描述
資料很多,上圖截取自這個帖子。雖然是有效果的,但是,我認爲這其實是在去除個別特殊的離羣值。其實本身沒有直接原理證明,只是一種概率統計學的規律,當然並沒有深究,說的錯的話輕噴,評論可以給我科普一下。(Lowe大佬的paper都敢質疑,怕是瘋了)可以看到,有的時候最佳匹配(第0列)比次佳匹配(第一列)其實不見得就是正確的匹配。比如第0行,第540列明顯比216列更像對的匹配點所在列(當然也不一定是對的)。所以可以在匹配時候保留前n個匹配點,然後根據聚集程度篩選。(我才用的是統計方式,可以用直方圖也可以用別的方式,自由發揮)
對比一下用這種匹配出來的結果和原來的結果:
先看原來的結果:
在這裏插入圖片描述
可以看到效果還是不錯的。下面是採用統計篩選出來的結果:
在這裏插入圖片描述
可以看到數據的完整性好的多,但是噪聲也多了很多。至於去噪,還是有辦法的,常見的二維去噪的原理都可以應用。
在這裏插入圖片描述
因爲一些扯淡的原因不能公開,所以可以自己腦補去噪算法,其實應用常規二維圖像去噪的原理修改一下即可。

總結:

(2019年3月19日09:07:42)這裏只是講解了如何看源碼,以及OpenCV裏面的一些工程結構和算法實現,可以類比這些去學習OpenCV其他部分。不得不說OCV是一個很強的庫,從這裏面看源碼可以學到好多騷操作。岡薩雷斯第三版裏面的所有算法這裏都有實現,而且還有改進。當然,看源碼註釋經常能看到XXX來自XXX的文章,然後附上鍊接。這是對知識的尊重。感動ing…
這裏講了knnMatch的向量相似度計算查找最近似解。實際上,在真正的雙目三維重構上,用這種方法做出來的效果是完全不能滿足測量要求的,因爲點密度不可控、對噪聲的魯棒性也很差、計算複雜度也很高,所以,學習學習就好啦,畢竟這個module不是專門用於3Dreconstruction的。順便在下面貼出來我們現在已經做到的效果看看叭
在這裏插入圖片描述

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