OpenCV版本:4.5.3.56
演算法實作思路:
- 影像拼接
- 全景輪廓提取
- 輪廓最小正矩形
- 腐蝕處理
- 裁剪
代碼實作:
import cv2
import numpy as np
def stitch(image):
# 影像拼接
# stitcher = cv2.createStitcher(False) # OpenCV 3.X.X.X使用該方法
stitcher = cv2.Stitcher_create(cv2.Stitcher_PANORAMA) # OpenCV 4.X.X.X使用該方法,cv2.Stitcher_create()也可以
status, pano = stitcher.stitch(image)
# 黑邊處理
if status == cv2.Stitcher_OK:
# 全景圖輪廓提取
stitched = cv2.copyMakeBorder(pano, 10, 10, 10, 10, cv2.BORDER_CONSTANT, (0, 0, 0))
gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
# 輪廓最小正矩形
mask = np.zeros(thresh.shape, dtype="uint8")
(x, y, w, h) = cv2.boundingRect(cnts[0]) # 取出list中的輪廓二值圖,型別為numpy.ndarray
cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)
# 腐蝕處理,直到minRect的像素值都為0
minRect = mask.copy()
sub = mask.copy()
while cv2.countNonZero(sub) > 0:
minRect = cv2.erode(minRect, None)
sub = cv2.subtract(minRect, thresh)
# 提取minRect輪廓并裁剪
cnts = cv2.findContours(minRect, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
(x, y, w, h) = cv2.boundingRect(cnts[0])
stitched = stitched[y:y + h, x:x + w]
cv2.imshow('stitched', stitched)
cv2.imwrite('stitched.jpg', stitched)
cv2.waitKey(0)
cv2.destroyAllWindows()
else:
print('影像匹配的特征點不足')
if __name__ == "__main__":
image1 = cv2.imread('data/space1.jpg')
image2 = cv2.imread('data/space2.jpg')
image3 = cv2.imread('data/space3.jpg')
image = image1, image2, image3
stitch(image)
原圖:



影像拼接
# stitcher = cv2.createStitcher(False) # OpenCV 3.X.X.X使用該方法
stitcher = cv2.Stitcher_create(cv2.Stitcher_PANORAMA) # OpenCV 4.X.X.X使用該方法,cv2.Stitcher_create()也可以
status, pano = stitcher.stitch(image)
OpenCV-Python的stitch實作了影像拼接方法,在OpenCV 3.X.X.X系列版本中,使用cv2.createStitcher,在OpenCV 4.X.X.X系列版本中,使用cv2.Stitcher_create或者cv2.Stitcher_create,兩者用法一致,
stitch有兩個回傳值,一個是status,表示是否拼接成功;另一個是pano,當影像匹配的特征點足夠時,拼接成功,回傳全景圖,當影像匹配的特征點不夠時,拼接失敗,回傳None,效果如下:

黑邊處理
全景圖拼接完成后,會出現影像邊界外的黑色像素(0),使全景圖不完美,可采取如下方法去除黑邊:全景圖輪廓提取、輪廓最小正矩形、腐蝕處理,
全景圖輪廓提取
# 全景圖輪廓提取
stitched = cv2.copyMakeBorder(pano, 10, 10, 10, 10, cv2.BORDER_CONSTANT, (0, 0, 0))
gray = cv2.cvtColor(stitched, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]

輪廓最小正矩形
# 輪廓最小正矩形
mask = np.zeros(thresh.shape, dtype="uint8")
(x, y, w, h) = cv2.boundingRect(cnts[0]) # 取出list中的輪廓二值圖,型別為numpy.ndarray
cv2.rectangle(mask, (x, y), (x + w, y + h), 255, -1)

腐蝕處理
# 腐蝕處理,直到minRect的像素值都為0
minRect = mask.copy()
sub = mask.copy()
while cv2.countNonZero(sub) > 0:
minRect = cv2.erode(minRect, None)
sub = cv2.subtract(minRect, thresh)
創建了兩個mask副本:
- minRect,最小mask,將慢慢縮小尺寸,直到它可以放入全景圖的內部
- sub,判斷minRect是否全黑(0)
通過cv2.erode()腐蝕minRect,直到sub為全黑(0),用類似動圖演示,上面為sub,下面為minRect:

全景圖

參考鏈接
OpenCV: samples/python/stitching.py
Image Stitching with OpenCV and Python - PyImageSearch
使用OpenCV和Python拼接影像_W_Tortoise的博客-CSDN博客
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/301382.html
標籤:其他
