一、圖像拼接的介紹
圖像拼接是一種將多幅具有部分重疊內容的圖像合并成一幅完整、無縫且具有更廣闊視野或更高分辨率圖像的技術。其目的是通過整合多個局部圖像來獲取更全面、更具信息價值的圖像內容。
二、圖像拼接的原理
圖像拼接的核心目標是將多幅有重疊區域的圖像進行準確對齊和融合,形成一個連續、無縫的大圖像。其基本原理主要包括以下幾個關鍵步驟:
特征提取:在每幅圖像中尋找具有代表性的特征點,如角點、邊緣點等。常用的特征提取算法有 SIFT(尺度不變特征變換)、SURF(加速穩健特征)和 ORB(Oriented FAST and Rotated BRIEF)等。這些特征點具有獨特的屬性,能夠在不同的光照、尺度和旋轉條件下保持相對穩定。
特征匹配:對不同圖像中的特征點進行匹配,找出它們之間的對應關系。這一步驟的目的是確定哪些特征點來自同一物理位置,從而為后續的圖像對齊提供基礎。常見的特征匹配方法有暴力匹配(Brute-Force Matching)和基于快速最近鄰搜索庫(FLANN)的匹配等。
圖像對齊:根據特征匹配的結果,計算出圖像之間的變換關系,如旋轉、平移和縮放等。然后使用這些變換關系將圖像進行對齊,使得它們的重疊區域能夠精確重合。常用的變換模型有仿射變換和透視變換。
圖像融合:將對齊后的圖像進行融合,消除拼接處的明顯痕跡,使拼接后的圖像看起來自然、連續。融合的方法有多種,如簡單的平均融合、漸入漸出融合等。
三、代碼實現
1.導入庫與定義輔助函數
import cv2
import numpy as np
import sysdef cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)def detectAndDescribe(image):gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) # 將彩色圖片轉換成灰度圖descriptor = cv2.SIFT_create()(kps, des) = descriptor.detectAndCompute(gray, None) # 將結果轉換成NumPy數組kps_float = np.float32([kp.pt for kp in kps])return (kps, kps_float, des)
導入庫:cv2 是 OpenCV 庫,用于圖像處理;numpy 用于數值計算;sys 用于系統相關操作,如退出程序。
cv_show 函數:該函數用于顯示圖像,cv2.imshow 用于在窗口中顯示圖像,cv2.waitKey(0) 表示無限等待用戶按下任意鍵,以保持窗口顯示。
detectAndDescribe 函數:將輸入的彩色圖像轉換為灰度圖像,然后使用 SIFT(尺度不變特征變換)算法檢測關鍵點并計算描述符。最后將關鍵點的坐標轉換為 float32 類型的 NumPy 數組,返回關鍵點、關鍵點坐標數組和描述符。
2.讀取圖像并提取特征
imageA = cv2.imread("1.jpg")
cv_show('imageA', imageA)
imageB = cv2.imread("2.jpg")
cv_show('imageB', imageB)
(kpsA, kps_floatA, desA) = detectAndDescribe(imageA)
(kpsB, kps_floatB, desB) = detectAndDescribe(imageB)
讀取圖像:使用 cv2.imread 函數讀取兩張圖像 1.jpg 和 2.jpg,并使用 cv_show 函數顯示這兩張圖像。
提取特征:調用 detectAndDescribe 函數分別對兩張圖像進行特征提取,得到每張圖像的關鍵點、關鍵點坐標數組和描述符。
3.特征匹配與篩選
matcher = cv2.BFMatcher()
rawMatches = matcher.knnMatch(desB, desA, 2)
good = []
matches = []
for m in rawMatches:if len(m) == 2 and m[0].distance < 0.65 * m[1].distance:good.append(m)matches.append((m[0].queryIdx, m[0].trainIdx))
print(len(good))
print(matches)
vis = cv2.drawMatchesKnn(imageB, kpsB, imageA, kpsA, good, None, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
cv_show("Keypoint Matches", vis)
特征匹配:創建一個暴力匹配器 cv2.BFMatcher,使用 knnMatch 方法對圖像 B 和圖像 A 的描述符進行匹配,k=2 表示為每個描述符找到兩個最近鄰匹配。
篩選匹配結果:遍歷所有匹配結果,若匹配結果包含兩個元素且第一個匹配的距離小于第二個匹配距離的 0.65 倍,則認為該匹配是可靠的,將其添加到 good 列表中,并記錄匹配點的索引到 matches 列表中。
顯示匹配結果:打印可靠匹配的數量和匹配點的索引,使用 cv2.drawMatchesKnn 函數繪制匹配點,并使用 cv_show 函數顯示匹配結果。
4.透視變換矩陣計算
# 透視變換
if len(matches) > 4:ptsB = np.float32([kps_floatB[i] for (i, _) in matches]) # matches是通過閾值篩選之后的特征點對象ptsA = np.float32([kps_floatA[i] for (_, i) in matches])(H, mask) = cv2.findHomography(ptsB, ptsA, cv2.RANSAC, 10)
else:print('圖片未找到4個以上的匹配點')sys.exit()
判斷匹配點數量:如果可靠匹配點的數量大于 4,則可以進行透視變換矩陣的計算。
提取匹配點坐標:從關鍵點坐標數組中提取可靠匹配點的坐標,分別存儲在 ptsB 和 ptsA 中。
計算透視變換矩陣:使用 cv2.findHomography 函數,采用 RANSAC 算法計算圖像 B 到圖像 A 的透視變換矩陣 H。
處理匹配點不足的情況:如果可靠匹配點的數量小于等于 4,則打印提示信息并退出程序。
5.圖像拼接與顯示
result = cv2.warpPerspective(imageB, H, (imageB.shape[1] + imageA.shape[1], imageB.shape[0]))
cv_show('resultB', result)
result[0:imageA.shape[0], 0:imageA.shape[1]] = imageA
cv_show('result', result)
透視變換:使用 cv2.warpPerspective 函數將圖像 B 進行透視變換,變換后的圖像大小為圖像 B 和圖像 A 的寬度之和,高度為圖像 B 的高度。
顯示透視變換后的圖像:使用 cv_show 函數顯示透視變換后的圖像。
圖像拼接:將圖像 A 復制到透視變換后的圖像的左上角,實現圖像拼接。
顯示拼接結果:使用 cv_show 函數顯示最終的拼接結果。
綜上所述,這段代碼的主要功能是讀取兩張圖像,提取圖像的 SIFT 特征,進行特征匹配和篩選,計算透視變換矩陣,將圖像 B 進行透視變換并與圖像 A 進行拼接,最后顯示拼接結果。
完整代碼:
import cv2
import numpy as np
import sys
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)
def detectAndDescribe(image):gray =cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)# 將彩色圖片轉換成灰度圖descriptor =cv2.SIFT_create()#(kps, des) = descriptor.detectAndCompute(gray, None) # 將結果轉換成NumPy數組kps_float = np.float32([kp.pt for kp in kps])return (kps,kps_float,des)
imageA = cv2.imread("1.jpg")
cv_show( 'imageA',imageA)
imageB = cv2.imread("2.jpg")
cv_show( 'imageB',imageB)
(kpsA,kps_floatA, desA)= detectAndDescribe(imageA)
(kpsB,kps_floatB,desB)= detectAndDescribe(imageB)
matcher =cv2.BFMatcher()
rawMatches =matcher.knnMatch(desB,desA,2)
good =[]
matches =[]
for m in rawMatches:if len(m) == 2 and m[0].distance < 0.65 * m[1].distance:good.append(m)matches.append((m[0].queryIdx, m[0].trainIdx))
print(len(good))
print(matches)
vis = cv2.drawMatchesKnn(imageB, kpsB, imageA, kpsA, good, None,flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
cv_show( "Keypoint Matches",vis)
# 透視變換
if len(matches)>4:ptsB = np.float32([kps_floatB[i]for(i,_)in matches])# matches是通過閾值鍗選之后的特征點對象ptsA = np.float32([kps_floatA[i]for(_,i)in matches])(H, mask) = cv2.findHomography(ptsB, ptsA, cv2.RANSAC, 10)
else:print('圖片未找到4個以上的匹配點')sys.exit()
result = cv2.warpPerspective(imageB, H, (imageB.shape[1]+ imageA.shape[1], imageB.shape[0]))
cv_show( 'resultB',result)
result[0:imageA.shape[0],0:imageA.shape[1]]= imageA
cv_show( 'result', result)
結果顯示:
四、圖像拼接的優缺點
圖像拼接是將多幅具有重疊區域的圖像拼接成一幅全景圖像或高分辨率圖像的技術。以下是圖像拼接的一些優缺點:
優點
獲得全景視野:可以將多幅局部圖像拼接成一幅全景圖像,提供更廣闊的視野,讓人們能夠更全面地觀察場景。例如,在拍攝大型風景、建筑或活動場景時,通過圖像拼接可以將多個局部畫面組合成一個完整的全景畫面,展現出更宏大的場景。
提高圖像分辨率:通過將多幅低分辨率圖像拼接在一起,可以在一定程度上提高圖像的整體分辨率。這對于一些需要高分辨率圖像的應用,如醫學圖像分析、衛星圖像觀測等非常有幫助,可以獲取更多的細節信息。
增強圖像信息:拼接過程中,由于多幅圖像的重疊部分包含了相同場景的不同視角信息,拼接后的圖像能夠融合這些信息,從而增強圖像的細節和紋理,使圖像更加清晰和準確。
靈活性高:可以根據需要選擇不同的圖像進行拼接,適應各種不同的拍攝環境和需求。例如,在不同時間、不同角度拍攝的圖像,只要有適當的重疊區域,都可以進行拼接,以獲得獨特的視覺效果或滿足特定的分析要求。
缺點
圖像配準難度:要實現精確的圖像拼接,需要準確地找到多幅圖像之間的對應關系,即進行圖像配準。如果圖像的特征不明顯、存在光照變化、視角差異較大等情況,圖像配準就會變得困難,可能導致拼接結果出現錯位、變形等問題。
拼接算法復雜度:為了獲得高質量的拼接效果,需要使用復雜的算法來處理圖像的融合、消除拼接縫等問題。這些算法通常需要較高的計算資源和時間成本,特別是對于高分辨率圖像或大量圖像的拼接,計算量會顯著增加,可能導致拼接過程緩慢。
光照和色彩不一致:不同圖像之間可能由于拍攝時間、光線條件、相機設置等因素而存在光照和色彩差異。在拼接過程中,如果不進行有效的處理,這些差異會在拼接處形成明顯的邊界或色彩突變,影響拼接圖像的視覺效果和質量。
遮擋和運動模糊:如果在拍攝過程中,場景中有物體發生運動,或者不同圖像之間存在遮擋情況,那么在拼接時就會出現問題。運動物體在不同圖像中的位置不同,可能導致拼接后出現重影或模糊;而遮擋會使圖像的重疊區域信息不完整,影響拼接的準確性。