论文信息
论文链接:[1806.01260] Digging Into Self-Supervised Monocular Depth Estimation (arxiv.org)
官方代码:[nianticlabs/monodepth2: ICCV 2019] Monocular depth estimation from a single image (github.com)
主要工作概述
在深度估计领域,面临着逐像素的深度真值获取成本很高的问题。主要原因是激光雷达太贵及激光雷达采集的数据点过于稀疏。自监督学习能够很好地克服这一局限性。本篇论文主要有以下三点贡献:
- 提出了一个全新的外观匹配损失(Appearance Matching Loss),用于解决单目监督时像素遮挡的问题。
- 提出了一种简单的auto-masking方法,用于忽略那些相对于相机静止的像素点。
- 提出多尺度外观匹配损失,将中间层预测的深度图上采样到输入的分辨率大小,然后再计算损失,可以有效减少纹理复制伪影现象。
pipeline
上图是Monodepth2的主要组成部分,其中:
- Depth network是Unet结构,输入一帧图像$I_{t}$,网络输出预测的深度图$D_{t}$。
- Pose network用于学习位姿变化,输入两张图像$I_{t}、I_{t^{‘}}$,可以输出一个源图像$I_{t^{‘}}$相对于目标图像$I_{t}$的位姿变换映射$T_{t \rightarrow t^{\prime}}$。
上图便是整个网络的pipeline,在使用单目数据训练时,需要输入相邻的三帧图像,将它们表示为t-1、t、t+1,其中算法要预测的即是第t帧(目标帧)的深度图,t+1及t-1是t帧的后一帧及前一帧。
网络的工作流程如下:
首先将第t+1、t、t-1帧输入到Depth Network中,得到预测的深度$D_{t+1}、D_{t}、D_{t+1}$。
再将分别将(t-1,t),(t+1,t)两组图片输入到Pose Network中,得到t+1->t的姿态变换$T_{t+1 \rightarrow t}$,t-1->t的姿态变换 $T_{t-1 \rightarrow t}$。
利用相机内参$K$深度图$D_{t+1}、D_{t+1}$将$I_{t+1}、I_{t-1}$转换成3D点云形式。
利用2中学到的姿态变换$T_{t+1 \rightarrow t}$、 $T_{t-1 \rightarrow t}$将目标帧的点云转换到目标帧t的空间坐标系下。
利用相机的内参$K$将转换后的3D点云转换成2D图像,此即为利用$I_{t+1}、I_{t-1}$重建出来的图像$I_{t+1 \rightarrow t}$、$I_{t-1 \rightarrow t}$。
此时相当于利用相邻两帧重建了两张目标帧的图像,将每一张重建图像和目标帧$I_{t}$计算外观匹配损失然后都加起来,即为最终的外观匹配损失,如下:
$$
L_{p}=pe(I_{t},I_{t+1 \rightarrow t})+pe(I_{t},I_{t-1 \rightarrow t})
$$然后利用$D_{t}$计算控制深度图平滑的损失函数$L_{s}$。
联合$L_{s}$以及改进后的$L_{p}$(怎么改的下文说),对网络进行训练。
注:pe损失函数表示的是重投影损失函数,它的计算公式如下:
$$
pe(I_{a},I_{b})=\frac{\alpha }{2} (1-SSIM(I_{a},I_{b}))+(1-\alpha )\left | I_{a}-I_{b} \right | _{1}
$$
图中蓝色的shared encoder部分,表明两个网络可以使用相同的encoder来进行特征提取,之后再分别送入Depth Decoder及Pose Decoder中,以节省参数。
当网络训练好进行测试时,只输入单张图像,利用Depth Network即可获得对应的深度图
三点改进
Per-Pixel Minimum Reprojection Loss
论文版本:当从多个源图像计算重投影误差时,现有的自我监督深度估计方法会将重投影误差平均到每个可用的源图像中。这可能会导致目标图像中可见,但源图像中不可见的像素出现问题。 如果网络预测了此类像素的正确深度,则被遮挡的源图像中的相应颜色将很可能与目标不匹配,从而导致较高的光度误差。 这种有问题的像素主要来自两类:由于图像边界处的自我运动而产生的视野外像素和被遮挡的像素。 对于视点外像素的影响,可以通过在重投影损失中掩盖这些像素来减少,但这不能解决遮挡像素的问题。
人话版本:像上图中$I_{t-1}$不是有部分像素出现了遮挡现象嘛,那用它来重建的那个图像$I_{t-1 \rightarrow t}$会保留这个遮挡现象,那这个pe损失计算公式如下:
$$
L_{p}^{t-1}=pe(I_{t},I_{t-1 \rightarrow t})
$$
而$I_{t+1}$匹配的很好,没有遮挡现象,它的pe损失计算公式如下:
$$
L_{p}^{t+1}=pe(I_{t},I_{t+1 \rightarrow t})
$$
很显然,$L_{p}^{t-1}$要比$L_{p}^{t+1}$大很多,之前的方法(Baseline)求最后的外观匹配损失$L_{p}$时,直接如下计算:
$$
L_{p}=\frac{1}{2}(L_{p}^{t-1}+L_{p}^{t+1})
$$
而这篇文章直接使用$L_{p}^{t-1}$和$L_{p}^{t+1}$中的最小值作为最后的外观匹配损失,即:
$$
L_{p}=min(L_{p}^{t-1},L_{p}^{t+1})
$$
肯定取最小值会比取平均值来的误差更小!!!这个取最小的操作,是在每一个像素上进行取最小,就比如你有两张重建出来的图像,还有一个目标帧的原图像,那就是在两张重建图像上每个像素与源图像计算损失,然后选择较小的那个损失。
Auto-Masking Stationary Pixels
自监督的单目训练通常是在摄像机移动和场景不动的假设下进行的。 当这些假设失效时,例如当相机静止不动或场景中有物体运动时,性能可能会受到很大影响。 对于在训练过程中通常被观察到运动的物体,这个问题导致在测试时出现无限深度的“空洞”。 本文提出使用auto-masking来解决这个问题,该方法可以过滤出不会在外观上从一帧到下一帧变化的像素。 这样的效果是,让网络忽略跟照相机以相同速度运动的对象,甚至在照相机不动时也可以忽略单目视频中的整个帧。
具体的做法就是在计算pe损失$L_{p}$的时候,对每一个像素都施加一个二值化的mask,即用$\mu \in{0,1}$对每一个像素进行加权,序列中相邻帧里在运动的像素我就给你加权1,静止的像素我就给你加权0,防止静止的像素被计算到损失之中。那么怎么确定每个像素是在运动还是静止呢?
作者认为,在以下几种条件会出现序列中相邻帧之间保持不变的像素,即为“静止的像素”:
- 相机是静止的
- 物体和相机都在动,但是相对速度为0
- 低纹理区域(不太明白)???
具体的取值呢,是用的如下公式:

