用Python和OpenCV從零搭建一個完整的雙目視覺系統(四)

本系列文章旨在系統性地闡述如何利用 Python 與 OpenCV 庫,從零開始構建一個完整的雙目立體視覺系統。

本項目github地址:https://github.com/present-cjn/stereo-vision-python.git

在上一篇文章中,我們完成了相機標定這一最關鍵的基礎步驟,并得到了一份高精度的相機參數文件。現在,我們將利用這份參數文件,來執行雙目視覺的核心任務——立體匹配 (Stereo Matching)

我們的目標是,模仿人類大腦處理左右眼圖像差異的方式,為左圖中的每一個像素,在右圖中找到它的對應點。通過計算它們之間的像素位置差異,即視差 (Disparity),我們就能得到一張灰色的、包含深度信息的圖像——視差圖 (Disparity Map)。這張圖上的每一個像素點的強度值,都直接對應著真實世界的深度信息。

本文將詳細講解立體匹配的全過程,從準備工作“立體校正”,到核心算法“SGBM”,再到決定最終效果的“參數調優”。

1. 匹配前的準備:立體校正 (Rectification)

在原始的雙目圖像中,由于相機安裝可能存在微小的角度偏差,左圖中的一個點,其在右圖中的對應點可能位于一條傾斜的直線上(我們稱之為“對極線”)。在整張圖上沿著成千上萬條斜線去搜索匹配點,計算量巨大且效率低下。

立體校正 (Stereo Rectification) 的目的,就是通過數學變換,將這種復雜的二維搜索問題,簡化為高效的一維搜索。

  • 目標: 利用標定得到的旋轉矩陣 R 和平移向量 T,對左右圖像進行虛擬的旋轉,使得兩個相機的成像平面完全共面,并且像素行嚴格對齊。
  • 效果: 校正后,對于左圖上的任意一個像素點 (x, y),其在右圖上的對應點必定位于同一水平線 y。現在,算法只需要在這一行上進行一維搜索即可,效率和可靠性都大大提升。

原左右圖像為

極線校正后左右圖像為

代碼實現 (utils/image_utils.py)

我們的 rectify_stereo_pair 函數封裝了整個校正過程。

# utils/image_utils.py
def rectify_stereo_pair(left_img, right_img, stereo_params, calib_image_size):# 從標定參數中提取 K, D, R, T 矩陣K1, D1, K2, D2, R, T = (stereo_params[k] for k in ('K1', 'D1', 'K2', 'D2', 'R', 'T'))# 1. 計算校正變換和投影矩陣# 這一步是核心,它計算出將相機坐標系旋轉到理想平行狀態所需的旋轉矩陣 R1, R2# 以及將3D點投影到校正后圖像平面上的投影矩陣 P1, P2# 最重要的是,它還輸出了用于三維重建的 Q 矩陣R1, R2, P1, P2, Q, _, _ = cv2.stereoRectify(K1, D1, K2, D2, calib_image_size, R, T, alpha=0)# 2. 計算從原始圖像到校正圖像的像素映射表# `initUndistortRectifyMap` 會為每個像素計算出它在校正后圖像中的新位置left_map1, left_map2 = cv2.initUndistortRectifyMap(K1, D1, R1, P1, left_img.shape[1::-1], cv2.CV_16SC2)right_map1, right_map2 = cv2.initUndistortRectifyMap(K2, D2, R2, P2, right_img.shape[1::-1], cv2.CV_16SC2)# 3. 應用映射表,執行校正left_rectified = cv2.remap(left_img, left_map1, left_map2, cv2.INTER_LINEAR)right_rectified = cv2.remap(right_img, right_map1, right_map2, cv2.INTER_LINEAR)return left_rectified, right_rectified, Q

這個函數的輸出,就是我們進行立體匹配所需要的、高質量的校正圖像和Q矩陣。

2. 核心算法:SGBM (Semi-Global Block Matching)

現在我們有了對齊的左右圖像,接下來就要計算視差了。本項目采用的是 SGBM (半全局塊匹配) 算法,它是對傳統 BM (塊匹配) 算法的巨大改進。

  • 基本思想: 它不僅像 BM 算法那樣,通過比較小像素塊的相似度(SAD)來尋找匹配,更引入了一個“全局”的視角。它會懲罰那些導致視差劇烈跳變的匹配,鼓勵生成一條平滑、連續的視差路徑。
  • 優勢: 相比 BM,SGBM 能更好地處理弱紋理區域(如白墻)和重復紋理區域,生成的視差圖更完整、噪聲更少。
代碼實現 (processing/stereo_matcher.py)

我們將 SGBM 的所有邏輯都封裝在 StereoMatcher 類中。

