《Revisiting Self-Supervised Monocular Depth Estimation》论文笔记

参考代码:rmd

1. 概述

介绍:回顾前几年的一些自监督型深度估计算法,它们都是从不同的角度对自监督深度估计方法进行改进。总结这些算法中对自监督深度估计的改进idea,发现这些算法有的是为了解决场景光照变化对深度估计稳定性的影响;有的是对相机运动下场景中物体遮挡运动进行建模,从而减少对于前期假设先验的违背的影响。而这些改进的idea它们的来源是不同的文章,那么它们组合起来是否能达到比原方法更好的效果呢?或者更进一步怎么将这些idea进行有机组合才能得到最优的优化效果?这篇文章算是对这些问题的初步探究,也为产生更佳深度估计结果给出了一些具备一定指导价值的引导。

在自监督的深度估计任务中,往往输入的是单目图像序列或是双目图像序列(也可以两者的混合,如KITTI),然后通过构建相对位姿估计网络、深度估计网络得到图像之间的相对位姿变化与图像对应的深度图,之后通过在图像之前warp,使得warp之后的图像在结构相似性上最小化(SSIM Loss),也就是这类文章中经常提到的光度重构误差最小化。

然而,对自监督深度估计任务进行细致分解,可以发现这个任务并不是只需要去关注结构相似性最小化就可以了,影响整体网络性能的条件非常多。而且这个任务构建起来的依据和整体pipeline优化的目标是光度重构误差最小化,而不是直接去优化深度,深度只是优化光度重构误差过程中附带产生的结果,所以其并不是存在很强的线性关系的。基于此,这里将影响自监督深度估计性能的一些点归纳为:

  • 1)整体pipeline中编码器的选择:选择不同容量、表达能力的编码器对整体pipeline性能的影响程度;
  • 2)深度预测网络中对于深度的表达:是直接估计视差图、带scale属性的视差图还是log深度图效果好?以及这些选择对其pipeline其它部分的影响;
  • 3)场景中对于物体遮挡的处理:是通过选择最小 / 平均重构最为遮挡处损失,还是选择source图深度warp到target之后选择最小;
  • 4)场景中光照变化的处理:是通过预测图像之间的光照变换关系还是通过结构相似性最小化;
  • 5)场景中物体运动目标的处理:自监督深度估计任务中前提假设是场景中是不存在运动的物体的,那么存在运动的物体必然打破这样的规则。那么是通过MonoDepth2中的automask、不确定mask预测、还是motion filed建模进行处理?

除了上面提到的几点之外,其实整体的pipeline中还有一些额外的因素也会去影响整体自监督深度估计的性能,例如:

  • 1)相对位姿估计网络输出相对位姿是否真的准确?提升相机位姿估计网络的性能是否能带来深度估计效果的改善。在不同场景下数据序列的平移旋转量的分布是不一样的,位姿估计网络是否能对这些变化作出准确预测。而且对于相机位姿估计网络本身的结构也是可以进行细致讨论的;
  • 2)相机内参数对输出效果的影响?相机的内参数一般是通过标定的形式进行解算的,那么解算就会存在一定的误差,那么这样的误差是否会影响自监督深度估计的性能?而且,在现有的自监督深度估计中很多时候采用的是畸变很小近似针孔模型的相机,那么相机内参中的其它参数是否对最后的新能带来影响;
  • 3)自监督pipeline中深度解码器的影响,这部分是网络设计层面的事情,如何去有效抓取场景中的语义信息与场景物体细节信息,这是考验网络设计。例如,对上下采样进行优化,代表有PackNet、Pixelshuffle等;
  • 4)自监督pipeline中的优化目标,在现有的很多自监督深度估计中使用的是光度误差最小化,那么这个误差最小化并不是意味着深度效果最优化,其是存在多解的。特别是在一些低纹理或是无纹理区域,就有很大的奇异在里面。对于误差函数本身SSIM而言其度量的是一个窗口(patch)(例如,使用大小 3 ∗ 3 3*3 33的窗口)中统计量上的差异,实际RGB场景中呈现的细节很难去体现,这就导致深度生成地不够精细;

因而,整体来讲自监督深度估计要做好、做精细是目前来讲是一件较难的事情,文章提出的一些观察角度只是其中的一部分,但也可为对应的自监督pipeline改进提供引导。

2. 自监督pipeline影响因子

2.1 深度估计本身的表示

说明:下面的内容中使用 d d d代表深度(其值近小远大)。

直接估计视差:
其估计的形式也就是:
d = 1 x d=\frac{1}{x} d=x1
但是,这样的会导致一些离相机很近的物体其视差需要特别大,导致网络预测困难。

