【立体匹配】:双目立体匹配SGBM:(1)运行
注:这是一个专题,我会一步步介绍SGBM的实现,按照我的使用和优化过程逐步改善算法,附带实现方法
系列文章
- 【立体匹配】:双目立体匹配SGBM:(1)运行
【立体匹配】:双目立体匹配SGBM:(1)运行
- 双目立体匹配SGBM概述
- SGBM参数配置方法
- 性能优化策略
- 常见问题与解决方案
- 具体使用
- sgbm的python类接口
双目立体匹配SGBM概述
SGBM(Semi-Global Block Matching)是一种结合局部和全局优化的立体匹配算法,通过代价聚合和动态规划实现视差计算。其核心包括代价计算、代价聚合、视差计算和视差优化四个步骤。
SGBM参数配置方法
OpenCV中SGBM的关键参数如下:
import cv2
sgbm = cv2.StereoSGBM_create( minDisparity=0, # 最小视差 numDisparities=64, # 视差范围(需为16的倍数) blockSize=3, # 匹配块大小(奇数) P1=8*3*3, # 平滑性惩罚参数1 P2=32*3*3, # 平滑性惩罚参数2 disp12MaxDiff=1, # 左右视差检查阈值 preFilterCap=63, # 预处理滤波截断值 uniquenessRatio=15, # 唯一性匹配比率 speckleWindowSize=100, # 视差连通区域滤波窗口 speckleRange=32 # 视差连通性阈值
)
性能优化策略
参数调优
- 增大
numDisparities
可提升深度范围但会增加计算量,建议根据实际场景调整。 P1
和P2
控制视差平滑性,通常设为P1=8*通道数*blockSize^2
,P2=4*P1
。
预处理增强
- 使用直方图均衡化或CLAHE增强图像对比度:
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
left_img = clahe.apply(left_img)
后处理优化
- 采用WLS(加权最小二乘)滤波消除噪声:
wls_filter = cv2.ximgproc.createDisparityWLSFilter(sgbm)
filtered_disp = wls_filter.filter(disp, left_img)
常见问题与解决方案
边缘模糊
- 原因:
blockSize
过大导致过度平滑。 - 解决:减小
blockSize
或使用导向滤波优化视差图。
视差不连续
- 原因:
uniquenessRatio
过低或噪声干扰。 - 解决:增大
uniquenessRatio
至10-20,或启用speckleWindowSize
滤波。
具体使用
sgbm的python类接口
import cv2
import numpy as np
import time
cv2.setNumThreads(4) # 设置最大线程
cv2.setUseOptimized(True)
class SGBM:def __init__(self, use_blur=True):self.prev_disp = Noneself.alpha = 0.3 # 平滑系数 (0-1),越小越平滑self.use_blur = use_blurself.sgbm = self.create_sgbm()def create_sgbm(self):window_size = 5min_disp = 0num_disp = 64 - min_disp # 必须是16的整数倍stereo = cv2.StereoSGBM_create(minDisparity=min_disp,numDisparities=num_disp,blockSize=window_size,P1=8 * 3 * window_size**2, # 视差平滑参数P2=32 * 3 * window_size**2,disp12MaxDiff=1,uniquenessRatio=10,speckleWindowSize=100,speckleRange=32,mode=cv2.STEREO_SGBM_MODE_SGBM_3WAY# STEREO_SGBM_MODE_SGBM_3WAY ,STEREO_SGBM_MODE_HH, STEREO_SGBM_MODE_SGBM, STEREO_SGBM_MODE_HH4,STEREO_SGBM_MODE_HH4的速度最快,STEREO_SGBM_MODE_HH的精度最好)return stereodef create_bm_matcher(self):stereo = cv2.StereoBM_create(numDisparities=64, # 视差范围(必须是16的倍数)blockSize=15 # 匹配块大小(奇数,建议5~25))return stereodef estimate_depth(self, left_image, right_image):"""进行深度估计推理,返回视差图(深度图)。"""# 转换为灰度图gray_left = cv2.cvtColor(left_image, cv2.COLOR_BGR2GRAY)gray_right = cv2.cvtColor(right_image, cv2.COLOR_BGR2GRAY)# clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))# gray_left = clahe.apply(gray_left)# gray_right = clahe.apply(gray_right)# gray_left = cv2.equalizeHist(gray_left)# gray_right = cv2.equalizeHist(gray_right)disp = self.sgbm.compute(gray_left, gray_right).astype(np.float32) / 16.0 # SGBM返回的视差需要除以16# # 应用选择的滤波器# if current_filter in ['guided', 'wls', 'fgs']:# disp = apply_disparity_filter(# disp, left_image, current_filter,# lambda_=8000, sigma=1.5# )# else:# disp = apply_disparity_filter(disp, filter_type=current_filter)if self.prev_disp is not None:disp = self.alpha * disp + (1 - self.alpha) * self.prev_dispself.prev_disp = disp.copy()# disp = cv2.medianBlur(disp, 5) # 中值滤波disp = cv2.morphologyEx(disp, cv2.MORPH_CLOSE, np.ones((5,5),np.uint8)) # 闭运算填充空洞return disp
在这个类里,默认调用sgbm方法,也可以切换bm算法,速度更快,但是视差图的空洞更多
import cv2
import numpy as npfrom stereomodel.OpencvSGBM.utils.SGBM import SGBM
from config import StereoSGBM_ins = SGBM(use_blur=True)
Stereo_ins = Stereo()
if __name__ == '__main__':left_img = cv2.imread('../../data/mid/im0.png')right_img = cv2.imread('../../data/mid/im1.png')disp = SGBM_ins.estimate_depth(left_img, right_img)Stereo_ins.show_depth_point(disp, left_img)
sgbm方法
bm方法