計算視覺——圖像拼接融合


  • 一、全景圖像拼接原理介紹
  • 1.1 背景介紹 

    圖片的全景拼接如今已不再稀奇,現在的智能攝像機和手機攝像頭基本都帶有圖片自動全景拼接的功能,但是一般都會要求拍攝者保持設備的平穩以及單方向的移動取景以實現較好的拼接結果。這是因為拼接的圖片之間必須要有相似的區域以保證拼接結果的准確性和完整性。本文主要簡單描述如何用 Python 和 OpenCV 庫實現多張圖片的自動拼合。

  • 1.2 基本原理
        要實現兩張圖片的簡單拼接,其實只需找出兩張圖片中相似的點 (至少四個,因為 homography 矩陣的計算需要至少四個點), 計算一張圖片可以變換到另一張圖片的變換矩陣 (homography 單應性矩陣),用這個矩陣把那張圖片變換后放到另一張圖片相應的位置 ( 就是相當於把兩張圖片中定好的四個相似的點給重合在一起)。如此,就可以實現簡單的全景拼接。當然,因為拼合之后圖片會重疊在一起,所以需要重新計算圖片重疊部分的像素值,否則結果會很難看。下面是書上原圖的全景拼接結果:

 

 

 

  • 二. 圖像拼接介紹圖像拼接在實際的應用場景很廣,小到我們手機的全景圖片,大到航天領域和地理圖像領域,都會用到推向拼接,圖像拼接的結果好壞會直接影響接下來工作的進行。下面介紹一下圖像拼接中常用的方法。
  • 2.1 圖像拼接步驟

針對某個場景拍攝多張/序列圖像
計算第二張圖片和第一張圖片的變換關系
將第二張圖像疊加到第一張圖像的坐標系中
變換后的融合/合成
如果是多圖場景,重復上述步驟
那么如何就散圖像間的變換關系呢?
首先提取兩幅圖像的特征點並生成描述子,對兩張圖像進行特征匹配,然后就可以計算圖像的變換結構。
圖像的變換結構有位移,旋轉,尺度大小變換,仿射和透視。

  • 2.2 圖像拼接算法

圖像拼接首先進行特征點匹配,這里特征點匹配使用的是Sift特征檢測。

由於圖像是將三維景物顯示在2D平面上,圖像中的景物的三維信息丟失,所以拼接時經常會有“鬼影”的出現,例如下圖:

 

 

  • 三.APAP算法

APAP算法全稱As-Projective-As-Possible Image Stitching,也是圖像拼接算法的一種。關於APAP算法,詳盡信息可以參考圖像拼接之APAP算法代碼詳解

APAP算法流程如下:

1.提取兩張圖片的sift特征點
2.對兩張圖片的特征點進行匹配
3.匹配后,使用RANSAC算法進行特征點對的篩選,排除錯誤點。篩選后的特征點基本能夠一一對應。
4.使用DLT算法,將剩下的特征點對進行透視變換矩陣的估計。
5.因為得到的透視變換矩陣是基於全局特征點對進行的,即一個剛性的單應性矩陣完成配准。為提高配准的精度,APAP將圖像切割成無數多個小方塊,對每個小方塊進行單應性矩陣變換。
經過APAP算法的計算過后,上面那張原本有重疊影像的圖就變成如下圖像:

  • 四.實驗結果
  • 1.針對固定點位拍攝多張圖片,以中間圖片為中心,實現圖像的拼接融合

 

 

 

 拼接的效果不是很好,經百度了解后得知

  • 當圖片模糊度高(像素值小)時,拼接會將五張圖片拆成2+3兩組進行拼接,拼接效果不理想;
  • 圖片較清晰時,以及能夠實現較准確的拼接,雖然沒有看到鬼影現象,但無可避免的還有過重的拼接痕跡;
  • 圖像本身像素對於運行時間和實驗效果都有很大的影響,圖像像素要適當,不能太大也不能太小。

2.移動位置的拍攝

 

 

 

 可以看到拼接的效果十分不理想。

在該場景下,近處和遠處的樓房形成明顯的近遠景,視差變化大。觀察近景目標拼接,可以看到右側護欄處出現了明顯的拼接縫,后面的建築物出現鬼影現象,但是觀察SIFT特征匹配結果,看到匹配結果基本正確。這是因為景深變化大,這時即使都是正確的匹配點,但是不能用homography 單應性矩陣表示,所以會出現鬼影等現象。

  • 代碼
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

import os
root=os.getcwd()+"\\"

"""
This is the panorama example from section 3.3.
"""
# set paths to data folder
featname = ['RANSAC-data/' + str(i + 1) + '.sift' for i in range(5)]
imname = ['RANSAC-data/' + str(i + 1) + '.jpg' for i in range(5)]

# extract features and match
l = {}
d = {}
for i in range(5):
    sift.process_image(root+imname[i], root+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])

# visualize the matches (Figure 3-11 in the book)
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)


# function to convert the matches to hom. points
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


# estimate the homographies
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

# warp the images
delta = 500  # 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')
savefig("quanjing.png", dpi=300)
show()
  • 總結

1.為了拼接出效果比較好的圖像,在保證有相同匹配點的情況下,拍攝圖像的間隔盡可能不要太小,如果太小會導致拼接出來的結果與原圖沒有太大差別,喪失拼接圖像的意義。但如果間隔太大可能會導致匹配點較少而拼接失敗。且一定要站在同一點,水平移動手機進行拍攝,就像拍攝全景圖那樣。若人拍攝的位置發生移動的話,算法可能就會因為找不到正確的點對而報錯。
2.在給圖像編號進行測試時,一定要從右往左進行編號,因為我們的算法的匹配是從最右邊的圖像計算出來的,代碼中有一步驟是將對應的順序進行顛倒,使其從左邊圖像開始進行扭曲。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM