问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

双目相机标定与点云生成:从原理到实现

创作时间:
作者:
@小白创作中心

双目相机标定与点云生成:从原理到实现

引用
CSDN
1.
https://blog.csdn.net/qq_39333636/article/details/144271872

本文详细介绍了从双目相机标定到点云生成的完整流程,包括相机标定、图片畸变矫正、极线矫正、视差图计算、深度图生成以及点云显示等关键步骤。通过本文,读者可以系统地学习双目视觉技术的核心内容,并通过提供的代码实现这些功能。

大致思路

双目视觉系统通过模拟人眼的视觉原理,利用两个摄像头同时拍摄同一场景,通过计算图像之间的差异(即视差)来获取深度信息,进而生成3D点云。整个过程主要包括以下几个步骤:

  1. 相机标定:获取每个相机的内参和外参,这是后续所有计算的基础。
  2. 图片畸变矫正:消除镜头畸变对图像质量的影响。
  3. 极线矫正:将立体匹配问题从二维空间降低到一维,提高计算效率。
  4. 视差图计算:通过立体匹配算法(如SGBM)计算左右图像之间的视差。
  5. 深度图生成:根据视差图计算每个像素点的深度信息。
  6. 点云生成:结合深度信息和颜色信息,生成3D点云。


点云数据展示,将图片像右旋转45°即和图片视角一致。

一、相机标定

相机标定是整个流程中最关键的一步,它获取了相机的内参和外参,这些参数用于后续的所有计算。

1. 相机参数介绍

相机参数主要包括内参和外参:

  • 内参:包括焦距、像主点坐标、畸变参数等,共有11个参数变量。
  • 外参:包括旋转矩阵和平移向量,用于描述两个摄像头之间的相对位置和姿态。

2. 单目相机标定

单目相机标定通常使用张正友标定法,需要准备一个标定板并拍摄多张照片。但要获得高精度的结果较为困难,因此本文选择使用已标定好的数据集。

3. 双目相机标定

双目相机标定除了求解每个摄像头的内参外,还需要求解两个摄像头之间的相对位置和姿态(外参)。例如,外参矩阵中的平移向量可以表示两个相机镜头之间的距离(基线长度)。

二、图片畸变矫正

使用相机的内参和畸变参数对图像进行矫正,消除镜头畸变的影响。OpenCV提供了cv.undistort函数实现这一功能:

void undistort( InputArray src, //输入原图
                OutputArray dst,//输出矫正后的图像
                InputArray cameraMatrix,//内参矩阵
                InputArray distCoeffs,//畸变系数
                InputArray newCameraMatrix=noArray() );

三、极线矫正

极线矫正将立体匹配问题从二维空间降低到一维,显著提高计算效率。具体步骤如下:

1. 极线矫正

通过极线矫正,可以将匹配过程从整张图片(二维空间)降低到一维空间。具体实现代码如下:

# 读取图像
imgl = cv.imread('1_L.jpg')
imgr = cv.imread('1_R.jpg')
high, wide = imgl.shape[0:2]

# 读取相机参数
config = stereoCamera()

# 消除图像畸变
imgl_qb = cv.undistort(imgl, config.cam_matrix_l, config.distortion_l)
imgr_qb = cv.undistort(imgr, config.cam_matrix_r, config.distortion_r)

# 极线校正
map1x, map1y, map2x, map2y, Q = getRectifyTransform(high, wide, config)
imgl_jx, imgr_jx = rectifyImage(imgl_qb, imgr_qb, map1x, map1y, map2x, map2y)

# 绘制等间距平行线,检查效果
line = draw_line(imgl_jx, imgr_jx)

2. 投影矩阵Q

Q矩阵在生成3D点云时会用到,具体细节可参考相关文献。

3. 图片检查

极线矫正后的图片需要进行检查,确保左右图像在同一个平面内的点投影到同一条直线上。检查结果如下图所示:


极线矫正后的图片检查结果

四、SGBM局部匹配算法计算视差图

SGBM(Semi-Global Block Matching)是一种常用的立体匹配算法,用于计算视差图。

1. 设置立体匹配算法SGBM

SGBM算法的参数设置对结果影响较大,需要根据具体场景进行调整。关键参数包括窗口大小(blockSize)、最大最小视差等。具体实现代码如下:

def opencv_SGBM(left_img, right_img, use_wls=False):
    blockSize = 11
    paramL = {"minDisparity": 0,
              "numDisparities": 170,
              "blockSize": blockSize,
              "P1": 8 * 3 * blockSize * blockSize,
              "P2": 32 * 3 * blockSize * blockSize,
              "disp12MaxDiff": 1,
              "uniquenessRatio": 10,
              "speckleWindowSize": 50,
              "speckleRange": 1,
              "preFilterCap": 31,
              "mode": cv.STEREO_SGBM_MODE_SGBM_3WAY
              }
    matcherL = cv.StereoSGBM_create(**paramL)
    dispL = matcherL.compute(left_img, right_img)

    if use_wls:
        paramR = paramL
        paramR['minDisparity'] = -paramL['numDisparities']
        matcherR = cv.StereoSGBM_create(**paramR)
        dispR = matcherR.compute(right_img, left_img)
        filter = cv.ximgproc.createDisparityWLSFilter(matcher_left=matcherL)
        filter.setLambda(80000)
        filter.setSigmaColor(1.0)
        dispL = filter.filter(dispL, left_img, None, dispR)

    dispL = cv2.bilateralFilter(dispL.astype(np.float32), d=9, sigmaColor=75, sigmaSpace=75)
    dispL[dispL < 0] = 1e-6
    dispL = dispL.astype(np.int16)
    dispL = dispL / 16.0
    return dispL

2. WLS滤波平滑优化

WLS(Weighted Least Squares)滤波可以对视差图进行平滑处理,提高图像质量。具体实现代码已在上一步中给出。

五、通过视差图计算深度图

根据视差图计算深度图,深度计算公式为z = (f * b) / d,其中f是焦距,b是基线长度,d是视差值。需要注意单位的统一,例如fd的单位是像素,b的单位是米,计算出的深度单位也是米。

六、通过视差图和Q矩阵计算点云

通过视差图和Q矩阵可以计算出每个像素点的三维坐标,并结合颜色信息生成点云。具体实现代码略。

七、点云显示

点云数据量较大,可以在本地或在线展示。虽然可以在线展示点云,但通常没有颜色信息,直观性较差。

反思

在实际操作中,可能会遇到视差图生成后深度图显示异常的问题。这通常是因为视差图中存在大量接近0的数值,导致深度计算结果异常。解决方法是将这些异常值赋值为最小有效视差值,并通过直方图分析视差图的数值分布,确保数据的合理性。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号