Python图像拼接:创建全景图
Python圖像拼接:創建全景圖
- 算法原理
- 基礎流程
- 幾何原理
- 核心步驟(RANSAC算法)
- 源代碼
- 結果分析
- 綜述
- 夜景(中華城)
- 室內(引桐樓)
- 多建筑(鷺江道周邊)
- 單調場景(海灘)
- 復雜場景(集大校園)
算法原理
基礎流程
1.針對某個場景拍攝多張/序列圖像
2.計算第二張圖像與第一張圖像之間的變換關系
3.將第二張圖像疊加到第一張圖像的坐標系中
4.變換后的融合/合成
5.在多圖場景中,重復上述過程
首先提取一張圖片的特征點,生成對應描述子
接著進行特征匹配
同時,將圖像變換到目標坐標系,計算變換結構,進行圖像融合
幾何原理
全景融合相當于將圖像投影到共同的拼接平面上(同一坐標系)
,接著在拼接平面上實現全景融合
在拼接的應用中,其實可以簡化理解為 2D圖像的變換,疊加過程
核心步驟(RANSAC算法)
圖像拼接的核心步驟在于計算圖片間的變換結構,即如何實現圖像的映射變換,我們通過RANSAC算法實現。
PANSAC是“RANdom SAmple Consensus”(隨機一致性采樣)的縮寫。該方法是用來找到正確模型來擬合帶有噪聲數據的迭代方法。給定一個模型,例如點集之間的單應性矩陣,RANSAC基本的思想是,數據中包含著正確的點和噪聲點,合理的模型應該能夠在描述正確數據點的同時摒棄噪聲點。其大致過程如下:
源代碼
from pylab import *
from numpy import *
from PIL import Imagefrom PCV.geometry import homography, warp
from PCV.localdescriptors import sift# 將匹配轉換成齊次坐標點的函數
def convert_points(j):ndx = matches[j].nonzero()[0]fp = homography.make_homog(l[j + 1][ndx, :2].T)ndx2 = [int(matches[j][i]) for i in ndx]tp = homography.make_homog(l[j][ndx2, :2].T)fp = vstack([fp[1], fp[0], fp[2]])tp = vstack([tp[1], tp[0], tp[2]])return fp, tpif __name__=='__main__':featname = ['img\\jmu0' + str(i + 1) + '.sift' for i in range(5)]imname = ['img\\jmu0' + str(i + 1) + '.jpg' for i in range(5)]im = [array(Image.open(imname[i]).convert('L')) for i in range(5)]l = {}d = {}for i in range(5):sift.process_image(imname[i], featname[i])l[i], d[i] = sift.read_features_from_file(featname[i])matches = {}for i in range(4):matches[i] = sift.match(d[i + 1], d[i])model = homography.RansacModel()fp, tp = convert_points(1)H_12 = homography.H_from_ransac(fp, tp, model)[0] fp, tp = convert_points(0)H_01 = homography.H_from_ransac(fp, tp, model)[0] tp, fp = convert_points(2) H_32 = homography.H_from_ransac(fp, tp, model)[0] tp, fp = convert_points(3) H_43 = homography.H_from_ransac(fp, tp, model)[0] delta = 1000 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)figure()imshow(array(im_42, "uint8"))axis('off')show()
結果分析
綜述
通過對結過分析,得出了如下圖所示問題,其中 “√” 表示效果相對較好。從中我們可以得出圖片數據越多與場景月復雜則越容易出現錯配,以一端為基準進行拼接容易產生圖像扭曲,且圖片數據越多越容易出現,具體各情況間下文分析。
夜景(中華城)
首先,對于夜景,以中華城為例,圖片數據如下
結果如下,從結果中我們可以看出在黑夜環境下背景與建筑對比度高,能夠很好進行特征匹配,但是最終的拼接結果還是稍有瑕疵。如下圖中的警示桿沒能夠很好的進行拼接,個人認為這是由于兩張圖片的亮度相差較大,雖然sift特征匹配能夠一定程度上對亮度有差異的圖像特征進行匹配,但不能夠實現完全匹配,在該情況中由于部分特征點的錯配而導致了拼接錯位。
同時結果中也可以看出有很明顯的拼接縫隙,如下圖,可以很明顯的看到兩側圖片的明暗對比,這是由于兩張圖片本就存在亮度差距,而該算法并沒有實現對圖片灰度值的優化,為了解決該問題可以在拼接后對圖片全局進行均衡化以均衡明暗程度
室內(引桐樓)
室內拼接狀況以引桐樓宿舍為例,數據如下
該組數據不為同一平面拍攝,更真實的還原了全景圖像的拍攝。但其效果如圖所示,圖像的扭曲過于嚴重,拼接效果極差。這是由于該算法僅能對二維平面實現很好的特征匹配,而對于不在同一平面的三維場景
無法進行高準確度的匹配,因此出現了圖片的過渡扭曲與拼接錯位。
多建筑(鷺江道周邊)
對于多建筑的戶外場景,我們以鷺江道周邊為例,圖片數據如下圖:
該拼接結果同樣很明顯的可以看出拼接縫隙即左右的圖片明暗對比。但在一些細節之處,如圖中國際銀行大廈頂上的一片云彩都進行了很好的拼接。而若要解決圖片明暗不均問題還是需要上文所提到進行均衡化。
對于同樣多建筑的情景,通過復現書本中的代碼與圖片數據,可以發現在位于邊緣區域的圖片在拼接時出現“拉伸”的情況,這是由于圖片的尺度不同而導致,在與周圍圖片進行拼接時對圖片進行的一定程度的放縮。對于該問題可以使用平差法進行優化,將每張圖片匹配后的誤差總和計算均值,在均分到每一張圖片,這樣能夠達到更優的圖片拼接效果。
單調場景(海灘)
對于單調場景,我們取白城沙灘一隅為例,圖片數據如下圖:
在對于這種單調且景觀及其相似的場景,尤其考研算法的精度,從以下結果中我們也可以看出出現了不少圖片的錯配。
在這種景物高度相似的場景下特征不易進行匹配,且容易出現錯配,因此需要優化特征點的匹配算法才能夠更好的解決該問題
復雜場景(集大校園)
對于復雜場景即內容豐富的場景,以集大校園為例,圖片數據如下圖:
在該情景下由于景物豐富,我們的算法可以找到大量的匹配特征點,充分利用了場景中的各個景物,因此也能夠得到極優的圖像拼接結果。但不容忽視的是對于旋轉扭曲的圖片該算法還是出現了拼接錯誤。
如下圖所示,圖片間雖然有很多特征點能夠進行匹配但是在拼接過程中卻出現了問題,個人認為這是由于圖片中錯配的特征點太多,導致取均值后出現誤差過大而導致,若想解決該問題則需要運用更加精確的特征匹配算法或是對特征匹配的結果進行優化,出去錯配特征。
總結
以上是生活随笔為你收集整理的Python图像拼接:创建全景图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021 年第十一届 MathorCup
- 下一篇: 【python】一次移动平均算法