一、算法目的:
在同一位置拍攝的兩幅或者多幅圖像是單應性相關的的,使用該限制将很多圖檔縫補起來,拼成一個大的圖像來建立全景圖像。兩張圖檔的拼接必須首先找到相同特征,也就是說兩張照片必須要有重疊的部分才能實作拼接,對人眼來說很容易找到兩張圖檔的相似點,對計算機來說需要借助算法。是以圖像拼接的第一步是分别擷取兩張圖檔的特征點并對特征點進行比對,第二步對圖檔進行透視變換并對圖檔進行拼接。
二、特征點配對:
查找特征點使用sift方法,将兩幅或者多幅圖像中的相似點提取出來并完成圖像的特征點比對,相關sift的原了解釋請看前面介紹。
運作sift找到特征比對點對:
下面的圖檔是需要比對的兩張原圖,而且它們具有相同的區域,可以找到相同特征點并完成比對,由于兩張圖檔相似點比較多,特征點容易找,是以比對效果很明顯。
三、RANSAC介紹:
1、ransac
是随機一緻性采樣,該方法是用來找到正确模型來拟合帶來有噪聲資料的疊代方法。給定一個模型,例如點集之間的單應性矩陣,ransac的基本思想是,資料中包含正确的點和噪聲點,合理的模型應該能夠在描述正确資料點的同時摒棄噪聲點。
RANSAC算法的具體描述是:給定N個資料點組成的集合P,假設集合中大多數的點都是可以通過一個模型來産生的,且最少通過n個點(n<N)可以拟合出模型的參數,則可以通過以下的疊代方式拟合該參數。
對下面的操作執行k次:
(1)從P中随機選擇n個資料點;
(2)用這n個資料點拟合出一個模型M;
(3)對P中剩餘的資料點,計算每個點與模型M的距離,距離超過門檻值的則認定為局外點,不超過門檻值的認定為局内點,并記錄該模型M所對應的局内點的值m;
疊代k次以後,選擇m最大的模型M作為拟合的結果。
因為在實際應用中N的值通常會很大,那麼從其中任選n個資料點的組合就會很大,如果對所有組合都進行上面的操作運算量就會很大,是以對于k的選擇就很重要。通常情況下,隻要保證模型估計需要的n個點都是點的機率足夠高即可。是以設w為N個資料中局内點的比例,z為進行k次選取後,至少有一次選取的n個點都是局内點的機率。則有
拟合結果顯示表示為:
2、Ransac原理:
OpenCV中濾除誤比對對采用RANSAC算法尋找一個最佳單應性矩陣H,矩陣大小為3×3。RANSAC目的是找到最優的參數矩陣使得滿足該矩陣的資料點個數最多,通常令h33=1來歸一化矩陣。由于單應性矩陣有8個未知參數,至少需要8個線性方程求解,對應到點位置資訊上,一組點對可以列出兩個方程,則至少包含4組比對點對。
RANSAC算法從比對資料集中随機抽出4個樣本并保證這4個樣本之間不共線,計算出單應性矩陣,然後利用這個模型測試所有資料,并計算滿足這個模型資料點的個數與投影誤差(即代價函數),若此模型為最優模型,則對應的代價函數最小。
3、ransac算法步驟為:
1. 随機從資料集中随機抽出4個樣本資料 (此4個樣本之間不能共線),計算出變換矩陣H,記為模型M;
2. 計算資料集中所有資料與模型M的投影誤差,若誤差小于門檻值,加入内點集 I ;
3. 如果目前内點集 I 元素個數大于最優内點集 I_best , 則更新 I_best = I,同時更新疊代次數k ;
4. 如果疊代次數大于k,則退出 ; 否則疊代次數加1,并重複上述步驟)
注:疊代次數k在不大于最大疊代次數的情況下,是在不斷更新而不是固定的;
使用ransac算法求解單應性矩陣,将下面模型類添加到homography.py中,相關解釋如下:
class RansacModel(object):
#用于測試單應性矩陣的類
def __init__(self, debug=False):
self.debug = debug
def fit(self, data):
#計算選取的4個對應的單應性矩陣
#将其轉置,來調用H_from_points()計算單應性矩陣
data = data.T
# 映射的起始點
fp = data[:3, :4]
# 映射的目标點
tp = data[3:, :4]
# 計算單應性矩陣然後傳回
return H_from_points(fp, tp)
def get_error(self, data, H):
#對所有的對應計算單應性矩陣,然後對每個變換後的點,傳回相應的誤差
data = data.T
# 映射的起始點
fp = data[:3]
# 映射的目标點
tp = data[3:]
# 變換 fp
fp_transformed = dot(H, fp)
# 歸一化齊次坐标
for i in range(3):
fp_transformed[i]/=fp_transformed[2]
# 傳回每個點的坐标
return sqrt(sum((tp - fp_transformed) ** 2, axis=0))
四、拼接圖檔:
估計出圖像間的單應性矩陣,現在我們需要将所有的圖像扭曲到一個公共的圖像平面上。通常,這裡的公共平面為中心圖像平面。一種方法是建立一個很大的圖像,比如圖像中全部填充0,使其和中心圖像平行,然後将所有的圖像扭曲到上面。由于我們所有的圖像是由照相機水準旋轉拍攝的,由此我們可以使用一個簡單的步驟:将中心圖像左邊或者右邊的區域填充0,以便扭曲的圖像騰出空間。
利用panorama()函數,使用單應性矩陣H,協調相幅圖像,建立水準全景圖像。結果為一幅和toim具有相同高度的圖像。
扭曲圖像的相關代碼為:
im1 = array(Image.open(imname[1]), "uint8")
im2 = array(Image.open(imname[2]), "uint8")
im_12 = warp.panorama(H_12, im1, im2, delta, delta)
im1 = array(Image.open(imname[0]), "f")
im_02 = warp.panorama(dot(H_12, H_01), im1, im_12, delta, delta)
im1 = array(Image.open(imname[3]), "f")
im_32 = warp.panorama(H_32, im1, im_02, delta, delta)
im1 = array(Image.open(imname[4]), "f")
im_42 = warp.panorama(dot(H_32, H_43), im1, im_32, delta, 2 * delta)
五、實驗結果分析:
第一對圖檔特征點比對結果為:
拼接效果為:
由于兩張圖檔重合的地方比較多,而且相同點比較多,特征點找到的比較多,圖檔經過扭曲後的拼接效果較好,而且拼接也算完美,但是對于圖檔相差較較大的兩張圖檔進行拼接時就會出現問題。