本篇是比较简单的基础概念,刚入门的朋友可能是需要的。

立体匹配入门指南(8):视差图、深度图、点云
视差图

立体匹配入门指南(8):视差图、深度图、点云
三维点云

首先,我们要介绍下这三个概念。

立体匹配入门指南(8):视差图、深度图、点云

视差(disparity)

视差
d
d
d
等于同名点对在左视图的列坐标减去在右视图上的列坐标,是像素单位

d
=
x
l

x
r
d=x_l-x_r
d=xlxr
立体视觉里,视差概念在极线校正后的像对里使用。

深度(depth)

深度D等于像素在该视图相机坐标系下
Z
Z
Z
坐标,是空间单位。深度并不特在校正后的图像对里使用,而是任意图像都可获取深度图。

视差图(disparity map)

视差图指存储立体校正后单视图所有像素视差值的二维图像。

  1. 视差图是一张二维图像,和原图等大小
  2. 视差图每个位置保存的以像素为单位的该位置像素的视差值
  3. 以左视图视差图为例,在像素位置p的视差值等于该像素在右图上的匹配点的列坐标减去其在左图上的列坐标

深度图(depth map)

深度图指存储单视图所有像素的深度值的二维图像,是空间单位,比如毫米。

  1. 深度图是一张二维图像,和原图等大小,也就和视差图等大小
  2. 深度图每个位置保存的是该位置像素的深度值
  3. 深度值就是相机坐标系下的Z坐标值

点云(point cloud)

点云指三维空间的三维点集合,坐标属性(
X
,
Y
,
Z
X,Y,Z
X,Y,Z
),法线属性(
N
x
,
N
y
,
N
z
N_x,N_y,N_z
Nx,Ny,Nz
)(可选),颜色属性(
R
,
G
,
B
R,G,B
R,G,B
)(可选)

其次,为什么会有视差图和深度图呢?

我们知道,立体匹配一般是指逐像素的稠密匹配,这意味着每个像素都会得到一个视差值(包括无效值),如何存储这些视差值呢,显然以二维图的方式存储是很合适的,最大的两点优势是一方面可以通过像素坐标快速的在二维图中找到对应位置的视差值,而且和图像一样是有序的,邻域检索、视差滤波等将会变得非常方便;另一方面是可以直观的通过观察视差图和原图的对比,对视差图的质量有初步的判定。

而深度图的意义则是以更少的存储空间、有序的表达图像匹配的三维成果。更少的存储空间是因为只保存了一个深度值,而不是三维点云的三个坐标值,而深度值是可以结合像素坐标计算三维点坐标值的。有序是因为深度图和原图像素是一一对应的,所以原图的邻域信息完全继承到了深度图里。

这就是视差图和深度图的意义,视差图是立体匹配算法的产出,而深度图则是立体匹配到点云生成的中间桥梁。

视差图和深度图中间,有着一对一的转换公式:

D
=
B
f
d
+
(
x
r

x
l
)
D=\frac {Bf}{d+(x_{0r}-x_{0l})}
D=d+(x0rx0l)Bf

其中,
D
D
D
为深度,
d
d
d
为视差,
B
B
B
为基线长度,
f
f
f
为焦距(像素单位),
x
l
x_{0l}
x0l

x
r
x_{0r}
x0r
分别为左右视图主点的列坐标。,另一个较为熟知的公式是

D
=
B
f
d
D=\frac {Bf}{d}
D=dBf

这是在左右视图主点的列坐标相同的特殊情况,比如主点都在中心。

深度图计算相机坐标系下的点云,也有着简单的公式:

Z
=
D
X
=
D
(
x

x
l
)
f
Y
=
D
(
y

y
l
)
f
\begin{aligned} Z &= D\\ X &= \frac {D(x-x_{0l})}{f}\\ Y &= \frac {D(y-y_{0l})}{f} \end{aligned}
ZXY=D=fD(xx0l)=fD(yy0l)

其中,
x
,
y
x,y
x,y
为像素的列坐标和行坐标,
x
l
x_{0l}
x0l

y
l
y_{0l}
y0l
为主点的像素坐标。

常见问答:
问:为什么我从.png格式的视差图里读取到的视差值和真实值有很大差异?
答: 我们要先搞清楚,视差图是如何存储的。通常而言,我们是把二维视差图以图像格式存储,常见的格式有png、tif、pfm等,但这些图像格式存储的数据类型是有区别的,其中png只能存储整数,而tif和pfm则可以存储小数。而显然准确的视差值必然是浮点型的小数,所以存储为tif和pfm可以原值无损存储,而存储为png必然会损失精度,所以有的代码比如opencv会把得到的浮点型视差值乘以16倍取整,存储到png里,这样存储视差值的精度变为1/16,对于这种情况我们在读取png后要先除以16才是真实视差值,且视差会有阶梯分层现象。

那有同学就问,既然这样为什么要存储png呢?是因为目前主流的图像软件,不支持直接看浮点格式的tif和pfm,存储为png可以更好的观看视差图,当然要是实际生产使用,是必然不建议存储为png的,用来查看视差结果是可以的。

还有人会直接把视差值拉伸或者压缩到0~255,存储到png或bmp等存储整数的格式中,这样的视差图只能用来观看视差效果,没有其他作用,比如我的代码里的存储方式。

问:极线像对下的深度图和原图的深度图是一样的吗?如何转换?
答: 不一样,因为深度图是在视图所在的相机坐标系下的,所以和相机坐标系强挂钩,极限校正后的左视图和原始的左视图是不一样的相机坐标系,所以它们的深度图是不一样的。

  1. 对于极线像对左视图某像素
    p
    p
    p
    ,通过单应变换
    H
    H
    H
    转换到原左视图上,得到原图上的像素坐标
    q
    q
    q

  2. p
    p
    p
    的相机坐标系坐标通过一个旋转
    R
    R
    R
    变换到原左视图的相机坐标系坐标,得到
    q
    q
    q
    的深度。

  3. H
    H
    H

    R
    R
    R
    在极线校正步骤可以获取(极线校正的必然产出)。