python實(shí)現(xiàn)圖像全景拼接
圖像的全景拼接包括三大部分:特征點(diǎn)提取與匹配、圖像配準(zhǔn)、圖像融合。
1、基于SIFT的特征點(diǎn)的提取與匹配
利用Sift提取圖像的局部特征,在尺度空間尋找極值點(diǎn),并提取出其位置、尺度、方向信息。
具體步驟:
1). 生成高斯差分金字塔(DOG金字塔),尺度空間構(gòu)建
2). 空間極值點(diǎn)檢測(cè)(關(guān)鍵點(diǎn)的初步查探)
3). 穩(wěn)定關(guān)鍵點(diǎn)的精確定位
4). 穩(wěn)定關(guān)鍵點(diǎn)方向信息分配
5). 關(guān)鍵點(diǎn)描述
6). 特征點(diǎn)匹配
2、圖像配準(zhǔn)
圖像配準(zhǔn)是一種確定待拼接圖像間的重疊區(qū)域以及重疊位置的技術(shù),它是整個(gè)圖像拼接的核心。本節(jié)采用的是基于特征點(diǎn)的圖像配準(zhǔn)方法,即通過匹配點(diǎn)對(duì)構(gòu)建圖像序列之間的變換矩陣,從而完成全景圖像的拼接。
變換矩陣H求解是圖像配準(zhǔn)的核心,其求解的算法流程如下。
1)檢測(cè)每幅圖像中特征點(diǎn)。
2)計(jì)算特征點(diǎn)之間的匹配。
3)計(jì)算圖像間變換矩陣的初始值。
4)迭代精煉H變換矩陣。
5)引導(dǎo)匹配。用估計(jì)的H去定義對(duì)極線附近的搜索區(qū)域,進(jìn)一步確定特征點(diǎn)的對(duì)應(yīng)。
6)重復(fù)迭代4)和5)直到對(duì)應(yīng)點(diǎn)的數(shù)目穩(wěn)定為止。
設(shè)圖像序列之間的變換為投影變換
可用4組最佳匹配計(jì)算出H矩陣的8 個(gè)自由度參數(shù)hi=( i=0,1,...,7),并以此作為初始值。
為了提高圖像配準(zhǔn)的精度,本節(jié)采用RANSAC算法對(duì)圖像變換矩陣進(jìn)行求解與精煉,達(dá)到了較好的圖像拼接效果。RANSAC算法的思想簡(jiǎn)單而巧妙:首先隨機(jī)地選擇兩個(gè)點(diǎn),這兩個(gè)點(diǎn)確定了一條直線,并且稱在這條直線的一定范圍內(nèi)的點(diǎn)為這條直線的支撐。這樣的隨機(jī)選擇重復(fù)數(shù)次,然后,具有最大支撐集的直線被確認(rèn)為是樣本點(diǎn)集的擬合。在擬合的誤差距離范圍內(nèi)的點(diǎn)被認(rèn)為是內(nèi)點(diǎn),它們構(gòu)成一致集,反之則為外點(diǎn)。根據(jù)算法描述,可以很快判斷,如果只有少量外點(diǎn),那么隨機(jī)選取的包含外點(diǎn)的初始點(diǎn)集確定的直線不會(huì)獲得很大的支撐,值得注意的是,過大比例的外點(diǎn)將導(dǎo)致RANSAC算法失敗。在直線擬合的例子中,由點(diǎn)集確定直線至少需要兩個(gè)點(diǎn);而對(duì)于透視變換,這樣的最小集合需要有4個(gè)點(diǎn)。
3、圖像融合
因?yàn)橄鄼C(jī)和光照強(qiáng)度的差異,會(huì)造成一幅圖像內(nèi)部,以及圖像之間亮度的不均勻,拼接后的圖像會(huì)出現(xiàn)明暗交替,這樣給觀察造成極大的不便。 亮度與顏色均衡處理,通常的處理方式是通過相機(jī)的光照模型,校正一幅圖像內(nèi)部的光照不均勻性,然后通過相鄰兩幅圖像重疊區(qū)域之間的關(guān)系,建立相鄰兩幅圖像之間直方圖映射表,通過映射表對(duì)兩幅圖像做整體的映射變換,最終達(dá)到整體的亮度和顏色的一致性。
具體實(shí)現(xiàn):
import numpy as np import cv2 as cv from matplotlib import pyplot as plt if __name__ == '__main__': top, bot, left, right = 100, 100, 0, 500 img1 = cv.imread('1.jpg') img2 = cv.imread('2.jpg') srcImg = cv.copyMakeBorder(img1, top, bot, left, right, cv.BORDER_CONSTANT, value=(0, 0, 0)) testImg = cv.copyMakeBorder(img2, top, bot, left, right, cv.BORDER_CONSTANT, value=(0, 0, 0)) img1gray = cv.cvtColor(srcImg, cv.COLOR_BGR2GRAY) img2gray = cv.cvtColor(testImg, cv.COLOR_BGR2GRAY) sift = cv.xfeatures2d_SIFT().create() # find the keypoints and descriptors with SIFT kp1, des1 = sift.detectAndCompute(img1gray, None) kp2, des2 = sift.detectAndCompute(img2gray, None) # FLANN parameters FLANN_INDEX_KDTREE = 1 index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) search_params = dict(checks=50) flann = cv.FlannBasedMatcher(index_params, search_params) matches = flann.knnMatch(des1, des2, k=2) # Need to draw only good matches, so create a mask matchesMask = [[0, 0] for i in range(len(matches))] good = [] pts1 = [] pts2 = [] # ratio test as per Lowe's paper for i, (m, n) in enumerate(matches): if m.distance < 0.7*n.distance: good.append(m) pts2.append(kp2[m.trainIdx].pt) pts1.append(kp1[m.queryIdx].pt) matchesMask[i] = [1, 0] draw_params = dict(matchColor=(0, 255, 0), singlePointColor=(255, 0, 0), matchesMask=matchesMask, flags=0) img3 = cv.drawMatchesKnn(img1gray, kp1, img2gray, kp2, matches, None, **draw_params) plt.imshow(img3, ), plt.show() rows, cols = srcImg.shape[:2] MIN_MATCH_COUNT = 10 if len(good) > MIN_MATCH_COUNT: src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2) dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2) M, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC, 5.0) warpImg = cv.warpPerspective(testImg, np.array(M), (testImg.shape[1], testImg.shape[0]), flags=cv.WARP_INVERSE_MAP) for col in range(0, cols): if srcImg[:, col].any() and warpImg[:, col].any(): left = col break for col in range(cols-1, 0, -1): if srcImg[:, col].any() and warpImg[:, col].any(): right = col break res = np.zeros([rows, cols, 3], np.uint8) for row in range(0, rows): for col in range(0, cols): if not srcImg[row, col].any(): res[row, col] = warpImg[row, col] elif not warpImg[row, col].any(): res[row, col] = srcImg[row, col] else: srcImgLen = float(abs(col - left)) testImgLen = float(abs(col - right)) alpha = srcImgLen / (srcImgLen + testImgLen) res[row, col] = np.clip(srcImg[row, col] * (1-alpha) + warpImg[row, col] * alpha, 0, 255) # opencv is bgr, matplotlib is rgb res = cv.cvtColor(res, cv.COLOR_BGR2RGB) # show the result plt.figure() plt.imshow(res) plt.show() else: print("Not enough matches are found - {}/{}".format(len(good), MIN_MATCH_COUNT)) matchesMask = None
實(shí)驗(yàn)結(jié)果:
1、室內(nèi)場(chǎng)景:
原圖1
原圖2
拼接后:
2、室外場(chǎng)景:
場(chǎng)景1:
原圖1
原圖2
拼接后:
場(chǎng)景2:
原圖1
原圖2
拼接后:
場(chǎng)景3:
原圖1
原圖2
拼接后:
總結(jié):
本文分別針對(duì)室內(nèi)和室外兩種情況對(duì)兩張圖像做全景拼接,發(fā)現(xiàn)室內(nèi)情況下拼接的效果較為好。在室外場(chǎng)景1情況下,兩張圖像有近景和遠(yuǎn)景結(jié)合,兩張圖像拼接后近景的圖像被放大并有一定程度的傾斜;在場(chǎng)景2中,兩張圖像都是遠(yuǎn)景,拼接后的效果還不錯(cuò)但是在拼接后圖像的中上方出現(xiàn)了拼接縫;場(chǎng)景3是在不同明亮程度下圖像的拼接可以發(fā)現(xiàn)拼接后的圖像出現(xiàn)明顯的明暗差距,并且拼接縫明顯兩張圖像沒有很好的拼接在一起,出現(xiàn)很多沒有重合的地方。
本實(shí)驗(yàn)最初是用opencv-contrib3.4.5版本,但是由于sift的專利限制無(wú)法使用,隨后用opencv-contriv3.4.2代碼可以運(yùn)行,不會(huì)出現(xiàn)問題。方法:先卸載當(dāng)前版本的opencv并安裝:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-contrib-python==3.4.2.16
本文已被收錄到專題《python圖片處理操作》 ,歡迎大家點(diǎn)擊學(xué)習(xí)更多精彩內(nèi)容。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python實(shí)現(xiàn)文本進(jìn)度條 程序進(jìn)度條 加載進(jìn)度條 單行刷新功能
這篇文章主要介紹了python實(shí)現(xiàn)文本進(jìn)度條 程序進(jìn)度條 加載進(jìn)度條 單行刷新功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07Python連接MySQL數(shù)據(jù)庫(kù)的四種方法
用?Python?連接到?MySQL?數(shù)據(jù)庫(kù)的方法不是很系統(tǒng),實(shí)際中有幾種不同的連接方法,而且不是所有的方法都能與不同的操作系統(tǒng)很好地配合,本文涵蓋了四種方法,你可以用它們來(lái)連接你的Python應(yīng)用程序和MySQL,需要的朋友可以參考下2024-08-08pygame.display.flip()和pygame.display.update()的區(qū)別及說(shuō)明
這篇文章主要介紹了pygame.display.flip()和pygame.display.update()的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03在django-xadmin中APScheduler的啟動(dòng)初始化實(shí)例
今天小編就為大家分享一篇在django-xadmin中APScheduler的啟動(dòng)初始化實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2019-11-11Python源碼學(xué)習(xí)之PyObject和PyTypeObject
今天給大家?guī)?lái)的是關(guān)于Python源碼的相關(guān)知識(shí)學(xué)習(xí),文章圍繞著PyObject和PyTypeObject展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06Python生成ubuntu apt鏡像地址實(shí)現(xiàn)
本文主要介紹了Python生成ubuntu apt鏡像地址實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05