解释一下,就是如果目标帧和重建帧上某一像素的pe损失小于目标帧和相邻帧(源帧)对应位置像素的损失,就令$\mu=1$,反之令$\mu=0$。
我个人的理解就是,重建帧中的像素如果与目标帧对应像素更接近(即pe损失值小),同时目标帧中的像素与相邻帧(源帧)对应像素如果差距比较大(即pe损失值大),那这种像素是在运动的,因为源帧到目标帧经过了时间,像素产生了较大的变化。反之,如果目标帧中的像素与相邻帧(源帧)对应像素差距比较小(即pe损失值小),那就说明经过一段时间(指两帧之间的间隔时间),该像素变化不大,说明这个像素基本上静止了。同时注意到,重建帧和目标帧之间的pe误差肯定是越来越小的,因为优化的目标就是重建图像和目标图像尽可能接近。
Multi-scale Estimation
首先由于双线性采样器的梯度局部性,为了防止训练陷入局部最优,现有的很多模型使用多尺度的深度来进行深度估计和图像重建。它们计算pe损失呢,也是在各自的尺度下面进行的,然后把各个尺度的pe损失加起来作为最后的误差。那作者做实验就发现这个效果不好啊,那他就改进了一下这个方法。如下图:
作者在计算pe损失之前,做了一个上采样的操作,把所有小尺度的深度图都上采样到和输入图像一样大小,然后再计算pe损失。
我个人感觉这个地方上采样也是有道理的,不然对于小尺度的图像,到时候做这个mask也不好做,因为$\mu$取值是靠输入图像和重建图像、相邻帧图像计算误差来定值的,这个小尺度的重建图像和输入图像大小也不一样,那我怎么算对应像素的pe误差啊?倒是可以将输入图像下采样,但这个又会引来其他误差了,所以作者这里这个上采样操作我感觉十分巧妙。
总的损失函数
$$
L=\mu L_{p}+\lambda L_{s}
$$
其中$\mu L_{p}$就是加了auto-mask的pe损失函数,$\lambda L_{s}$是一个控制深度图平滑的损失,在Monodepth中有用到过,具体就不讲了。
实验复现
。。。。