# processing/stereo_matcher.py
import cv2
import configclass StereoMatcher:def __init__(self):# 在構造函數中,從 config.py 文件一次性加載所有 SGBM 參數# 這使得調參變得非常方便self.matcher = cv2.StereoSGBM_create(minDisparity=config.SGBM_MIN_DISPARITY,numDisparities=config.SGBM_NUM_DISPARITIES,blockSize=config.SGBM_BLOCK_SIZE,P1=config.SGBM_P1,P2=config.SGBM_P2,disp12MaxDiff=config.SGBM_DISP12_MAX_DIFF,preFilterCap=config.SGBM_PRE_FILTER_CAP,uniquenessRatio=config.SGBM_UNIQUENESS_RATIO,speckleWindowSize=config.SGBM_SPECKLE_WINDOW_SIZE,speckleRange=config.SGBM_SPECKLE_RANGE,mode=config.SGBM_MODE)def compute_disparity(self, left_rectified_img, right_rectified_img):# SGBM 算法要求輸入單通道的灰度圖gray_left = cv2.cvtColor(left_rectified_img, cv2.COLOR_BGR2GRAY)gray_right = cv2.cvtColor(right_rectified_img, cv2.COLOR_BGR2GRAY)# 計算視差圖disparity_map = self.matcher.compute(gray_left, gray_right)return disparity_map

4. 視差圖的秘密:*16 的含義

當你拿到 compute 函數返回的 disparity_map 時,需要注意一個關鍵細節:它的數據類型是 CV_16S(16位有符號整數),并且里面的值是真實視差的16倍

這是 OpenCV 為了在內部用高效的整數運算來表示亞像素精度而做的設計。一個值為 800 的點,其真實的、以像素為單位的視差是 800 / 16.0 = 50.0

因此,當我們需要使用或顯示真實的視差值時,必須記得將它除以16.0

用項目的中的測試圖片可以得到以下視差圖

總結

通過立體校正的預處理和強大的 SGBM 算法,我們成功地從兩張2D圖像中提取出了包含深度信息的視差圖。更重要的是,我們學會了如何通過交互式調參來優化匹配結果,這是所有立體視覺應用開發者的核心技能之一。

在下一篇文章中,我們將進入一個核心步驟:利用這張高質量的視差圖和 Q 矩陣,計算出深度圖并重建出真正的三維點云。

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

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

相關文章

STM32-中斷

