双目立体视觉三维重建

双目立体视觉三维重建双目立体视觉的整体流程包括 图像获取 双目标定 双目矫正 立体匹配 三维重建 StereoVision OpenGL 双目立体视觉三维重建 OpenCV 双目测距 双目标定 双目校正和立体匹配 真实场景的双目立体匹配 StereoMatchi 获取深度图详解图像获取双目相机拍摄获取左右目图像双目标定内参外参相

Overview

欢迎访问 持续更新:https://cgabc.xyz/posts/aa4d53ac/

双目立体视觉的整体流程包括:

  • 图像采集
  • 双目标定
  • 双目矫正
  • 立体匹配
  • 三维重建
双目立体视觉三维重建

1. 图像采集

双目相机采集 左右目图像

2. 双目标定

通过 双目标定工具 对双目相机进行标定,得到如下结果参数:

内参 外参
相机矩阵 K 1 , K 2 K_1, K_2 K1,K2 旋转矩阵 R R R
畸变系数 D 1 , D 2 D_1, D_2 D1,D2 平移向量 t t t

《Learning OpenCV》中对于 Translation 和 Rotation 的图示是这样的:

双目立体视觉三维重建

示例代码:

cv::Matx33d K1, K2, R; cv::Vec3d T; cv::Vec4d D1, D2; int flag = 0; flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC; flag |= cv::fisheye::CALIB_CHECK_COND; flag |= cv::fisheye::CALIB_FIX_SKEW; cv::fisheye::stereoCalibrate( obj_points_, img_points_l_, img_points_r_, K1, D1, K2, D2, img_size_, R, T, flag, cv::TermCriteria(3, 12, 0)); 

3. 双目矫正

双目矫正 主要包括两方面:畸变矫正立体矫正

利用 OpenCV的函数,主要分为

  • stereoRectify
  • initUndistortRectifyMap
  • remap

stereoRectify

根据双目标定的结果 K 1 , K 2 , D 1 , D 2 , R , t K_1, K_2, D_1, D_2, R, t K1,K2,D1,D2,R,t,利用 OpenCV函数 stereoRectify,计算得到如下参数

  • 左目 矫正矩阵(旋转矩阵) R 1 R_1 R1 (3×3)
  • 右目 矫正矩阵(旋转矩阵) R 2 R_2 R2 (3×3)
  • 左目 投影矩阵 P 1 P_1 P1 (3×4)
  • 右目 投影矩阵 P 2 P_2 P2 (3×4)
  • disparity-to-depth 映射矩阵 Q Q Q (4×4)

其中,

左右目投影矩阵(horizontal stereo, c x 1 ′ = c x 2 ′ {c_x}_1’={c_x}_2′ cx1=cx2 if CV_CALIB_ZERO_DISPARITY is set)

P 1 = [ f ′ 0 c x 1 ′ 0 0 f ′ c y ′ 0 0 0 1 0 ] P_1 = \begin{bmatrix} f’ & 0 & {c_x}_1′ & 0 \\ 0 & f’ & c_y’ & 0 \\ 0 & 0 & 1 & 0 \end{bmatrix} P1=
f000f0cx1cy1000

P 2 = [ f ′ 0 c x 2 ′ t x ′ ⋅ f ′ 0 f ′ c y ′ 0 0 0 1 0 ] P_2 = \begin{bmatrix} f’ & 0 & {c_x}_2′ & t_x’ \cdot f’ \\ 0 & f’ & c_y’ & 0 \\ 0 & 0 & 1 & 0 \end{bmatrix} P2=
f000f0cx2cy1txf00

where

t x ′ = − B t_x’ = -B tx=B

disparity-to-depth 映射矩阵

