python創建全景圖
- RANSAC
- 穩健的單應性矩陣估計
- 代碼實作
- 結果分析
- 實驗總結
在同一位置(即影像的照相機位置相同)拍攝的兩幅或者多幅影像是單應性相關的,我們經常使用該約束將很多影像縫補起來,拼成一個大的影像來創建全景影像,
RANSAC
RANSAC 是“RANdom SAmple Consensus”(隨機一致性采樣)的縮寫,該方法是用來找到正確模型來擬合帶有噪聲資料的迭代方法,給定一個模型,例如點集之間的單應性矩陣,RANSAC 基本的思想是,資料中包含正確的點和噪聲點,合理的模型應該能夠在描述正確資料點的同時摒棄噪聲點,
RANSAC 的標準例子:用一條直線擬合帶有噪聲資料的點集,簡單的最小二乘在該例子中可能會失效,但是 RANSAC 能夠挑選出正確的點,然后獲取能夠正確擬合的直線,下面來看使用 RANSAC 的例子,你可以從 http://www.scipy.org/Cookbook/RANSAC 下載 ransac.py,里面包含了特定的例子作為測驗用例,
穩健的單應性矩陣估計
使用RANSAC演算法求解單應性矩陣 RansacModel類是用于測驗單應性矩陣的類 里面包含了fit()和get_error()方法
fit()方法計算選取的四個對應的單應性矩陣
get_error() 是對所有的對應計算單應性矩陣,然后對每個變換后的點,回傳相應的誤差
class RansacModel(object):
""" Class for testing homography fit with ransac.py from
http://www.scipy.org/Cookbook/RANSAC"""
def __init__(self, debug=False):
self.debug = debug
def fit(self, data):
""" Fit homography to four selected correspondences. """
# transpose to fit H_from_points()
data = data.T
# from points
fp = data[:3, :4]
# target points
tp = data[3:, :4]
# fit homography and return
return H_from_points(fp, tp)
def get_error(self, data, H):
""" Apply homography to all correspondences,
return error for each transformed point. """
data = data.T
# from points
fp = data[:3]
# target points
tp = data[3:]
# transform fp
fp_transformed = dot(H, fp)
# normalize hom. coordinates
for i in range(3):
fp_transformed[i]/=fp_transformed[2]
# return error per point
return sqrt(sum((tp - fp_transformed) ** 2, axis=0))
H_from_ransac() 使用RANSAC穩健性估計點對應間的單應性矩陣H,該函式允許提供閾值和最小期望的點對數目,最重要的引數是最大迭代次數:程式退出太早可能得到一個壞解;迭代次數太多會占有太多時間,函式的回傳結果為單應性矩陣和對應該單應性矩陣的正確點對,
def H_from_ransac(fp, tp, model, maxiter=1000, match_theshold=10):
""" Robust estimation of homography H from point
correspondences using RANSAC (ransac.py from
http://www.scipy.org/Cookbook/RANSAC).
input: fp,tp (3*n arrays) points in hom. coordinates. """
import ransac
# group corresponding points
data = vstack((fp, tp))
# compute H and return
H, ransac_data = ransac.ransac(data.T, model, 4, maxiter, match_theshold, 10, return_all=True)
return H, ransac_data['inliers']
代碼實作
from pylab import *
from numpy import *
from PIL import Image
# If you have PCV installed, these imports should work
from PCV.geometry import homography, warp
from PCV.localdescriptors import sift
# 設定資料檔案夾的路徑
featname = ['image/' + str(i + 1) + '.sift' for i in range(5)]
imname = ['image/' + str(i + 1) + '.jpg' for i in range(5)]
# 使用sift特征自動找到匹配對應
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])
# 可視化兩張影像
for i in range(4):
im1 = array(Image.open(imname[i]))
im2 = array(Image.open(imname[i + 1]))
figure()
sift.plot_matches(im2, im1, l[i + 1], l[i], matches[i], show_below=True)
# 將匹配項轉化為特征點
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)
# switch x and y - TODO this should move elsewhere
fp = vstack([fp[1], fp[0], fp[2]])
tp = vstack([tp[1], tp[0], tp[2]])
return fp, tp
# 估計單應性矩陣
model = homography.RansacModel()
fp, tp = convert_points(1)
H_12 = homography.H_from_ransac(fp, tp, model)[0] # im 1 to 2
fp, tp = convert_points(0)
H_01 = homography.H_from_ransac(fp, tp, model)[0] # im 0 to 1
tp, fp = convert_points(2) # NB: reverse order
H_32 = homography.H_from_ransac(fp, tp, model)[0] # im 3 to 2
tp, fp = convert_points(3) # NB: reverse order
H_43 = homography.H_from_ransac(fp, tp, model)[0] # im 4 to 3
# 扭曲影像
delta = 2000 # for padding and translation
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特征匹配:




拼接結果:

這是針對于遠景圖片拼接的結果圖,因為將五張圖片的像素調為1000*750,所以會比較模糊,但是可以大致的看出拼接的結果是不錯的,比較好的還原了拍攝的全景圖,不過演算法并未考慮全域拼接多張圖片平均亮度的問題,出現了分割很明顯的部分,
實驗總結
- 影像大小會影響程式的速度,所以要對圖片進行壓縮,圖片太大的話會出現錯誤

- 圖片全景拼接把幾張圖片拼接在一起,先選取一個中間影像作為中心影像,也就是希望將其他影像變成的影像,由于匹配是從最右邊的影像開始計算,所以需要注意將圖片的順序進行顛倒(即由1,2,3,4,5的存放順序變為5,4,3,2,1),使得從左邊影像開始扭曲,將所有影像扭曲到一個公共的影像平面上,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/280351.html
標籤:其他
上一篇:C語言之函式進擊