中斷分為兩路:12345用于產生中斷;678產生事件外設為NVIC設計流程:使能外設中斷設置中斷優先級分組初始化結構體編寫中斷服務函數初始化結構體:typedef struct {uint8_t NVIC_IRQChannel; 指定要使能或禁用的中斷通道例如: TIM3_I…

Shader面試題100道之(61-80)

Shader面試題(第61-80題) 以下是第61到第80道Shader相關的面試題及答案: 61. 什么是UV展開?它在Shader中有什么作用? UV展開是將3D模型表面映射到2D紋理空間的過程,用于定義紋理如何貼合模型。在Shader中&a…

C#基礎:Winform桌面開發中窗體之間的數據傳遞

1.主窗體using System; using System.Windows.Forms;public partial class MainForm : Form {public MainForm(){InitializeComponent();}// 打開二級窗體private void btnOpenSecondaryForm_Click(object sender, EventArgs e){// 創建二級窗體并訂閱事件SecondaryForm second…

工程改Mvvm

導入CommunityToolKit vs2017只能導入7 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input;namespace WpfApp1.vi…

【HarmonyOS Next之旅】DevEco Studio使用指南(四十二) -> 動態修改編譯配置

目錄 1 -> 通過hook以及插件上下文實現動態配置 2 -> 在hvigorfile.ts中通過overrides關鍵字導出動態配置 3 -> 通過hook以及插件上下文動態配置構建配置 3.1 -> 修改每個hvigorNode中的build-profile.json5 3.2 -> 修改module.json5中的配置信息 3.3 -&g…

Android View事件分發機制詳解

Android 的 View 事件分發機制是處理用戶觸摸(Touch)事件的核心流程,它決定了觸摸事件如何從系統傳遞到具體的 View 并被消費。理解這個機制對于處理復雜的觸摸交互、解決滑動沖突至關重要。 核心思想:責任鏈模式 事件分發遵循一個…

【CMake】自定義package并通過find_package找到

在一些場景下我們需要編寫一些庫,并希望其他程序可以找到這些庫并引用。 CMake采用package這個概念來解決這個問題。 關于CMake的find_package文章有很多,但這些文章的內容大多不直觀講了一堆講不到點子上,讓人看了一頭霧水。因此我想通過本文…

【MATLAB例程】AOA與TDOA混合定位例程,適用于二維環境、3個錨點的定位|附代碼下載鏈接

本 MATLAB 程序實現了基于 Angle of Arrival (AOA) 與 Time Difference of Arrival (TDOA) 的二維定位方法,通過自適應融合與最小二乘優化,實現對未知目標的高精度估計。本例中固定使用了 3 個基站(錨點),算法框架支持…

磐維數據庫panweidb集中式集群配置VIP【添加、刪除和修改】

0 說明 panweidb集中式集群為了防止主備切換后應用連接無法切換到新主庫,需要配置vip,應用可以只通過該ip與數據庫連接,不用感知數據庫在哪個節點上。 panweidb中配置 VIP主要依賴 CM 組件的 VIP 仲裁功能,通過回調腳本在主備切換…

python的保險業務管理與數據分析系統

前端開發框架:vue.js 數據庫 mysql 版本不限 后端語言框架支持: 1 java(SSM/springboot)-idea/eclipse 2.NodejsVue.js -vscode 3.python(flask/django)–pycharm/vscode 4.php(thinkphp/laravel)-hbuilderx 數據庫工具:Navicat/SQLyog等都可以 保險行業…

R語言如何接入實時行情接口

目錄 1. 安裝必要的R包 2. 導入庫 3. 連接WebSocket 4. 處理連接成功后的操作 5. 處理接收到的消息 6. 處理連接關閉和錯誤 7. 發送心跳數據 8. 自動重連機制 9. 啟動連接和重連 總結 在數據分析和金融研究中,實時行情數據的獲取至關重要,但市…

Redis數據安全性分析

Redis高可用與數據安全機制深度解析前置知識:Redis基礎安裝與使用(主從復制、哨兵集群、Cluster集群搭建)一、Redis性能壓測工具 工具名稱:redis-benchmark核心作用:快速基準測試Redis性能使用場景:評估不同…

差分和前綴和

差分和前綴和的原理、用法和區別。前綴和(Prefix Sum)核心思想:預處理數組的前綴和,快速回答「區間和查詢」 適用場景:數組靜態(更新少、查詢多),需要頻繁計算任意區間的和1. 定義與…

C++并發編程-12. 用內存順序實現內存模型

前情回顧 前文我們介紹了六種內存順序,以及三種內存模型,本文通過代碼示例講解六種內存順序使用方法,并實現相應的內存模型。全局一致性模型同步模型(獲取和釋放)松散模型memory_order_seq_cst memory_order_seq_cst代表全局一致性順序&#…

AI測試革命:從智能缺陷檢測到自愈式測試框架的工業實踐

AI測試革命:從智能缺陷檢測到自愈式測試框架的工業實踐 希望對大家有用! 目錄AI測試革命:從智能缺陷檢測到自愈式測試框架的工業實踐希望對大家有用!一、傳統測試之殤:工業質檢的切膚之痛二、智能缺陷檢測系統架構1. …

二、深度學習——損失函數

二、損失函數損失函數定義:損失函數是用來衡量模型參數的質量的函數,衡量方式是比較網絡輸出和真實輸出的差異別名:損失函數(loss function),代價函數(cost function),目…

面向數據報的套接字通道技術詳解

數據報通道基礎 通道特性與創建方式 java.nio.channels.DatagramChannel類實例代表數據報通道,默認處于阻塞模式。通過configureBlocking(false)方法可將其配置為非阻塞模式。創建數據報通道需調用其靜態open()方法,若用于IP組播則需指定組播組的地址類型…

147.在 Vue3 中使用 OpenLayers 地圖上 ECharts 模擬飛機循環飛行

🧩 效果預覽 👇 飛機從多個城市起飛并向其他城市飛行,動畫流暢,地圖可縮放拖拽: 📦 一、項目技術棧 技術用途Vue 3現代前端框架OpenLayers地圖底圖渲染ECharts ol-echarts飛機飛行動畫渲染ol-echarts將 …

OCR與PDF解析的區別

我們日常所接觸的文檔中,經常能碰到多語言混合的文檔。比如論文試卷、財報研報、跨國票據都含有多種語言和文字。要將文檔中的內容識別并提取務必需要使用到OCR技術,而傳統的OCR工具在處理這類型文檔的時候有局限性。早期的 OCR 系統識別精度有限&#x…

Java 單例類詳解:從基礎到高級,掌握線程安全與高效設計

作為一名Java開發工程師,你一定對**單例模式(Singleton Pattern)**不陌生。它是23種經典設計模式中最簡單也是最常用的一種,用于確保一個類在整個應用程序中只有一個實例存在。單例廣泛應用于系統配置、數據庫連接池、日志管理器、…