Q = [ 1 0 0 − c x 1 ′ 0 1 0 − c y ′ 0 0 0 f ′ 0 0 − 1 t x ′ c x 1 ′ − c x 2 ′ t x ′ ] Q = \begin{bmatrix} 1 & 0 & 0 & -{c_x}_1′ \\ 0 & 1 & 0 & -c_y’ \\ 0 & 0 & 0 & f’ \\ 0 & 0 & -\frac{1}{t_x’} & \frac{ {c_x}_1′-{c_x}_2′}{t_x’} \end{bmatrix} Q=
10000100000tx1cx1cyftxcx1cx2

通过 P 2 P_2 P2 可计算出 基线 长度:

baseline = B = − t x ′ = − P 2 ( 03 ) f ′ \begin{aligned} \text{baseline} = B = – t_x’ = – \frac{ {P_2}_{(03)} }{f’} \end{aligned} baseline=B=tx=fP2(03)

示例代码:

cv::Mat R1, R2, P1, P2, Q; cv::fisheye::stereoRectify( K1, D1, K2, D2, img_size_, R, T, R1, R2, P1, P2, Q, CV_CALIB_ZERO_DISPARITY, img_size_, 0.0, 1.1); 

CameraInfo DKRP

参考:sensor_msgs/CameraInfo Message

  • D: distortion parameters.
    • For “plumb_bob”, the 5 parameters are: (k1, k2, t1, t2, k3)
  • K: Intrinsic camera matrix for the raw (distorted) images.
    • Projects 3D points in the camera coordinate frame to 2D pixel coordinates using the focal lengths (fx, fy) and principal point (cx, cy).
      K = [ f x 0 c x 0 f y c y 0 0 1 ] \mathbf{K} = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} K=
      fx000fy0cxcy1


  • R: Rectification matrix (stereo cameras only).
    • A rotation matrix aligning the camera coordinate system to the ideal stereo image plane so that epipolar lines in both stereo images are parallel.
    • For monocular cameras R = I \mathbf{R} = \mathbf{I} R=I
  • P: Projection/camera matrix.
    • For monocular cameras
      P = [ f x 0 c x 0 0 f y c y 0 0 0 1 0 ] \mathbf{P} = \begin{bmatrix} f_x & 0 & c_x & 0 \\ 0 & f_y & c_y & 0 \\ 0 & 0 & 1 & 0 \end{bmatrix} P=
      fx000fy0cxcy1000


    • For a stereo pair, the fourth column [Tx Ty 0]’ is related to the position of the optical center of the second camera in the first camera’s frame. We assume Tz = 0 so both cameras are in the same stereo image plane.
      • The first camera
        P = [ f x ′ 0 c x ′ 0 0 f y ′ c y ′ 0 0 0 1 0 ] \mathbf{P} = \begin{bmatrix} f_x’ & 0 & c_x’ & 0 \\ 0 & f_y’ & c_y’ & 0 \\ 0 & 0 & 1 & 0 \end{bmatrix} P=
        fx000fy0cxcy1000


      • The second camera
        P = [ f x ′ 0 c x ′ − f x ′ ⋅ B 0 f y ′ c y ′ 0 0 0 1 0 ] \mathbf{P} = \begin{bmatrix} f_x’ & 0 & c_x’ & -f_x’ \cdot B \\ 0 & f_y’ & c_y’ & 0 \\ 0 & 0 & 1 & 0 \end{bmatrix} P=
        fx000fy0cxcy1fxB00


    • Given a 3D point [ X Y Z ] ′ [X Y Z]’ [XYZ], the projection ( x , y ) (x, y) (x,y) of the point onto the rectified image is given by:

    [ u v w ] = P ⋅ [ X Y Z 1 ] , { x = u w y = v w \begin{bmatrix} u \\ v \\ w \end{bmatrix} = \mathbf{P} \cdot \begin{bmatrix} X \\ Y \\ Z \\ 1 \end{bmatrix} , \quad \begin{cases} x = \frac{u}{w} \\ y = \frac{v}{w} \end{cases}
    uvw
    =
    P
    XYZ1
    ,{
    x=wuy=wv

initUndistortRectifyMap

左右目 分别利用 OpenCV函数 initUndistortRectifyMap 计算 the undistortion and rectification transformation map,得到

  • 左目map: m a p 1 l , m a p 2 l map^l_1, map^l_2 map1l,map2l
  • 右目map: m a p 1 r , m a p 2 r map^r_1, map^r_2 map1r,map2r

示例代码:

cv::fisheye::initUndistortRectifyMap(K1, D1, R1, P1, img_size, CV_16SC2, rect_map_[0][0], rect_map_[0][1]); cv::fisheye::initUndistortRectifyMap(K2, D2, R2, P2, img_size, CV_16SC2, rect_map_[1][0], rect_map_[1][1]); 

Remap

左右目 分别利用 OpenCV函数 remap 并根据 左右目map 对左右目图像进行 去畸变 和 立体矫正,得到 左右目矫正图像

示例代码:

cv::remap(img_l, img_rect_l, rect_map_[0][0], rect_map_[0][1], cv::INTER_LINEAR); cv::remap(img_r, img_rect_r, rect_map_[1][0], rect_map_[1][1], cv::INTER_LINEAR); 

4. 立体匹配

根据双目矫正图像,通过 BM或SGM等立体匹配算法 对其进行立体匹配,计算 视差图

双目立体视觉三维重建

视差计算

通过 OpenCV函数 stereoBM (block matching algorithm),生成 视差图(Disparity Map) (CV_16S or CV_32F)

So if you’ve chosen disptype = CV_16S during computation, you can access a pixel at pixel-position (X,Y) by: short pixVal = disparity.at

(Y,X);
, while the disparity value is float disparity = pixVal / 16.0f;; if you’ve chosen disptype = CV_32F during computation, you can access the disparity directly: float disparity = disparity.at

(Y,X);

  • Disparity Map
  • Disparity map post-filtering

5. 三维重建

(1)算法1:根据视差图,利用 f ′ f’ f B B B 通过几何关系计算 深度值,并利用相机内参计算 三维坐标

双目立体视觉三维重建

根据上图相似三角形关系,得

Z B = Z − f B − d w ⟹ Z = B f d w \frac{Z}{B} = \frac{Z-f}{B-d_w} \quad \Longrightarrow \quad Z = \frac{Bf}{d_w} BZ=BdwZfZ=dwBf

其中, f f f d w d_w dw 分别为 成像平面的焦距和视差,单位均为 物理单位,将其转换为 像素单位,上式写为

Z = B f ′ d p Z = \frac{B f’}{d_p} Z=dpBf

其中,

d p = ( O r − u r ) + ( u l − O l ) = ( u l − u r ) + ( O r − O l ) d_p = (O_r – u_r) + (u_l – O_l) = (u_l – u_r) + (O_r – O_l) dp=(Orur)+(ulOl)=(ulur)+(OrOl)

最终,深度计算公式如下,通过遍历图像可生成 深度图

Z = depth = B ⋅ f ′ d p with d p = disp ( u , v ) + ( c x 2 ′ − c x 1 ′ ) Z = \text{depth} = \frac{B \cdot f’}{d_p} \quad \text{with} \quad d_p = \text{disp}(u,v) + ({c_x}_2′ – {c_x}_1′) Z=depth=dpBfwithdp=disp(u,v)+(cx2cx1)

根据 小孔成像模型,已知 Z Z Z相机内参 可计算出 三维点坐标,从而可生成 三维点云

{ Z = depth = f ′ ⋅ B d p X = u − c x 1 ′ f ′ ⋅ Z Y = v − c y ′ f ′ ⋅ Z 或 { bd = B d p Z = depth = f ′ ⋅ bd X = ( u − c x 1 ′ ) ⋅ bd Y = ( u − c y ′ ) ⋅ bd \begin{aligned} \begin{cases} Z = \text{depth} = \frac{f’ \cdot B}{d_p} \\ X = \frac{u-{c_x}_1′}{f’} \cdot Z \\ Y = \frac{v-{c_y}’}{f’} \cdot Z \end{cases} \end{aligned} \text{或} \begin{aligned} \begin{cases} \text{bd} = \frac{B}{d_p}\\ Z = \text{depth} = f’ \cdot \text{bd} \\ X = (u-{c_x}_1′) \cdot \text{bd} \\ Y = (u-{c_y}’) \cdot \text{bd} \end{cases} \end{aligned}

Z=depth=dpfBX=fucx1ZY=fvcyZ


bd=dpBZ=depth=fbdX=(ucx1)bdY=(ucy)bd

其中, disp ( u , v ) \text{disp}(u,v) disp(u,v) 代表 视差图 坐标值

(2)算法2:根据视差图,利用 Q Q Q 矩阵 计算 三维点坐标(reprojectImageTo3D

[ X ′ Y ′ Z ′ W ] = Q ⋅ [ u v disp ( u , v ) 1 ] \begin{bmatrix} X’ \\ Y’ \\ Z’ \\ W \end{bmatrix} = Q \cdot \begin{bmatrix} u \\ v \\ \text{disp}(u,v) \\ 1 \end{bmatrix}
XYZW
=
Q
uvdisp(u,v)1

最终,三维点坐标为

[ X Y Z ] = [ X ′ W Y ′ W Z ′ W ] \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} = \begin{bmatrix} \frac{X’}{W} \\[2ex] \frac{Y’}{W} \\[2ex] \frac{Z’}{W} \end{bmatrix}
XYZ
=

WXWYWZ

深度图 图像类型

  • 单位meter –> 32FC1
  • 单位millimeter –> 16UC1

总结

双目立体视觉三维重建
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/204729.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午7:40
下一篇 2026年3月19日 下午7:40


相关推荐

  • 类模板和模板类

    类模板和模板类类模板和模板类所谓类模板 实际上是建立一个通用类 其数据成员 成员函数的返回值类型和形参类型不具体指定 用一个虚拟的类型来代表 使用类模板定义对象时 系统会实参的类型来取代类模板中虚拟类型从而实现了不同类的功能 定义一个类模板与定义函数模板的格式类似 必须以关键字 template 开始 后面是尖括号括起来的模板参数 然后是类名 其格式如下 template

    2026年3月20日
    2
  • MyBatis-Plus 批量插入

    MyBatis-Plus 批量插入springboot mybatisplus 环境 单条插入用的是 BaseMapper 自带的 insert 方法 publicApiRes Ancanc ApiResultres newApiResult Integerinser ancMapper insert anc if

    2026年3月18日
    2
  • plsql developer 使用技巧[通俗易懂]

    plsql developer 使用技巧[通俗易懂] Oracle数据库相信已成为很多企业构建自身关键业务的重要后台支撑,也是众多开发人员常常采用的后台。但Oracle自己提供的一套客户端工具不是很好用,极大的影响了工作效率,幸好现在有了PL/SQLDeveloper这款工具。现在越来越多的开发人员成了它的忠实fans。本文就是立足于实用的基础上,总结了了改工具的常用技巧:   1.记住登陆密码   为了工作方便希望PL/SQLDe…

    2022年5月18日
    30
  • 根治Windows 2003操作系统登录及关机麻烦

    根治Windows 2003操作系统登录及关机麻烦

    2021年8月4日
    65
  • “龙虾”上桌,上市公司抢着“养”!OpenClaw引爆科技圈

    “龙虾”上桌,上市公司抢着“养”!OpenClaw引爆科技圈

    2026年3月15日
    2
  • 读《aspnetmvc-stepbystep》笔记

    读《aspnetmvc-stepbystep》笔记  读《aspnetmvc-stepbystep》笔记  这几天读了《aspnetmvc-stepbystep》,为了以后不忘记这次遇到的问题,以及此书中的一些重点观点或者主要内容,就做了一个大概的笔记。  学习软件平台:vs2008、vs2008sp1、mvc1.0rc21、传统的Web框架,如ASP/PHP/ASP.NETWebForms等等,请求的U…

    2026年4月18日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号