Image Stitching with OpenCV and Python
在本教程中,您將學(xué)習(xí)如何使用Python,OpenCV和cv2.createStitcher和cv2.Stitcher_create函數(shù)執(zhí)行圖像拼接。
使用今天的代碼,您將可以將多張圖像拼接在一起,從而創(chuàng)建出拼接圖像的全景圖。
就在不到兩年前,我發(fā)布了有關(guān)圖像拼接和全景圖構(gòu)建的兩個(gè)指南:
這兩個(gè)教程都涵蓋了典型圖像拼接算法的基礎(chǔ)知識(shí),該算法至少需要四個(gè)關(guān)鍵步驟:
- 從兩個(gè)輸入圖像中檢測(cè)關(guān)鍵點(diǎn)(DoG,Harris等)并提取局部不變描述符(SIFT,SURF等)
- 在圖像之間匹配描述符
- 使用RANSAC算法通過匹配的特征向量估計(jì)單應(yīng)矩陣(homography matrix)
- 使用從步驟#3獲得的單應(yīng)性矩陣應(yīng)用翹曲變換(warping transformation)
但是,我最初的實(shí)現(xiàn)最大的問題是它們不能處理兩個(gè)以上的輸入圖像。
在今天的教程中,我們將重新討論OpenCV的圖像拼接,包括如何將兩個(gè)以上的圖像拼接在一起成為全景圖像。
第一部分將簡(jiǎn)要回顧OpenCV的圖像拼接算法,該算法通過cv2.createStitcher和cv2.Stitcher_create函數(shù)嵌入OpenCV庫(kù)本身。
從那里,我們將審查我們的項(xiàng)目結(jié)構(gòu),并實(shí)現(xiàn)可用于圖像拼接的Python腳本。
我們將回顧第一個(gè)腳本的結(jié)果,注意其局限性,然后實(shí)施第二個(gè)Python腳本,該腳本可用于在美學(xué)上使圖像拼接效果更加令人滿意。
最后,我們將檢查第二個(gè)腳本的結(jié)果,并再次注意任何限制或缺點(diǎn)。
OpenCV的圖像拼接算法
今天我們將在此處使用的算法類似于Brown和Lowe在2007年的論文《具有不變特征的自動(dòng)全景圖像拼接》中提出的方法。
Automatic Panoramic Image Stitching with Invariant Features
與以前的對(duì)圖像輸入順序敏感的圖像拼接算法不同,Brown and Lowe方法更健壯,使其對(duì)以下內(nèi)容不敏感:
- 圖像順序
- 圖像方向
- 光照變化
- 實(shí)際上不是全景圖的一部分的有噪聲圖像
此外,通過使用增益補(bǔ)償和圖像融合來產(chǎn)生更加美觀的輸出全景圖像。
對(duì)該算法進(jìn)行完整,詳細(xì)的介紹超出了本文的范圍,因此,如果您有興趣了解更多信息,請(qǐng)參閱原始出版物。
cv2.createStitcher and cv2.Stitcher_create
OpenCV已經(jīng)通過cv2.createStitcher(OpenCV 3.x)和cv2.Stitcher_create(OpenCV 4)函數(shù)實(shí)現(xiàn)了類似于Brown和Lowe論文的方法。
OpenCV 3.x的cv2.createStitcher的功能簽名:
createStitcher(...)
createStitcher([, try_use_gpu]) -> retval
請(qǐng)注意,此函數(shù)只有一個(gè)參數(shù)try_gpu,可用于改善整個(gè)圖像拼接管道。 OpenCV的GPU支持有限,而且我永遠(yuǎn)無法使該參數(shù)正常工作,因此我建議始終將其保留為False。
OpenCV 4的cv2.Stitcher_create函數(shù)具有類似的簽名:
Stitcher_create(...)
Stitcher_create([, mode]) -> retval
. @brief Creates a Stitcher configured in one of the stitching
. modes.
.
. @param mode Scenario for stitcher operation. This is usually
. determined by source of images to stitch and their transformation.
. Default parameters will be chosen for operation in given scenario.
. @return Stitcher class instance.
要執(zhí)行實(shí)際的圖像拼接,我們需要調(diào)用.stitch方法:
OpenCV 3.x:
stitch(...) method of cv2.Stitcher instance
stitch(images[, pano]) -> retval, pano
OpenCV 4.x:
stitch(...) method of cv2.Stitcher instance
stitch(images, masks[, pano]) -> retval, pano
. @brief These functions try to stitch the given images.
.
. @param images Input images.
. @param masks Masks for each input image specifying where to
. look for keypoints (optional).
. @param pano Final pano.
. @return Status code.
此方法接受輸入圖像列表,然后嘗試將它們拼接成全景圖,然后將輸出的全景圖圖像返回給調(diào)用函數(shù)。
status變量指示圖像拼接是否成功,并且可以是四個(gè)變量之一:
- OK = 0:圖像拼接成功。
- ERR_NEED_MORE_IMGS = 1:如果您收到此狀態(tài)碼,則需要更多輸入圖像來構(gòu)建全景圖。
通常,如果在輸入圖像中沒有檢測(cè)到足夠的關(guān)鍵點(diǎn),則會(huì)發(fā)生此錯(cuò)誤。 - ERR_HOMOGRAPHY_EST_FAIL = 2:當(dāng)RANSAC單應(yīng)性估計(jì)失敗時(shí),會(huì)發(fā)生此錯(cuò)誤。
同樣,您可能需要更多圖像,或者圖像沒有足夠的可區(qū)分的獨(dú)特紋理/對(duì)象來精確匹配關(guān)鍵點(diǎn)。 - ERR_CAMERA_PARAMS_ADJUST_FAIL = 3:我之前從未遇到過此錯(cuò)誤,所以我對(duì)此不太了解,但是要點(diǎn)在于,這與無法從輸入圖像中正確估計(jì)相機(jī)的內(nèi)在/外在特性有關(guān)。
如果遇到此錯(cuò)誤,則可能需要參考OpenCV文檔,甚至需要深入研究OpenCV C ++代碼。
現(xiàn)在,我們已經(jīng)回顧了cv2.createStitcher,cv2.Stitcher_create和.stitch方法,讓我們繼續(xù)實(shí)際使用OpenCV和Python實(shí)現(xiàn)圖像拼接。
基本圖像拼接結(jié)果
但是全景周圍的黑色區(qū)域呢? 那些是什么?
這些區(qū)域從執(zhí)行構(gòu)建全景所需的透視扭曲開始。
有一種方法可以消除它們……但是我們將需要在下一部分中實(shí)現(xiàn)一些其他邏輯。
使用OpenCV和Python更好的圖像拼接器
我們的第一個(gè)圖像拼接腳本是一個(gè)良好的開端,但是全景圖本身周圍的黑色區(qū)域并不是我們所謂的“美觀”。
更重要的是,您不會(huì)從內(nèi)置于iOS,Android等的流行圖像拼接應(yīng)用程序中看到這樣的輸出圖像。
因此,我們將對(duì)腳本進(jìn)行一些修改,并包括一些其他邏輯以創(chuàng)建更美觀的全景圖。
我將再次重申此方法是一種破解。
我們將審查基本的圖像處理操作,包括閾值,輪廓提取,形態(tài)學(xué)操作等,以便獲得所需的結(jié)果。
據(jù)我所知,OpenCV的Python綁定無法為我們提供手動(dòng)提取全景圖的最大內(nèi)部矩形區(qū)域所需的信息。 如果有,請(qǐng)?jiān)谠u(píng)論中讓我知道。
所有這些代碼都與我們之前的腳本相同,但有一個(gè)例外。
--crop命令行參數(shù)已添加。 在終端中為該參數(shù)提供1時(shí),我們將繼續(xù)進(jìn)行裁剪操作。
下一步是我們開始實(shí)現(xiàn)其他功能的地方:
局限和缺點(diǎn)
在上一教程中,我演示了如何構(gòu)建實(shí)時(shí)全景圖和圖像拼接算法-本教程基于以下事實(shí):我們手動(dòng)執(zhí)行關(guān)鍵點(diǎn)檢測(cè),特征提取和關(guān)鍵點(diǎn)匹配,從而使我們能夠使用所用的單應(yīng)性矩陣將我們的兩個(gè)輸入圖像扭曲成全景圖。
而且,盡管OpenCV內(nèi)置的cv2.createStitcher和cv2.Stitcher_create函數(shù)能夠構(gòu)造準(zhǔn)確,美觀的全景圖,但該方法的主要缺點(diǎn)之一是,它抽象了對(duì)單應(yīng)性矩陣的所有訪問。
實(shí)時(shí)全景圖構(gòu)建的一種假設(shè)是,場(chǎng)景本身在內(nèi)容方面變化不大。
一旦我們計(jì)算了初始單應(yīng)性估計(jì),我們只需要偶爾重新計(jì)算矩陣即可。
無需執(zhí)行全面的關(guān)鍵點(diǎn)匹配和RANSAC估計(jì),就可以在構(gòu)建全景圖時(shí)極大地提高了速度,因此,如果無法訪問原始的單應(yīng)性矩陣,采用OpenCV的內(nèi)置圖像拼接算法并對(duì)其進(jìn)行實(shí)時(shí)轉(zhuǎn)換將是一個(gè)挑戰(zhàn)。
總結(jié)
在今天的教程中,您學(xué)習(xí)了如何使用OpenCV和Python執(zhí)行多個(gè)圖像拼接。
使用OpenCV和Python,我們能夠?qū)⒍鄠€(gè)圖像拼接在一起并創(chuàng)建全景圖像。
我們輸出的全景圖像不僅在縫合位置上準(zhǔn)確,而且在美學(xué)上也令人愉悅。
但是,使用OpenCV的內(nèi)置圖像拼接類的最大缺點(diǎn)之一是,它抽象了許多內(nèi)部計(jì)算,包括由此產(chǎn)生的單應(yīng)性矩陣本身。
如果您嘗試執(zhí)行實(shí)時(shí)圖像拼接,如我們?cè)谇耙黄恼轮兴龅哪菢樱瑒t可能會(huì)發(fā)現(xiàn)緩存單應(yīng)性矩陣并且僅偶爾執(zhí)行關(guān)鍵點(diǎn)檢測(cè),特征提取和特征匹配是有益的。
跳過這些步驟并使用緩存的矩陣執(zhí)行透視變形可以減少管道的計(jì)算負(fù)擔(dān),并最終加快實(shí)時(shí)圖像拼接算法的速度,但是不幸的是,OpenCV的cv2.createStitcher Python綁定無法為我們提供對(duì)原始矩陣。