OpenCV 圖像拼接

一、圖像拼接的介紹

圖像拼接是一種將多幅具有部分重疊內容的圖像合并成一幅完整、無縫且具有更廣闊視野或更高分辨率圖像的技術。其目的是通過整合多個局部圖像來獲取更全面、更具信息價值的圖像內容。

二、圖像拼接的原理
圖像拼接的核心目標是將多幅有重疊區域的圖像進行準確對齊和融合,形成一個連續、無縫的大圖像。其基本原理主要包括以下幾個關鍵步驟:
特征提取:在每幅圖像中尋找具有代表性的特征點,如角點、邊緣點等。常用的特征提取算法有 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)

結果顯示:

四、圖像拼接的優缺點

圖像拼接是將多幅具有重疊區域的圖像拼接成一幅全景圖像或高分辨率圖像的技術。以下是圖像拼接的一些優缺點:
優點
獲得全景視野:可以將多幅局部圖像拼接成一幅全景圖像,提供更廣闊的視野,讓人們能夠更全面地觀察場景。例如,在拍攝大型風景、建筑或活動場景時,通過圖像拼接可以將多個局部畫面組合成一個完整的全景畫面,展現出更宏大的場景。
提高圖像分辨率:通過將多幅低分辨率圖像拼接在一起,可以在一定程度上提高圖像的整體分辨率。這對于一些需要高分辨率圖像的應用,如醫學圖像分析、衛星圖像觀測等非常有幫助,可以獲取更多的細節信息。
增強圖像信息:拼接過程中,由于多幅圖像的重疊部分包含了相同場景的不同視角信息,拼接后的圖像能夠融合這些信息,從而增強圖像的細節和紋理,使圖像更加清晰和準確。
靈活性高:可以根據需要選擇不同的圖像進行拼接,適應各種不同的拍攝環境和需求。例如,在不同時間、不同角度拍攝的圖像,只要有適當的重疊區域,都可以進行拼接,以獲得獨特的視覺效果或滿足特定的分析要求。
缺點
圖像配準難度:要實現精確的圖像拼接,需要準確地找到多幅圖像之間的對應關系,即進行圖像配準。如果圖像的特征不明顯、存在光照變化、視角差異較大等情況,圖像配準就會變得困難,可能導致拼接結果出現錯位、變形等問題。
拼接算法復雜度:為了獲得高質量的拼接效果,需要使用復雜的算法來處理圖像的融合、消除拼接縫等問題。這些算法通常需要較高的計算資源和時間成本,特別是對于高分辨率圖像或大量圖像的拼接,計算量會顯著增加,可能導致拼接過程緩慢。
光照和色彩不一致:不同圖像之間可能由于拍攝時間、光線條件、相機設置等因素而存在光照和色彩差異。在拼接過程中,如果不進行有效的處理,這些差異會在拼接處形成明顯的邊界或色彩突變,影響拼接圖像的視覺效果和質量。
遮擋和運動模糊:如果在拍攝過程中,場景中有物體發生運動,或者不同圖像之間存在遮擋情況,那么在拼接時就會出現問題。運動物體在不同圖像中的位置不同,可能導致拼接后出現重影或模糊;而遮擋會使圖像的重疊區域信息不完整,影響拼接的準確性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901536.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901536.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901536.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第十一章 網絡編程

在TCP/IP協議中&#xff0c;“IP地址TCP或UDP端口號”唯一標識網絡通訊中的一個進程。 因此可以用Socket來描述網絡連接的一對一關系。 常用的Socket類型有兩種&#xff1a;流式Socket&#xff08;SOCK_STREAM&#xff09;和數據報式Socket&#xff08;SOCK_DGRAM&#xff09…

ffmpeg實現視頻流抽幀