深度带scale属性:
这其实是在MonoDepth中使用的深度表示方式,给出最小很最大视差(由给定的最大最小深度值得到) σ m i n , σ m a x \sigma_{min},\sigma_{max} σmin,σmax,则将深度描述为:
d = 1 σ m i n + ( σ m a x − σ m i n ) ⋅ x d=\frac{1}{\sigma_{min}+(\sigma_{max}-\sigma_{min})\cdot x} d=σmin+(σmaxσmin)x1

Softplus直接估计深度:
它可以避免深度为0的情况,其深度表达式为:
d = l o g ( 1 + e x p ( x ) ) d=log(1+exp(x)) d=log(1+exp(x))

2.2 数据序列中光照影响

就算是在同一段视频序列中,不同帧之间的光照也会随着相机或是场景中的一些运动出现光照变化,因而不能直接做L1最小化。因而就需要将两张图像进行映射去除光照影响或是采用光照无关的损失度量。

光照映射:
这里是假设光照的变化符合线性变化关系,通过去预测两个变量 a , b a,b a,b实现光照的对齐:
I ′ = a ⋅ I + b I^{'}=a\cdot I+b I=aI+b
SSIM损失:
该损失函数是在一个窗口(patch)内进行统计意义上的近似,其表达为:
S S I M ( x , y ) = ( 2

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VLAD(Vector of Locally Aggregated Descriptors)是一种图像表示方法,常用于图像检索和计算机视觉任务中。它通过聚合局部特征描述符来生成图像的紧凑表示。 以下是一个简单的C++实现示例,展示了如何实现VLAD图像表示: ```cpp #include <iostream> #include <vector> #include <opencv2/opencv.hpp> // 聚类算法(这里使用K-means) cv::Mat kmeansClustering(const std::vector<cv::Mat>& descriptors, int numClusters) { cv::Mat allDescriptors; for (const cv::Mat& descriptor : descriptors) { allDescriptors.push_back(descriptor); } cv::Mat labels, centers; cv::TermCriteria criteria(cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER, 100, 0.01); cv::kmeans(allDescriptors, numClusters, labels, criteria, 1, cv::KMEANS_PP_CENTERS, centers); return centers; } // 计算VLAD图像表示 cv::Mat computeVLAD(const std::vector<cv::Mat>& descriptors, const cv::Mat& visualWords) { int descriptorSize = descriptors[0].cols; cv::Mat vlad(visualWords.rows, descriptorSize, CV_32F, cv::Scalar(0)); for (const cv::Mat& descriptor : descriptors) { // 找到每个描述符最近的视觉词 cv::Mat difference = visualWords - descriptor; cv::Mat distances; cv::reduce(difference.mul(difference), distances, 1, cv::REDUCE_SUM); cv::Point minLoc; cv::minMaxLoc(distances, nullptr, nullptr, &minLoc); // 计算每个视觉词的残差 cv::Mat residual = descriptor - visualWords.row(minLoc.y); // 更新VLAD表示 for (int i = 0; i < descriptorSize; i++) { vlad.at<float>(minLoc.y, i) += residual.at<float>(0, i); } } // 归一化VLAD表示 cv::normalize(vlad, vlad, 1.0, 0.0, cv::NORM_L2); return vlad; } int main() { // 假设有一组局部特征描述符(使用OpenCV的Mat表示) std::vector<cv::Mat> descriptors = { (cv::Mat_<float>(1, 128) << /* descriptor values */ ), (cv::Mat_<float>(1, 128) << /* descriptor values */ ), (cv::Mat_<float>(1, 128) << /* descriptor values */ ), // ... }; // 聚类算法,得到视觉词汇 int numClusters = 100; cv::Mat visualWords = kmeansClustering(descriptors, numClusters); // 计算VLAD图像表示 cv::Mat vlad = computeVLAD(descriptors, visualWords); // 输出VLAD表示结果 std::cout << "VLAD Representation:\n" << vlad << std::endl; return 0; } ``` 在这个示例中,`descriptors`是一组局部特征描述符,每个描述符用一个`cv::Mat`对象表示。首先,使用K-means聚类算法将所有描述符聚类成`numClusters`个视觉词汇,并得到`visualWords`矩阵。然后,根据每个描述符找到最近的视觉词,并计算每个视觉词的残差。将残差累加到VLAD表示中,并进行归一化处理。最后,输出VLAD图像表示结果。 请注意,这只是一个简单的VLAD图像表示的C++实现示例,供你参考。在实际应用中,你可能需要根据具体需求进行修改和扩展,例如使用更复杂的特征提取方法、改进聚类算法等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值