ffmpeg 實現視頻流抽幀 抽取實時視頻幀 如果你的實時視頻是通過 RTSP、UDP 或其他協議獲取的&#xff0c;可以直接調用 FFmpeg 命令來抽取幀。 ffmpeg 命令 示例 1 ffmpeg -i rtsp://your_rtsp_stream_url -vf fps1 -update 1 output.jpg說明&#xff1a; -i rtsp://your…

【GIT】放棄”本地更改,恢復到遠程倉庫的狀態git fetch origin git reset --hard origin/分支名

如果你想完全放棄本地更改&#xff0c;恢復到遠程倉庫的狀態&#xff0c;可以按照以下步驟操作&#xff1a; 獲取遠程最新版本 首先執行&#xff1a; git fetch origin這條命令會把遠程倉庫的最新提交拉取到你的本地&#xff0c;但不會自動合并到你的當前分支。 硬重置你的當前…

flutter doctor 信號號超時

報錯如下&#xff1a; :\Users\Administrator>flutter doctor Doctor summary (to see all details, run flutter doctor -v): [√] Flutter (Channel stable, 3.27.4, on Microsoft Windows [版本 10.0.22631.5189], locale zh-CN) [√] Windows Version (Installed versi…

【Linux】系統入門

【Linux】系統初識 起源開源 閉源版本內核內核編號 Linux的安裝雙系統(不推薦)WindowsLinuxvmware虛擬機vitualbox操作系統的鏡像centos 7/ubuntu云服務器租用 Linux的操作lsmkdir 文件名pwdadduser userdel -rrm文件名cat /proc/cpuinfolinux支持編程vim code.c./a.out 運行程…

mybatis-plus整合springboot與使用方式

注解 TableField(exist false)&#xff1a;表示該屬性不為數據庫表字段&#xff0c;但又是必須使用的。 整合springboot pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xs…

[第十六屆藍橋杯 JavaB 組] 真題 + 經驗分享

A&#xff1a;逃離高塔(AC) 這題就是簡單的簽到題&#xff0c;按照題意枚舉即可。需要注意的是不要忘記用long&#xff0c;用int的話會爆。 &#x1f4d6; 代碼示例&#xff1a; import java.io.*; import java.util.*; public class Main {public static PrintWriter pr ne…

GPU服務器聲音很響可以怎么處理

當GPU服務器運行時噪音過大&#xff0c;通常是由于高負載下散熱風扇高速運轉所致。以下是分步驟的解決方案&#xff0c;幫助您有效降低噪音并保持設備穩定運行&#xff1a; 一、排查噪音來源 定位聲源 ? 使用 聲級計 或手機分貝檢測APP&#xff0c;確定最大噪音位置&#xff0…

STM32平衡車開發實戰教程:從零基礎到項目精通

STM32平衡車開發實戰教程&#xff1a;從零基礎到項目精通 一、項目概述與基本原理 1.1 平衡車工作原理 平衡車是一種基于倒立擺原理的兩輪自平衡小車&#xff0c;其核心控制原理類似于人類保持平衡的過程。當人站立不穩時&#xff0c;會通過腿部肌肉的快速調整來維持平衡。平…

C#設計模式-狀態模式

狀態模式案例解析&#xff1a;三態循環燈的實現 案例概述 本案例使用 狀態模式&#xff08;State Pattern&#xff09; 實現了一個 三態循環燈 的功能。每點擊一次按鈕&#xff0c;燈的狀態會按順序切換&#xff08;狀態1 → 狀態2 → 狀態3 → 狀態1...&#xff09;&#xff…

Mac系統升級node.js版本和npm版本并安裝pnpm

1.升級node.js版本 第一步&#xff1a;查詢當前node.js版本 node -v第二步&#xff1a;清除node.js的緩存 sudo npm cache clean -f第三步&#xff1a;驗證緩存是否清空 npm cache verify第四步&#xff1a;安裝n工具&#xff0c;n工具是專門用于管理node.js版本的工具 su…

[net 5] udp_dict_server 基于udp的簡單字典翻譯(服務器與業務相分離)

目錄 1. 功能了解 1.1. 啥是 dic_server? 1.2. dic_server 的小目標 2. 基本框架 2.1. 基本文件框架 2.2. 業務與服務器解耦 -> 回調函數 3. 字典 3.1. 字典配置文件 3.2. 構建字典類 3.2.1. 字典類的基本成員 3.2.2. 字典類構造 3.2.2.1. 構造 3.2.2.2. 信息加…

七種驅動器綜合對比——《器件手冊--驅動器》

九、驅動器 名稱 功能與作用 工作原理 優勢 應用 隔離式柵極驅動器 隔離式柵極驅動器用于控制功率晶體管&#xff08;如MOSFET、IGBT、SiC或GaN等&#xff09;的開關&#xff0c;其核心功能是將控制信號從低壓側傳輸到高壓側的功率器件柵極&#xff0c;同時在輸入和輸出之…

EM儲能網關ZWS智慧儲能云應用(8) — 電站差異化支持

面對不同項目、種類繁多的儲能產品&#xff0c;如何在儲能云平臺上進行電站差異化支持尤為關鍵&#xff0c;ZWS智慧儲能云從多方面支持儲能電站差異化。 簡介 隨著行業發展&#xff0c;市場“內卷”之下&#xff0c;各大儲能企業推陳出新的速度加快。面對不同項目、種類繁多…

圖像預處理-色彩空間補充,灰度化與二值化

一.圖像色彩空間轉換 1.1 HSV顏色空間 HSV顏色空間使用色調&#xff08;Hue&#xff09;、飽和度&#xff08;Saturation&#xff09;和亮度&#xff08;Value&#xff09;三個參數來表示顏色 一般對顏色空間的圖像進行有效處理都是在HSV空間進行的&#xff0c;然后對于基本…

Midnight Flag CTF 2025

周末還是三個比賽&#xff0c;可惜不好弄。不是遠端連不上就是遠端打不開。再有就是太難了。 Crypto ABC 這個題還是不算難的。給了兩個30位數的平方和&#xff0c;并且pu1*baser0,qu2*baser1其中r 都很小&#xff0c;可以copper。 只是sage里的two_squres不管用&#xff0…

深度學習--激活函數

激活函數通過計算加權和并加上偏置來確定神經元是否應該倍激活&#xff0c;它們將輸入信號轉換為輸出的可微運算。大多數激活函數都是非線性的&#xff0c;由于激活函數是深度學習的基礎&#xff0c;下面簡要介紹一些常見的激活函數。 1 RelU函數 最受歡迎的激活函數是修正線性…

深入解析 OrdinalEncoder 與 OneHotEncoder:核心區別與實戰應用

標題&#xff1a;深入解析 OrdinalEncoder 與 OneHotEncoder&#xff1a;核心區別與實戰應用 摘要&#xff1a; 本文詳細探討了機器學習中類別特征編碼的兩種核心方法——OrdinalEncoder 和 OneHotEncoder。通過對比兩者的功能、特點、適用場景及代碼實現&#xff0c;幫助讀者…

CTF web入門之命令執行 完整版

web29 文件名過濾 由于flag被過濾,需要進行文件名繞過,有以下幾種方法: 1.通配符繞過 fla?.* 2.反斜杠繞過 fl\ag.php 3.雙引號繞過 fl’‘ag’.php 還有特殊變量$1、內聯執行等 此外 讀取文件利用cat函數,輸出利用system、passthru 、echo echo `nl flag.php`; ec…

【Linux實踐系列】:用c/c++制作一個簡易的進程池

&#x1f525; 本文專欄&#xff1a;Linux Linux實踐項目 &#x1f338;作者主頁&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客勵志語錄&#xff1a; 人生沒有標準答案&#xff0c;你的錯題本也能寫成傳奇。 ★★★ 本文前置知識&#xff1a; 匿名管道 1.前置知識回顧…