如何评价李飞飞团队管理论文的论文 Dense-Captioning Events in Videos

Dense-Captioning Events in Videos
Dense-Captioning Events in VideosArticle in
· May 2017 with 78 Reads4.13- Stanford University13.72- Universidad del Norte (Colombia)Most natural videos contain numerous events. For example, in a video of a &man playing a piano&, the video might also contain &another man dancing& or &a crowd clapping&. We introduce the task of dense-captioning events, which involves both detecting and describing events in a video. We propose a new model that is able to identify all events in a single pass of the video while simultaneously describing the detected events with natural language. Our model introduces a variant of an existing proposal module that is designed to capture both short as well as long events that span minutes. To capture the dependencies between the events in a video, our model introduces a new captioning module that uses contextual information from past and future events to jointly describe all events. We also introduce ActivityNet Captions, a large-scale benchmark for dense-captioning events. ActivityNet Captions contains 20k videos amounting to 849 video hours with 100k total descriptions, each with it's unique start and end time. Finally, we report performances of our model for dense-captioning events, video retrieval and localization.Egocentric vision consists in acquiring images along the day from a first person point-of-view using wearable cameras. The automatic analysis of this information allows to discover daily patterns for improving the quality of life of the user. A natural topic that arises in egocentric vision is storytelling, that is, how to understand and tell the story relying behind the pictures. In this paper, we tackle storytelling as an egocentric sequences description problem. We propose a novel methodology that exploits information from temporally neighboring events, matching precisely the nature of egocentric sequences. Furthermore, we present a new method for multimodal data fusion consisting on a multi-input attention recurrent network. We also publish the first dataset for egocentric image sequences description, consisting of 1,339 events with 3,991 descriptions, from 55 days acquired by 11 people. Furthermore , we prove that our proposal outperforms classical attentional encoder-decoder methods for video description.Article · April 2017During realistic, continuous perception, humans automatically segment experiences into discrete events. Using a novel model of cortical event dynamics, we investigate how cortical structures generate event representations during narrative perception and how these events are stored to and retrieved from memory. Our data-driven approach allows us to detect event boundaries as shifts between stable patterns of brain activity without relying on stimulus annotations and reveals a nested hierarchy from short events in sensory regions to long events in high-order areas (including angular gyrus and posterior medial cortex), which represent abstract, multimodal situation models. High-order event boundaries are coupled to increases in hippocampal activity, which predict pattern reinstatement during later free recall. These areas also show evidence of anticipatory reinstatement as subjects listen to a familiar narrative. Based on these results, we propose that brain activity is naturally structured into nested events, which form the basis of long-term memory representations.Article · August 2017Conference Paper · June 2016Conference Paper · June 2016Conference Paper · June 2016Conference Paper · June 2016Dense captioning is a newly emerging computer vision topic for understanding images with dense language descriptions. The goal is to densely detect visual concepts (e.g., objects, object parts, and interactions between them) from images, labeling each with a short descriptive phrase. We identify two key challenges of dense captioning that need to be properly addressed when tackling the problem. First, dense visual concept annotations in each image are associated with highly overlapping target regions, making accurate localization of each visual concept challenging. Second, the large amount of visual concepts makes it hard to recognize each of them by appearance alone. We propose a new model pipeline based on two novel ideas, joint inference and context fusion, to alleviate these two challenges. We design our model architecture in a methodical manner and thoroughly evaluate the variations in architecture. Our final model, compact and efficient, achieves state-of-the-art accuracy on Visual Genome for dense captioning with a relative gain of 73\% compared to the previous best algorithm. Qualitative experiments also reveal the semantic capabilities of our model in dense captioning.Article · November 2016Recent progress on image captioning has made it possible to generate novel sentences describing images in natural language, but compressing an image into a single sentence can describe visual content in only coarse detail. While one new captioning approach, dense captioning, can potentially describe images in finer levels of detail by captioning many regions within an image, it in turn is unable to produce a coherent story for an image. In this paper we overcome these limitations by generating entire paragraphs for describing images, which can tell detailed, unified stories. We develop a model that decomposes both images and paragraphs into their constituent parts, detecting semantic regions in images and using a hierarchical recurrent neural network to reason about language. Linguistic analysis confirms the complexity of the paragraph generation task, and thorough experiments on a new dataset of image and paragraph pairs demonstrate the effectiveness of our approach.Article · November 2016Conference Paper · June 2015Conference Paper · June 2015Conference Paper · June 2015Conference Paper · June 2015Conference Paper · June 2015Conference Paper · June 2016Conference Paper · June 2016Despite progress in perceptual tasks such as image classification, computers still perform poorly on cognitive tasks such as image description and question answering. Cognition is core to tasks that involve not just recognizing, but reasoning about our visual world. However, models used to tackle the rich content in images for cognitive tasks are still being trained using the same datasets designed for perceptual tasks. To achieve success at cognitive tasks, models need to understand the interactions and relationships between objects in an image. When asked &What vehicle is the person riding?&, computers will need to identify the objects in an image as well as the relationships riding(man, carriage) and pulling(horse, carriage) in order to answer correctly that &the person is riding a horse-drawn carriage&. In this paper, we present the Visual Genome dataset to enable the modeling of such relationships. We collect dense annotations of objects, attributes, and relationships within each image to learn these models. Specifically, our dataset contains over 100K images where each image has an average of 21 objects, 18 attributes, and 18 pairwise relationships between objects. We canonicalize the objects, attributes, relationships, and noun phrases in region descriptions and questions answer pairs to WordNet synsets. Together, these annotations represent the densest and largest dataset of image descriptions, objects, attributes, relationships, and question answers.Article · February 2016Article · September 2016Chapter · October 2016Chapter · October 2016Conference Paper · October 2016papers on tracking and activity classification/detection/understanding6 Followers&img src=&/50/v2-a0dd6ef36e543f6b81eec_b.jpg& data-rawwidth=&1540& data-rawheight=&1128& class=&origin_image zh-lightbox-thumb& width=&1540& data-original=&/50/v2-a0dd6ef36e543f6b81eec_r.jpg&&&blockquote&朋友,过去的时代对于我们&br&好比打着七重封印的密籍&br&你称为时代精神的那东西&br&它终归不过是过去的时代&br&反映在学究先生的精神里。&br&——《浮士德》&br&&br&他掘了坑,又挖深了,竟掉在自己所挖的阱裡。&br&——《圣经 诗篇 7.15》&/blockquote&&p&DSO(Direct Sparse Odometry),是慕尼黑工业大学(Technical University of Munich, TUM)计算机视觉实验室的雅各布.恩格尔(Jakob Engel)博士,于2016年发布的一个视觉里程计方法(期刊论文见[1],实验室主页见&a href=&/?target=https%3A//vision.in.tum.de/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Computer Vision Group&i class=&icon-external&&&/i&&/a&)。在SLAM领域,DSO属于稀疏直接法,据论文称能达到传统特征点法的五倍速度(需要降低图像分辨率),并保持同等或更高精度,代码见:&a href=&/?target=https%3A///JakobEngel/dso& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JakobEngel/dso&i class=&icon-external&&&/i&&/a&。然而,由于某些历史和个人的原因,DSO的代码清晰度和可读性,明显弱于其他SLAM方案如ORB、SVO、okvis等,使得研究人员很难以它为基础,展开后续的研究工作。因此,本文希望从理论和实现层面解读DSO,尝试为其他对DSO感兴趣的研究人员提供一些有益的思路和观点。&/p&&p&注:&/p&&ul&&li&为了读懂本文,我们假定读者已具有视觉SLAM的基本知识,否则,请先阅读相关材料。另外,如果读过DSO论文或代码,可能对本文有更好的理解。&/li&&li&由于知乎平台分辨率限制,插图可能不够清晰。如果能图像质量有更高要求,请联系作者:gao.xiang.thu at gmail dot com. &/li&&li&由于本文较长,我会花几次时间进行更新,应读者要求先发布草稿版。&/li&&/ul&&p&以下是本文的提纲:&/p&&p&提纲&/p&&ol&&li&概述&/li&&li&流程框架&/li&&li&滑动窗口&/li&&li&光度标定&/li&&li&评述&/li&&li&资料与参考文献&/li&&/ol&&img src=&/v2-a7b7cfb953ec3b6dceeea1_b.png& data-rawwidth=&692& data-rawheight=&688& class=&origin_image zh-lightbox-thumb& width=&692& data-original=&/v2-a7b7cfb953ec3b6dceeea1_r.png&&&p&&br&&/p&&hr&&ol&&li&概述&/li&&/ol&&p&DSO属于稀疏直接法的视觉里程计。它不是完整的SLAM,因为它不包含回环检测、地图复用的功能。因此,它不可避免地会出现累计误差,尽管很小,但不能消除。DSO目前开源了单目实现,双目DSO的论文已被ICCV接收,但目前未知是否开源。&/p&&p&DSO是少数使用纯直接法(Fully direct)计算视觉里程计的系统之一。相比之下,SVO[2]属于半直接法,仅在前端的Sparse model-based Image Alignment部分使用了直接法,之后的位姿估计、bundle adjustment,则仍旧使用传统的最小化重投影误差的方式。而ORB-SLAM2[3],则属于纯特征法,计算结果完全依赖特征匹配。从方法上来说,DSO是新颖、独树一帜的。&/p&&p&直接法相比于特征点法,有两个非常不同的地方:&/p&&ul&&li&特征点法通过最小化重投影误差来计算相机位姿与地图点的位置,而直接法则最小化光度误差(photometric error)。所谓光度误差是说,最小化的目标函数,通常由图像之间的误差来决定,而非重投影之后的几何误差。&/li&&li&直接法将数据关联(data association)与位姿估计(pose estimation)放在了一个统一的非线性优化问题中,而特征点法则分步求解,即,先通过匹配特征点求出数据之间关联,再根据关联来估计位姿。这两步通常是独立的,在第二步中,可以通过重投影误差来判断数据关联中的外点,也可以用于修正匹配结果(例如[4]中提到的类EM的方法)。&/li&&/ul&&img src=&/v2-56f7f5b0f617ee226eaf2c_b.png& data-rawwidth=&1281& data-rawheight=&687& class=&origin_image zh-lightbox-thumb& width=&1281& data-original=&/v2-56f7f5b0f617ee226eaf2c_r.png&&&p&由于这个原因,DSO会一直求解一个比较复杂的优化问题,我们很难将它划分为像特征点法那样一步一步的过程。DSO甚至没有“匹配点”这个概念。每一个三维点,从某个主导帧(host frame)出发,乘上深度值之后投影至另一个目标帧(target frame),从而建立一个投影残差(residual)。只要残差在合理范围内,就可以认为这些点是由同一个点投影的。从数据关联角度看,在这个过程中并没有a1-b1, a2-b2这样的关系,也可能存在a1-b1, a2-b1, a3-b1这样的情况。但是DSO并不在意这些,只要残差不大,我们就看成是同一个点。这是很重要的一点。在特征点法中,我们可以找到一个地图点分别在哪些帧中被看到,乃至找到各帧中的图像描述子是什么;但在DSO中,我们会尝试把每个点投影到所有帧中,计算它在各帧中的残差,而并不在意点和点之间的一一对应关系。&/p&&p&从后端来看,DSO使用一个由若干个关键帧组成的滑动窗口作为它的后端。这个窗口在整个VO过程中一直存在,并有一套方法来管理新数据的加入以及老数据的去除。具体来说,这个窗口通常保持5到7个关键帧。前端追踪部分,会通过一定的条件,来判断新来的帧是否可作为新的关键帧插入后端。同时,如果后端发现关键帧数已经大于窗口大小,也会通过特定的方法,选择其中一个帧进行去除。请注意被去除的帧并不一定是时间线上最旧的那个帧,而是会有一些复杂条件的。&/p&&p&后端除了维护这个窗口中的关键帧与地图点外,还会维护与优化相关的结构。特别地,这里指Gauss-Newton或Levenburg-Marquardt方法中的Hessian矩阵和b向量(仅先验部分)。当我们增加新的关键帧时,就必须扩展H和b的维度;反之,如果需要去掉某个关键帧(以及它携带的地图点)时,也需要降低H和b的维度。这个过程还需要将被删掉帧和点的信息,转移到窗口内剩余帧当中,这一步被称为边缘化(Marginalization)。&/p&&p&由于直接法需要比较图像信息,其结果容易受光照干扰。于是,DSO提出了光度标定,认为对相机的曝光时间、暗角、伽马响应等参数进行标定后,能够让直接法更加鲁棒。对于未进行光度标定的相机,DSO也会在优化中动态估计光度参数(具体来说,是一个仿射变化的参数,记作a和b)。这个过程建模了相机的成像过程,因此对于由相机曝光不同引起的图像明暗变化,会有更好的表现。但是,如果由于环境光源发生变化,光度标定也是无能为力的。&/p&&p&本文第2节介绍DSO基本框架和流程。第3节介绍滑动窗口内的最小二乘问题、雅可比、边缘化。第4节介绍光度标定。第5节会给出我个人对DSO的一些评述。最后列出参考文献。DSO相关的实验、比较结果,请参见作者原始论文,在此不作叙述。&/p&&hr&&p&2. 框架流程&/p&&p&2.1 代码框架与数据表示&/p&&p&现在我们来看DSO的大体框架。我去除了一些不重要的类和结构,方便读者阅读。&/p&&img src=&/v2-6a9dcd379ce3c772e8e14aeae09b6e0a_b.png& data-rawwidth=&7084& data-rawheight=&3853& class=&origin_image zh-lightbox-thumb& width=&7084& data-original=&/v2-6a9dcd379ce3c772e8e14aeae09b6e0a_r.png&&&p&DSO整体代码由四个部分组成:系统与各算法集成于src/FullSystem,后端优化位于src/OptimizationBackend,这二者组成了DSO大部分核心内容。src/utils和src/IOWrapper为一些去畸变、数据集读写和可视化UI代码。先来看核心部分的FullSystem和OptimizationBackend。&/p&&p&如上图上半部分所示,在FullSystem里,DSO致力于维护一个滑动窗口内部的关键帧序列。每个帧的数据存储于FrameHessian结构体中,FrameHessian即是一个带着状态变量与Hessian信息的帧。然后,每个帧亦携带一些地图点的信息,包括:&/p&&ul&&li&pointHessians是所有活跃点的信息。所谓活跃点,是指它们在相机的视野中,其残差项仍在参与优化部分的计算;&/li&&li&pointHessiansMarginalized是已经边缘化的地图点。&/li&&li&pointHessiansOut是被判为外点(outlier)的地图点。&/li&&li&以及immaturePoints为未成熟地图点的信息。&/li&&/ul&&p&在单目SLAM中,所有地图点在一开始被观测到时,都只有一个2D的像素坐标,其深度是未知的。这种点在DSO中称为未成熟的地图点:Immature Points。随着相机的运动,DSO会在每张图像上追踪这些未成熟的地图点,这个过程称为trace——实际上是一个沿着极线搜索的过程,十分类似于svo的depth filter。Trace的过程会确定每个Immature Point的逆深度和它的变化范围。如果Immature Point的深度(实际中为深度的倒数,即逆深度)在这个过程中收敛,那么我们就可以确定这个未成熟地图点的三维坐标,形成了一个正常的地图点。具有三维坐标的地图点,在DSO中称为PointHessian。与FrameHessian相对,PointHessian亦记录了这个点的三维坐标,以及Hessian信息。&/p&&p&与很多其他SLAM方案不同,DSO使用单个参数描述一个地图点,即它的逆深度。而ORB-SLAM等多数方案,则会记录地图点的x,y,z三个坐标。逆深度参数化形式具有形式简单、类似高斯分布、对远处场景更为鲁棒等优点[5],但基于逆深度参数化的Bundle adjustment,每个残差项需要比通常的BA多计算一个雅可比矩阵。为了使用逆深度,每个PointHessian必须拥有一个主导帧(host frame),说明这个点是由该帧反投影得到的。&/p&&p&于是,滑动窗口的所有信息,可以由若干个FrameHessian,加上每个帧带有的PointHessian来描述。所有的PointHessian又可以在除主导帧外的任意一帧中进行投影,形成一个残差项,记录于PointHessian::residuals中。所有的残差加起来,就构成了DSO需要求解的优化问题。当然,由于运动、遮挡的原因,并非每个点都可以成功地投影到其余任意一帧中去,于是我们还需要设置每个点的状态:有效的/被边缘化的/无效的。不同状态的点,被存储于它主导帧的pointHessians/pointHessianMarginalized/PointHessiansOut三个容器内。&/p&&p&除此之外,DSO将相机的内参、曝光参数等信息,亦作为优化变量考虑在内。相机内参由针孔相机参数fx, fy, cx, cy表达,曝光参数则由两个参数a,b描述。这部分内容在光度标定一节内。&/p&&p&后端优化部分单独具有独立的Frame, Point, Residual结构。由于DSO的优化目标是最小化能量(energy,和误差类似),所以有关后端的类均以EF开头,且与FullSystem中存储的实例一一对应,互相持有对方的指针。优化部分由EnergyFunctional类统一管理。它从FullSystem中获取所有帧和点的数据,进行优化后,再将优化结果返回。它也包含整个滑动窗口内的所有帧和点信息,负责处理实际的非线性优化矩阵运算。&/p&&p&2.2
VO流程&/p&&p&每当新的图像到来时,DSO将处理此图像的信息,流程如下:&/p&&img src=&/v2-a57b49f24c9af4df5ddbfc4_b.png& data-rawwidth=&2430& data-rawheight=&2753& class=&origin_image zh-lightbox-thumb& width=&2430& data-original=&/v2-a57b49f24c9af4df5ddbfc4_r.png&&&p&尽管没有解释每一步的具体用意,但可以看出DSO的大致流程。从上图可以简单总结出DSO的行为:&/p&&ul&&li&对于非关键帧,DSO仅计算它的位姿,并用该帧图像更新每个未成熟点的深度估计;&/li&&li&后端仅处理关键帧部分的优化。除去一些内存维护操作,对每个关键帧主要做的处理有:增加新的残差项、去除错误的残差项、提取新未成熟点。&/li&&li&整个流程在一个线程内,但内部可能有多线程的操作。&/li&&/ul&&hr&&p&3.
DSO详细介绍&/p&&p&3.1 残差的构成与雅可比&/p&&p&在VO过程中,DSO会维护一个滑动窗口,通常由5-7个关键帧组成,流程如前所述。DSO试图将每个先前关键帧中的地图点投影到新关键帧中,形成残差项。同时,会在新关键帧中提取未成熟点,并希望它们演变成正常地图点。在实际当中,由于运动、遮挡的原因,部分残差项会被当作outlier,最终剔除;也有部分未成熟地图点无法演化成正常地图点,最终被剔除。&/p&&p&滑动窗口内部构成了一个非线性最小二乘问题。表示成因子图(或图优化)的形式,如下所示:&/p&&img src=&/v2-a5f3c513c7961bfd90ab9_b.png& data-rawwidth=&1328& data-rawheight=&686& class=&origin_image zh-lightbox-thumb& width=&1328& data-original=&/v2-a5f3c513c7961bfd90ab9_r.png&&&p&每一个关键帧的状态为八维:六自由度的运动位姿加上两个描述光度的参数;每个地图点的状态变量为一维,即该点在主导帧(Host)里的逆深度。于是,每个残差项(或能量项E),将关联两个关键帧与一个逆深度。事实上,还有一个全局的相机内参数亦参与了优化,但未在此图中表示。&/p&&p&现在我们来考虑如何计算残差。这部分推导和LSD-SLAM的会议论文[6],以及我的书[7]是类似的。如果读者觉得有困难,可以参照它们。&/p&&p&设相机模型由针孔模型描述,那么内参矩阵为:&/p&&p&&img src=&/equation?tex=%5C%5BK+%3D+%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B%7Bf_x%7D%7D%26%7B%7D%26%7B%7Bc_x%7D%7D%5C%5C+%7B%7D%26%7B%7Bf_y%7D%7D%26%7B%7Bc_y%7D%7D%5C%5C+0%260%261+%5Cend%7Barray%7D%7D+%5Cright%5D%2C%5Cqquad+%7BK%5E%7B+-+1%7D%7D+%3D+%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7Bf_x%5E%7B+-+1%7D%7D%26%7B%7D%26%7B+-+f_x%5E%7B+-+1%7D%7Bc_x%7D%7D%5C%5C+%7B%7D%26%7Bf_y%5E%7B+-+1%7D%7D%26%7B+-+f_y%5E%7B+-+1%7D%7Bc_y%7D%7D%5C%5C+%7B%7D%26%7B%7D%261+%5Cend%7Barray%7D%7D+%5Cright%5D%5C%5D& alt=&\[K = \left[ {\begin{array}{*{20}{c}} {{f_x}}&{}&{{c_x}}\\ {}&{{f_y}}&{{c_y}}\\ 0&0&1 \end{array}} \right],\qquad {K^{ - 1}} = \left[ {\begin{array}{*{20}{c}} {f_x^{ - 1}}&{}&{ - f_x^{ - 1}{c_x}}\\ {}&{f_y^{ - 1}}&{ - f_y^{ - 1}{c_y}}\\ {}&{}&1 \end{array}} \right]\]& eeimg=&1&&&/p&&p&设有两个帧,一个称为Host,一个称Target,它们各自到世界坐标的变换矩阵记为 &img src=&/equation?tex=%5C%5B%7BT_%7BHW%7D%7D%2C%7BT_%7BTW%7D%7D%5C%5D& alt=&\[{T_{HW}},{T_{TW}}\]& eeimg=&1&& ,这二者又可以拆开为旋转和平移。考虑Host帧中一个像素点:&/p&&p&&img src=&/equation?tex=%5C%5B%7Bx_H%7D+%3D+%5Cleft%5B+%7Bu_T%2Cv_T%7D%2C1+%5Cright%5D_H%5ET%5C%5D& alt=&\[{x_H} = \left[ {u_T,v_T},1 \right]_H^T\]& eeimg=&1&&&/p&&p&其中 &img src=&/equation?tex=u_T%2Cv_T& alt=&u_T,v_T& eeimg=&1&& 为该点的像素坐标,这里使用了齐次坐标以方便矩阵运算。同时,该点的逆深度为:&/p&&p&&img src=&/equation?tex=%5C%5B%7B%5Crho+_H%7D+%3D+%5Cfrac%7B1%7D%7B%7B%7Bd_H%7D%7D%7D%5C%5D& alt=&\[{\rho _H} = \frac{1}{{{d_H}}}\]& eeimg=&1&&&/p&&p&其中 &img src=&/equation?tex=d_H& alt=&d_H& eeimg=&1&& 为该点的深度值。那么,这个点在Target帧中的投影为:&/p&&p&&img src=&/equation?tex=%5C%5B%5Cbegin%7Barray%7D%7Bll%7D+%7B%5Crho+_T%5E%7B-1%7D%7D%7Bx_T%7D+%26%3D+K%5Cunderbrace+%7B%7BT_%7BTW%7D%7DT_%7BHW%7D%5E%7B+-+1%7D%7D_%7B%7BT_%7BTH%7D%7D%7D%5Cunderbrace+%7B%7BK%5E%7B+-+1%7D%7D%5Cfrac%7B1%7D%7B%7B%7B%5Crho+_H%7D%7D%7D%7Bx_H%7D%7D_%7B%7Bp_W%7D%7D%5C%5C+%26%3D+K%5Cleft%28+%7B%7BR_%7BTH%7D%7D%7Bp_W%7D+%2B+%7Bt_%7BTH%7D%7D%7D+%5Cright%29+%5C%5C+%5Cend%7Barray%7D%5C%5D& alt=&\[\begin{array}{ll} {\rho _T^{-1}}{x_T} &= K\underbrace {{T_{TW}}T_{HW}^{ - 1}}_{{T_{TH}}}\underbrace {{K^{ - 1}}\frac{1}{{{\rho _H}}}{x_H}}_{{p_W}}\\ &= K\left( {{R_{TH}}{p_W} + {t_{TH}}} \right) \\ \end{array}\]& eeimg=&1&&&/p&&p&注:(i). 为方便起见,我们略去了此公式中的齐次坐标至非齐次的转换,默认它们是自动转换的;(ii). 我们定义了中间变量 &img src=&/equation?tex=p_w%2C+T_%7BTH%7D& alt=&p_w, T_{TH}& eeimg=&1&& ,即点的世界坐标,以及Host至Target的相对变换。&/p&&p&由此可以定义该点的残差。设Host和Target的图像分别是 &img src=&/equation?tex=I_H%2C+I_T& alt=&I_H, I_T& eeimg=&1&& ,那么残差为:&/p&&p&&img src=&/equation?tex=%5C%5Be+%3D+%7BI_H%7D%5Cleft%28+%7B%7Bx_H%7D%7D+%5Cright%29+-+%7BI_T%7D%5Cleft%28+%7B%7Bx_T%7D%7D+%5Cright%29%5C%5D& alt=&\[e = {I_H}\left( {{x_H}} \right) - {I_T}\left( {{x_T}} \right)\]& eeimg=&1&&&/p&&p&但是在实现中,DSO会同时估计图像的光度参数a,b,所以在计算误差时,会用到去掉光度参数之后的那个值。但是这里我们先不谈光度标定部分,所以暂时把 &img src=&/equation?tex=I_H%2CI_T& alt=&I_H,I_T& eeimg=&1&& 看成原始图像。&/p&&p&接下来我们要谈论雅可比。在完整DSO中,雅可比由三部分组成:&/p&&ul&&li&图像雅可比,即图像梯度;&/li&&li&几何雅可比,描述各量相对几何量,例如旋转和平移的变化率;&/li&&li&光度雅可比,描述各个量相对光度参数的雅可比;&/li&&/ul&&p&作者认为,几何和光度的雅可比,相对自变量来说通常是光滑函数;而图像雅可比则依赖图像数据,不够光滑;所以,在优化过程中,几何和光度的雅可比仅在迭代开始时计算一次,此后固定不变[1]。而图像雅可比则随着迭代更新。这种做法称为First-Estimate-Jacobian(FEJ),在VIO中也会经常用到[8]。它可以减小计算量、防止优化往错误的地方走太多,也可以在边缘化过程中保证零空间的维度不会降低,后者我们还要在后文继续谈。&/p&&p&下面来看几何雅可比的具体计算。记 &img src=&/equation?tex=%5C%5B%7B%5Cxi+_T%7D%5C%5D& alt=&\[{\xi _T}\]& eeimg=&1&& 为李代数表示的 &img src=&/equation?tex=T_%7BTW%7D& alt=&T_{TW}& eeimg=&1&& ,并定义:&/p&&p&&img src=&/equation?tex=x_T%5Cbuildrel+%5CDelta+%5Cover+%3D+K+%5Bu%2Cv%2C1%5D_T%5ET%3D%5Crho_T+K+%5Cleft%28+%7B%7BR_%7BTH%7D%7D%7Bp_W%7D+%2B+%7Bt_%7BTH%7D%7D%7D+%5Cright%29& alt=&x_T\buildrel \Delta \over = K [u,v,1]_T^T=\rho_T K \left( {{R_{TH}}{p_W} + {t_{TH}}} \right)& eeimg=&1&&&/p&&p&根据[7]的推导加一些变化,可知:&/p&&p&&img src=&/equation?tex=%5C%5B%5Cfrac%7B%7B%5Cpartial+%7Bx_T%7D%7D%7D%7B%7B%5Cpartial+%7B%5Cxi+_T%7D%7D%7D+%3D+%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B%7B%5Crho+_T%7D%7Bf_x%7D%7D%260%26%7B+-+%7B%5Crho+_T%7D%7Bu%7D%7Bf_x%7D%7D%26%7B+-+%7Bu%7D%7Bv%7D%7Bf_x%7D%7D%26%7B%5Cleft%28+%7B1+%2B+u%5E2%7D+%5Cright%29%7Bf_x%7D%7D%26%7B+-+v%7Bf_x%7D%7D%5C%5C+0%26%7B%7B%5Crho+_T%7D%7Bf_y%7D%7D%26%7B+-+%7Bf_y%7D%7B%5Crho+_T%7D%7Bv%7D%7D%26%7B+-+%5Cleft%28+%7B1+%2B+%7Bv%5E2%7D%7D+%5Cright%29%7Bf_y%7D%7D%26%7B%7Bf_y%7Duv%7D%26%7B%7Bf_y%7Du%7D+%5Cend%7Barray%7D%7D+%5Cright%5D%5C%5D& alt=&\[\frac{{\partial {x_T}}}{{\partial {\xi _T}}} = \left[ {\begin{array}{*{20}{c}} {{\rho _T}{f_x}}&0&{ - {\rho _T}{u}{f_x}}&{ - {u}{v}{f_x}}&{\left( {1 + u^2} \right){f_x}}&{ - v{f_x}}\\ 0&{{\rho _T}{f_y}}&{ - {f_y}{\rho _T}{v}}&{ - \left( {1 + {v^2}} \right){f_y}}&{{f_y}uv}&{{f_y}u} \end{array}} \right]\]& eeimg=&1&&&/p&&p&再考虑对于Host帧中的逆深度 &img src=&/equation?tex=%5Crho_H& alt=&\rho_H& eeimg=&1&& 之雅可比:&/p&&p&&img src=&/equation?tex=%5C%5B%5Cfrac%7B%7B%5Cpartial+%7Bx_T%7D%7D%7D%7B%7B%5Cpartial+%7B%5Crho+_H%7D%7D%7D+%3D+%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B%5Cfrac%7B%7B%5Cpartial+%7Bx_T%7D%7D%7D%7B%7B%5Cpartial+u%7D%7D%7D%26%7B%5Cfrac%7B%7B%5Cpartial+%7Bx_T%7D%7D%7D%7B%7B%5Cpartial+v%7D%7D%7D+%5Cend%7Barray%7D%7D+%5Cright%5D%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B%5Cfrac%7B%7B%5Cpartial+u%7D%7D%7B%7B%5Cpartial+%7B%5Crho+_H%7D%7D%7D%7D%5C%5C+%7B%5Cfrac%7B%7B%5Cpartial+v%7D%7D%7B%7B%5Cpartial+%7B%5Crho+_H%7D%7D%7D%7D+%5Cend%7Barray%7D%7D+%5Cright%5D%5C%5D& alt=&\[\frac{{\partial {x_T}}}{{\partial {\rho _H}}} = \left[ {\begin{array}{*{20}{c}} {\frac{{\partial {x_T}}}{{\partial u}}}&{\frac{{\partial {x_T}}}{{\partial v}}} \end{array}} \right]\left[ {\begin{array}{*{20}{c}} {\frac{{\partial u}}{{\partial {\rho _H}}}}\\ {\frac{{\partial v}}{{\partial {\rho _H}}}} \end{array}} \right]\]& eeimg=&1&&&/p&&p&显然:&/p&&p&&img src=&/equation?tex=%5C%5B%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B%5Cfrac%7B%7B%5Cpartial+%7Bx_T%7D%7D%7D%7B%7B%5Cpartial+u%7D%7D%7D%26%7B%5Cfrac%7B%7B%5Cpartial+%7Bx_T%7D%7D%7D%7B%7B%5Cpartial+v%7D%7D%7D+%5Cend%7Barray%7D%7D+%5Cright%5D+%3D+%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B%7Bf_x%7D%7D%26%7B%7Bf_y%7D%7D+%5Cend%7Barray%7D%7D+%5Cright%5D%5C%5D& alt=&\[\left[ {\begin{array}{*{20}{c}} {\frac{{\partial {x_T}}}{{\partial u}}}&{\frac{{\partial {x_T}}}{{\partial v}}} \end{array}} \right] = \left[ {\begin{array}{*{20}{c}} {{f_x}}&{{f_y}} \end{array}} \right]\]& eeimg=&1&&&/p&&p&对于后者,首先记:&/p&&p&&img src=&/equation?tex=%7B%5Cleft%28+%7B%7BR_%7BTH%7D%7D%7BK%5E%7B+-+1%7D%7D%7Bx_H%7D%7D+%5Cright%29%7D%3Da& alt=&{\left( {{R_{TH}}{K^{ - 1}}{x_H}} \right)}=a& eeimg=&1&&&/p&&p&那么:&/p&&p&&img src=&/equation?tex=%5C%5Bu+%3D+%7B%5Crho+_T%7D%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7D%7Ba_1%7D+%2B+%7Bt_1%7D%7D+%5Cright%29+%3D+%5Cfrac%7B%7B%5Crho+_H%5E%7B+-+1%7D%7Ba_1%7D+%2B+%7Bt_1%7D%7D%7D%7B%7B%5Crho+_H%5E%7B+-+1%7D%7Ba_3%7D+%2B+%7Bt_3%7D%7D%7D+%3D+%5Cleft%28+%7B%7Ba_1%7D+%2B+%7B%5Crho+_H%7D%7Bt_1%7D%7D+%5Cright%29%5Cleft%28+%7B%7Ba_3%7D+%2B+%7B%5Crho+_H%7D%7Bt_3%7D%7D+%5Cright%29%5E%7B-1%7D%5C%5D& alt=&\[u = {\rho _T}\left( {\rho _H^{ - 1}{a_1} + {t_1}} \right) = \frac{{\rho _H^{ - 1}{a_1} + {t_1}}}{{\rho _H^{ - 1}{a_3} + {t_3}}} = \left( {{a_1} + {\rho _H}{t_1}} \right)\left( {{a_3} + {\rho _H}{t_3}} \right)^{-1}\]& eeimg=&1&&&/p&&p&其中下标1表示取第一行,3表示第三行。于是&/p&&p&&img src=&/equation?tex=%5C%5B%5Cbegin%7Barray%7D%7Bll%7D+%5Cfrac%7B%7B%5Cpartial+u%7D%7D%7B%7B%5Cpartial+%7B%5Crho+_H%7D%7D%7D+%26%3D+%7Bt_1%7D%7B%5Cleft%28+%7B%7Ba_3%7D+%2B+%7B%5Crho+_H%7D%7Bt_3%7D%7D+%5Cright%29%5E%7B+-+1%7D%7D+%2B+%5Cleft%28+%7B%7Ba_1%7D+%2B+%7B%5Crho+_H%7D%7Bt_1%7D%7D+%5Cright%29%5Cfrac%7B%7B+-+%7Bt_3%7D%7D%7D%7B%7B%7B%7B%5Cleft%28+%7B%7Ba_3%7D+%2B+%7B%5Crho+_H%7D%7Bt_3%7D%7D+%5Cright%29%7D%5E2%7D%7D%7D%5C%5C+%26+%3D+%7Bt_1%7D%7B%5Cleft%28+%7B%7Ba_3%7D+%2B+%7B%5Crho+_H%7D%7Bt_3%7D%7D+%5Cright%29%5E%7B+-+1%7D%7D+-+u%7Bt_3%7D%7B%5Cleft%28+%7B%7Ba_3%7D+%2B+%7B%5Crho+_H%7D%7Bt_3%7D%7D+%5Cright%29%5E%7B+-+1%7D%7D+%5C%5C%26%3D+%5Cleft%28+%7B%7Bt_1%7D+-+u%7Bt_3%7D%7D+%5Cright%29%5Cfrac%7B%7B%7B%5Crho+_T%7D%7D%7D%7B%7B%7B%5Crho+_H%7D%7D%7D+%5Cend%7Barray%7D%5C%5D& alt=&\[\begin{array}{ll} \frac{{\partial u}}{{\partial {\rho _H}}} &= {t_1}{\left( {{a_3} + {\rho _H}{t_3}} \right)^{ - 1}} + \left( {{a_1} + {\rho _H}{t_1}} \right)\frac{{ - {t_3}}}{{{{\left( {{a_3} + {\rho _H}{t_3}} \right)}^2}}}\\ & = {t_1}{\left( {{a_3} + {\rho _H}{t_3}} \right)^{ - 1}} - u{t_3}{\left( {{a_3} + {\rho _H}{t_3}} \right)^{ - 1}} \\&= \left( {{t_1} - u{t_3}} \right)\frac{{{\rho _T}}}{{{\rho _H}}} \end{array}\]& eeimg=&1&&&/p&&p&最后的式子中我们重新把 &img src=&/equation?tex=%5Crho_T& alt=&\rho_T& eeimg=&1&& 代回去,使得式子更加简洁。同理有:&/p&&p&&img src=&/equation?tex=%5C%5B%5Cfrac%7B%7B%5Cpartial+v%7D%7D%7B%7B%5Cpartial+%7B%5Crho+_H%7D%7D%7D+%3D+%5Cleft%28+%7B%7Bt_2%7D+-+v%7Bt_3%7D%7D+%5Cright%29%5Cfrac%7B%7B%7B%5Crho+_T%7D%7D%7D%7B%7B%7B%5Crho+_H%7D%7D%7D%5C%5D& alt=&\[\frac{{\partial v}}{{\partial {\rho _H}}} = \left( {{t_2} - v{t_3}} \right)\frac{{{\rho _T}}}{{{\rho _H}}}\]& eeimg=&1&&&/p&&p&于是得:&/p&&p&&img src=&/equation?tex=%5C%5B%5Cfrac%7B%7B%5Cpartial+%7Bx_T%7D%7D%7D%7B%7B%5Cpartial+%7B%5Crho+_H%7D%7D%7D+%3D+%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B%7Bf_x%7D%5Cleft%28+%7B%7Bt_1%7D+-+u%7Bt_3%7D%7D+%5Cright%29%7B%5Crho+_T%7D%2F%7B%5Crho+_H%7D%7D%5C%5C+%7B%7Bf_y%7D%5Cleft%28+%7B%7Bt_2%7D+-+v%7Bt_3%7D%7D+%5Cright%29%7B%5Crho+_T%7D%2F%7B%5Crho+_H%7D%7D+%5Cend%7Barray%7D%7D+%5Cright%5D%5C%5D& alt=&\[\frac{{\partial {x_T}}}{{\partial {\rho _H}}} = \left[ {\begin{array}{*{20}{c}} {{f_x}\left( {{t_1} - u{t_3}} \right){\rho _T}/{\rho _H}}\\ {{f_y}\left( {{t_2} - v{t_3}} \right){\rho _T}/{\rho _H}} \end{array}} \right]\]& eeimg=&1&&&/p&&p&接下来考虑残差相对于相机内参的雅可比,这部分相对于其余部分稍为复杂,我们仅展示残差对 &img src=&/equation?tex=f_x& alt=&f_x& eeimg=&1&& 之导数,其余部分类似可得,因此留给读者。由于:&/p&&p&&img src=&/equation?tex=%5C%5B%7Bx_T%7D+%3D+K%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+u%5C%5C+v%5C%5C+1+%5Cend%7Barray%7D%7D+%5Cright%5D%2C%5Cquad+%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+u%5C%5C+v%5C%5C+1+%5Cend%7Barray%7D%7D+%5Cright%5D+%3D+%7B%5Crho+_T%7D%5Cleft%28+%7B%5Cfrac%7B1%7D%7B%7B%7B%5Crho+_H%7D%7D%7DR%5Cunderbrace+%7B%7BK%5E%7B+-+1%7D%7D%7Bx_H%7D%7D_P+%2B+t%7D+%5Cright%29%5C%5D& alt=&\[{x_T} = K\left[ {\begin{array}{*{20}{c}} u\\ v\\ 1 \end{array}} \right],\quad \left[ {\begin{array}{*{20}{c}} u\\ v\\ 1 \end{array}} \right] = {\rho _T}\left( {\frac{1}{{{\rho _H}}}R\underbrace {{K^{ - 1}}{x_H}}_P + t} \right)\]& eeimg=&1&&&/p&&p&该式略去了 &img src=&/equation?tex=R%2Ct& alt=&R,t& eeimg=&1&& 的下标,以保持行文简洁。展开后式,有:&/p&&p&&img src=&/equation?tex=%5C%5B%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+u%5C%5C+v%5C%5C+1+%5Cend%7Barray%7D%7D+%5Cright%5D+%3D+%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B%7B%5Crho+_T%7D%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_1%5ETP+%2B+%7Bt_1%7D%7D+%5Cright%29%7D%5C%5C+%7B%7B%5Crho+_T%7D%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_2%5ETP+%2B+%7Bt_2%7D%7D+%5Cright%29%7D%5C%5C+%7B%7B%5Crho+_T%7D%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_3%5ETP+%2B+%7Bt_3%7D%7D+%5Cright%29%7D+%5Cend%7Barray%7D%7D+%5Cright%5D%5C%5D& alt=&\[\left[ {\begin{array}{*{20}{c}} u\\ v\\ 1 \end{array}} \right] = \left[ {\begin{array}{*{20}{c}} {{\rho _T}\left( {\rho _H^{ - 1}r_1^TP + {t_1}} \right)}\\ {{\rho _T}\left( {\rho _H^{ - 1}r_2^TP + {t_2}} \right)}\\ {{\rho _T}\left( {\rho _H^{ - 1}r_3^TP + {t_3}} \right)} \end{array}} \right]\]& eeimg=&1&&&/p&&p&于是:&/p&&p&&img src=&/equation?tex=%5C%5B%7Bx_T%7D+%3D+%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B%7Bf_x%7D%5Cunderbrace+%7B%7B%5Crho+_T%7D%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_1%5ETP+%2B+%7Bt_1%7D%7D+%5Cright%29%7D_u+%2B+%7Bc_x%7D%7D%5C%5C+%7B%7Bf_y%7D%5Cunderbrace+%7B%7B%5Crho+_T%7D%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_2%5ETP+%2B+%7Bt_2%7D%7D+%5Cright%29%7D_v+%2B+%7Bc_y%7D%7D%5C%5C+%7B%5Cunderbrace+%7B%7B%5Crho+_T%7D%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_3%5ETP+%2B+%7Bt_3%7D%7D+%5Cright%29%7D_1%7D+%5Cend%7Barray%7D%7D+%5Cright%5D%5C%5D& alt=&\[{x_T} = \left[ {\begin{array}{*{20}{c}} {{f_x}\underbrace {{\rho _T}\left( {\rho _H^{ - 1}r_1^TP + {t_1}} \right)}_u + {c_x}}\\ {{f_y}\underbrace {{\rho _T}\left( {\rho _H^{ - 1}r_2^TP + {t_2}} \right)}_v + {c_y}}\\ {\underbrace {{\rho _T}\left( {\rho _H^{ - 1}r_3^TP + {t_3}} \right)}_1} \end{array}} \right]\]& eeimg=&1&&&/p&&p&现在想要求第一行关于 &img src=&/equation?tex=f_x& alt=&f_x& eeimg=&1&& 之导数,由链式法则:&/p&&p&&img src=&/equation?tex=%5C%5B%5Cfrac%7B%7B%5Cpartial+%7Bx_%7BT%2C1%7D%7D%7D%7D%7B%7B%5Cpartial+%7Bf_x%7D%7D%7D+%3D+u+%2B+%7Bf_x%7D%5Cfrac%7B%7B%5Cpartial+u%7D%7D%7B%7B%5Cpartial+%7Bf_x%7D%7D%7D%5C%5D& alt=&\[\frac{{\partial {x_{T,1}}}}{{\partial {f_x}}} = u + {f_x}\frac{{\partial u}}{{\partial {f_x}}}\]& eeimg=&1&&&/p&&p&而&/p&&p&&img src=&/equation?tex=%5C%5B%5Cfrac%7B%7B%5Cpartial+u%7D%7D%7B%7B%5Cpartial+%7Bf_x%7D%7D%7D+%3D+%5Cfrac%7B%7B%5Cpartial+u%7D%7D%7B%7B%5Cpartial+P%5ET%7D%7D%5Cfrac%7B%7B%5Cpartial+P%7D%7D%7B%7B%5Cpartial+%7Bf_x%7D%7D%7D%5C%5D& alt=&\[\frac{{\partial u}}{{\partial {f_x}}} = \frac{{\partial u}}{{\partial P^T}}\frac{{\partial P}}{{\partial {f_x}}}\]& eeimg=&1&&&/p&&p&第一项中,由前述,有:&/p&&p&&img src=&/equation?tex=%5C%5Bu+%3D+%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_1%5ETP+%2B+%7Bt_1%7D%7D+%5Cright%29%7B%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_3%5ETP+%2B+%7Bt_3%7D%7D+%5Cright%29%5E%7B+-+1%7D%7D%5C%5D& alt=&\[u = \left( {\rho _H^{ - 1}r_1^TP + {t_1}} \right){\left( {\rho _H^{ - 1}r_3^TP + {t_3}} \right)^{ - 1}}\]& eeimg=&1&&&/p&&p&于是&/p&&p&&img src=&/equation?tex=%5C%5B%5Cbegin%7Barray%7D%7Bl%7D+%5Cfrac%7B%7B%5Cpartial+u%7D%7D%7B%7B%5Cpartial+P%7D%7D+%3D+%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7D%7Br_1%7D%7D+%5Cright%29%7B%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_3%5ETP+%2B+%7Bt_3%7D%7D+%5Cright%29%5E%7B+-+1%7D%7D+-+%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_1%5ETP+%2B+%7Bt_1%7D%7D+%5Cright%29%5Cfrac%7B%7B%5Crho+_H%5E%7B+-+1%7D%7Br_3%7D%7D%7D%7B%7B%7B%7B%5Cleft%28+%7B%5Crho+_H%5E%7B+-+1%7Dr_3%5ETP+%2B+%7Bt_3%7D%7D+%5Cright%29%7D%5E2%7D%7D%7D%5C%5C+%3D+%7B%5Crho+_T%7D%2F%7B%5Crho+_H%7D%5Cleft%28+%7B%7Br_1%7D+-+%7Br_3%7Du%7D+%5Cright%29+%5Cend%7Barray%7D%5C%5D& alt=&\[\begin{array}{l} \frac{{\partial u}}{{\partial P}} = \left( {\rho _H^{ - 1}{r_1}} \right){\left( {\rho _H^{ - 1}r_3^TP + {t_3}} \right)^{ - 1}} - \left( {\rho _H^{ - 1}r_1^TP + {t_1}} \right)\frac{{\rho _H^{ - 1}{r_3}}}{{{{\left( {\rho _H^{ - 1}r_3^TP + {t_3}} \right)}^2}}}\\ = {\rho _T}/{\rho _H}\left( {{r_1} - {r_3}u} \right) \end{array}\]& eeimg=&1&&&/p&&p&第二项:&/p&&p&&img src=&/equation?tex=%5C%5B%5Cfrac%7B%7B%5Cpartial+P%7D%7D%7B%7B%5Cpartial+%7Bf_x%7D%7D%7D+%3D+%5Cleft%5B+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B+-+f_x%5E%7B+-+1%7D%7BP_1%7D%7D%5C%5C+0%5C%5C+0+%5Cend%7Barray%7D%7D+%5Cright%5D%5C%5D& alt=&\[\frac{{\partial P}}{{\partial {f_x}}} = \left[ {\begin{array}{*{20}{c}} { - f_x^{ - 1}{P_1}}\\ 0\\ 0 \end{array}} \right]\]& eeimg=&1&&&/p&&p&因此:&/p&&p&&img src=&/equation?tex=%5C%5B%5Cbegin%7Barray%7D%7Bll%7D+%5Cfrac%7B%7B%5Cpartial+%7Bx_%7BT%2C1%7D%7D%7D%7D%7B%7B%5Cpartial+%7Bf_x%7D%7D%7D+%26%3D+u+%2B+%7Bf_x%7D%5Cfrac%7B%7B%5Cpartial+u%7D%7D%7B%7B%5Cpartial+%7Bf_x%7D%7D%7D+%3D+u+%2B+%7Bf_x%7D%7B%5Crho+_T%7D%2F%7B%5Crho+_H%7D%7B%5Cleft%28+%7B%7Br_1%7D+-+%7Br_3%7Du%7D+%5Cright%29%5ET%7D%5Cleft%28+%7B%5Cbegin%7Barray%7D%7B%2A%7B20%7D%7Bc%7D%7D+%7B+-+f_x%5E%7B+-+1%7D%7BP_1%7D%7D%5C%5C+0%5C%5C+0+%5Cend%7Barray%7D%7D+%5Cright%29%5C%5C+%26+%3D+u+%2B+%7B%5Cleft%28+%7Br_%7B31%7D%7Du-+%7B%7Br_%7B11%7D%7D+%7D+%5Cright%29%5ET%7D%7BP_1%7D%5Crho_T%2F%5Crho_H+%5Cend%7Barray%7D%5C%5D& alt=&\[\begin{array}{ll} \frac{{\partial {x_{T,1}}}}{{\partial {f_x}}} &= u + {f_x}\frac{{\partial u}}{{\partial {f_x}}} = u + {f_x}{\rho _T}/{\rho _H}{\left( {{r_1} - {r_3}u} \right)^T}\left( {\begin{array}{*{20}{c}} { - f_x^{ - 1}{P_1}}\\ 0\\ 0 \end{array}} \right)\\ & = u + {\left( {r_{31}}u- {{r_{11}} } \right)^T}{P_1}\rho_T/\rho_H \end{array}\]& eeimg=&1&&&/p&&p&于是,得到了投影点关于 &img src=&/equation?tex=f_x& alt=&f_x& eeimg=&1&& 的导数。关于 &img src=&/equation?tex=f_y%2Cc_x%2Cc_y& alt=&f_y,c_x,c_y& eeimg=&1&& 的结论可类似推出,不再赘述。以上计算均实现于PointFrameResidual::linearize函数。&/p&&p&值得一提的是,在DSO中,每个投影点,除了自身的位置之外,一共提供八维残差,这是为了更好利用该点的信息。这八维残差由这个点与周围几个点组成的Pattern定义,如下图所示:&/p&&img src=&/v2-ce30efe925c_b.png& data-rawwidth=&412& data-rawheight=&402& class=&content_image& width=&412&&&p&选八个点是为了方便SSE(Super Strong Erection)(雾),其实在settings.cpp中还有许多别的Pattern。所以,在DSO的直接法中,我们实际上假设了这八个点在不同图像中保持灰度不变。并且,它们在优化中共享中间点的深度,所以也不能简单地看成八个独立的点。&/p&&hr&&p&3.2 滑动窗口的维护与边缘化&/p&&p&若干和关键帧,与它们关联的地图点组成的残差项,构成了整个滑动窗口中的内容。为了优化这些帧和点,我们会利用Gauss-Newton或Levernberg-Marquardt方法进行迭代。在迭代中,所有的残差项可以拼成一个大型的线性方程:&/p&&p&&img src=&/equation?tex=%5Cbegin%7Bequation%7DJ%5ET+W+J+%5Cdelta+x%3D-J%5ET+W+r%5Cend%7Bequation%7D& alt=&\begin{equation}J^T W J \delta x=-J^T W r\end{equation}& eeimg=&1&&&/p&&p&其中 &img src=&/equation?tex=J%2CW%2Cr& alt=&J,W,r& eeimg=&1&& 分别为拼接后的雅可比、权重和残差, &img src=&/equation?tex=%5Cdelta+x& alt=&\delta x& eeimg=&1&& 为整体的优化更新量。左侧可以记成: &img src=&/equation?tex=J%5ET+WJ%3DH& alt=&J^T WJ=H& eeimg=&1&& ,即Hessian矩阵。这个矩阵在整个优化过程中都会一直维护于内存中。注意这种做法和ORB-SLAM2是不同的。在ORB-SLAM2的后端中,我们会不停地重构整个优化问题,求解,然后存储优化后的结果,但这个H矩阵是不会一直存在的。而在DSO中,由于H是一直维护的,所以之后的优化可以利用先前的结果,或者说,先前的优化为下一步提供了&b&先验&/b&(&b&Prior&/b&)。但是,为了维护这个H信息,DSO必须手动地增加/删除每一个帧和点,而不像ORB-SLAM2那样,可以无视帧和点的变化。&/p&&p&我们知道,H实际上有一个特殊的形状(&b&箭头形矩阵,Arrow-like Matrix&/b&)[1,7,9],如下图所示:&/p&&img src=&/v2-01b132d5539ceec5eabc_b.png& data-rawwidth=&1052& data-rawheight=&576& class=&origin_image zh-lightbox-thumb& width=&1052& data-original=&/v2-01b132d5539ceec5eabc_r.png&&&p&众所周知,这个形状是由BA本身的结构导致的。把它的分块记为:&/p&&p&&img src=&/equation?tex=+%5Cleft%5B+%5Cbegin%7Bmatrix%7D+%5Cbm%7BB%7D+%26+%5Cbm%7BE%7D+%5C%5C+%5Cbm%7BE%5ET%7D+%26+%5Cbm%7BC%7D+%5Cend%7Bmatrix%7D%5Cright%5D+%5Cleft%5B+%5Cbegin%7Barray%7D%7Bl%7D+%5CDelta+%5Cbm%7Bx%7D_c+%5C%5C+%5CDelta+%5Cbm%7Bx%7D_p+%5Cend%7Barray%7D+%5Cright%5D+%3D+%5Cleft%5B+%5Cbegin%7Barray%7D%7Bl%7D+%5Cbm%7Bv%7D+%5C%5C+%5Cbm%7Bw%7D+%5Cend%7Barray%7D+%5Cright%5D.& alt=& \left[ \begin{matrix} \bm{B} & \bm{E} \\ \bm{E^T} & \bm{C} \end{matrix}\right] \left[ \begin{array}{l} \Delta \bm{x}_c \\ \Delta \bm{x}_p \end{array} \right] = \left[ \begin{array}{l} \bm{v} \\ \bm{w} \end{array} \right].& eeimg=&1&&&/p&&p&那么右下角的 &img src=&/equation?tex=%5Cbm%7BC%7D& alt=&\bm{C}& eeimg=&1&& 是一个对角块矩阵(因为没有结构的先验,即点——点的残差)。块的大小取决于地图点的参数化维度,在DSO中是一维,在ORB-SLAM2中是三维。接下来,在传统BA中(类似于ORB-SLAM2)的做法是这样的:&/p&&ul&&li&通过图优化构建这个H;&/li&&li&用高斯消元法(即舒尔补)将右下角部分消元:&/li&&/ul&&p&&img src=&/equation?tex=%5Cleft%5B+%5Cbegin%7Bmatrix%7D+%5Cbm%7BI%7D+%26+-%5Cbm%7BEC%5E%7B-1%7D%7D+%5C%5C+%5Cbm%7B0%7D+%26+%5Cbm%7BI%7D+%5Cend%7Bmatrix%7D%5Cright%5D+%5Cleft%5B+%5Cbegin%7Bmatrix%7D+%5Cbm%7BB%7D+%26+%5Cbm%7BE%7D+%5C%5C+%5Cbm%7BE%5ET%7D+%26+%5Cbm%7BC%7D+%5Cend%7Bmatrix%7D%5Cright%5D+%5Cleft%5B+%5Cbegin%7Barray%7D%7Bl%7D+%5CDelta+%5Cbm%7Bx%7D_c+%5C%5C+%5CDelta+%5Cbm%7Bx%7D_p+%5Cend%7Barray%7D+%5Cright%5D+%3D+%5Cleft%5B+%5Cbegin%7Bmatrix%7D+%5Cbm%7BI%7D+%26+-%5Cbm%7BEC%5E%7B-1%7D%7D+%5C%5C+%5Cbm%7B0%7D+%26+%5Cbm%7BI%7D+%5Cend%7Bmatrix%7D+%5Cright%5D+%5Cleft%5B+%5Cbegin%7Barray%7D%7Bl%7D+%5Cbm%7Bv%7D+%5C%5C+%5Cbm%7Bw%7D+%5Cend%7Barray%7D+%5Cright%5D+.& alt=&\left[ \begin{matrix} \bm{I} & -\bm{EC^{-1}} \\ \bm{0} & \bm{I} \end{matrix}\right] \left[ \begin{matrix} \bm{B} & \bm{E} \\ \bm{E^T} & \bm{C} \end{matrix}\right] \left[ \begin{array}{l} \Delta \bm{x}_c \\ \Delta \bm{x}_p \end{array} \right] = \left[ \begin{matrix} \bm{I} & -\bm{EC^{-1}} \\ \bm{0} & \bm{I} \end{matrix} \right] \left[ \begin{array}{l} \bm{v} \\ \bm{w} \end{array} \right] .& eeimg=&1&&&/p&&p&即:&/p&&p&&img src=&/equation?tex=%5Cleft%5B+%5Cbegin%7Bmatrix%7D+%5Cbm%7BB%7D+-+%5Cbm%7BE%7D%5Cbm%7BC%7D%5E%7B-1%7D%5Cbm%7BE%7D%5ET+%26+%5Cbm%7B0%7D+%5C%5C+%5Cbm%7BE%7D%5ET+%26+%5Cbm%7BC%7D+%5Cend%7Bmatrix%7D+%5Cright%5D+%5Cleft%5B+%5Cbegin%7Barray%7D%7Bl%7D+%5CDelta+%5Cbm%7Bx%7D_c+%5C%5C+%5CDelta+%5Cbm%7Bx%7D_p+%5Cend%7Barray%7D+%5Cright%5D+%3D+%5Cleft%5B%5Cbegin%7Barray%7D%7Bl%7D+%5Cbm%7Bv%7D+-+%5Cbm%7BE%7D%5Cbm%7BC%7D%5E%7B-1%7D%5Cbm%7Bw%7D+%5C%5C+%5Cbm%7Bw%7D+%5Cend%7Barray%7D%5Cright%5D.& alt=&\left[ \begin{matrix} \bm{B} - \bm{E}\bm{C}^{-1}\bm{E}^T & \bm{0} \\ \bm{E}^T & \bm{C} \end{matrix} \right] \left[ \begin{array}{l} \Delta \bm{x}_c \\ \Delta \bm{x}_p \end{array} \right] = \left[\begin{array}{l} \bm{v} - \bm{E}\bm{C}^{-1}\bm{w} \\ \bm{w} \end{array}\right].& eeimg=&1&&&/p&&ul&&li&此时方程解耦,于是先解左上部分(维度很小);再用左上部分的结果解右下部分。&/li&&/ul&&p&&img src=&/equation?tex=%5Cleft%5B+%5Cbm%7BB%7D+-+%5Cbm%7BE%7D%5Cbm%7BC%7D%5E%7B-1%7D%5Cbm%7BE%7D%5ET+%5Cright%5D+%5CDelta+%5Cbm%7Bx%7D_c+%3D+%5Cbm%7Bv%7D+-+%5Cbm%7BE%7D%5Cbm%7BC%7D%5E%7B-1%7D%5Cbm%7Bw%7D+.& alt=&\left[ \bm{B} - \bm{E}\bm{C}^{-1}\bm{E}^T \right] \Delta \bm{x}_c = \bm{v} - \bm{E}\bm{C}^{-1}\bm{w} .& eeimg=&1&&&/p&&p&&img src=&/equation?tex=%5CDelta+%5Cbm%7Bx%7D_p+%3D+%5Cbm%7BC%7D%5E%7B-1%7D+%28%5Cbm%7Bw%7D+-+%5Cbm%7BE%7D%5E%7BT%7D+%5CDelta+%5Cbm%7Bx%7D_c%29& alt=&\Delta \bm{x}_p = \bm{C}^{-1} (\bm{w} - \bm{E}^{T} \Delta \bm{x}_c)& eeimg=&1&&&/p&&p&这个过程也称为&b&边缘化(Marginalization)&/b&,此时我们边缘化掉了所有的点,将他们的信息归到了位姿部分中,形成了相机位姿部分的先验。这部分知识,对于每位SLAM研究者来说应当是熟知的。&/p&&p&那么在DSO中,有哪些地方用了边缘化?&/p&&p&首先,DSO的BA,也和传统BA一样,有上述步骤。因此DSO在解BA时,边缘化了所有点的信息,计算优化的更新量。然而,与传统BA不同的是,DSO的左上角部分,即公式中的 &img src=&/equation?tex=%5Cbm%7BB%7D& alt=&\bm{B}& eeimg=&1&& ,并非为对角块,而是有先验的。传统BA中,这部分为对角块,主要原因是不知道相机运动的先验,而DSO的滑动窗口,则通过一定手段计算了这个先验。这里的先验主要来自两个部分:&/p&&ol&&li&边缘化某个点时,这个点的共视帧之间产生先验;&/li&&li&边缘化某个帧时,在窗口内其他帧之间产生先验;&/li&&/ol&&p&这里的“边缘化”,具体的操作和上面讲的边缘化,是一样的。也就是说,通过舒尔补,用矩阵的一部分去消元另一部分。然而实际操作的含义却有所不同。在BA的边缘化中,我们希望用边缘化加速整个问题的求解,但是解完问题后,这些帧和点仍旧是存在于窗口中的!而滑动窗口中的边缘化,是指我们不再需要这个点/这个帧。当它被边缘化时,我们将它的信息传递到了之后的先验中,而不会再利用这个点/这个帧了!请读者务必理清这层区别,否则在理解过程中会遇到问题。我们不妨将后者称为“永久边缘化”,以示区分。&/p&&p&那么DSO如何永久边缘化某个帧或点?它遵循以下几个准则:&/p&&ul&&li&如果一个点已经不在相机视野内,就边缘化这个点;&/li&&li&如果滑动窗口内的帧数量已经超过设定阈值,那么选择其中一个帧进行边缘化;&/li&&li&当某个帧被边缘化时,以它为主导的地图点将被移除,不再参与以后的计算。否则这个点将与其他点形成结构先验,破坏BA中的稀疏结构[10]。&/li&&/ul&&p&在边缘化的过程,DSO维护了帧与帧间的先验信息(见EnergyFunctional::HM和bM),并将这些信息利用到BA的求解中去。&/p&&p&3.3 零空间,FEJ&/p&&p&在SLAM中,GN或LM优化过程中,状态变量事实上是存在零空间(nullspace)的。所谓零空间,就是说,如果在这个子空间内改变状态变量的值,不会影响到优化的目标函数取值。在纯视觉SLAM中,典型的零空间就是场景的绝对尺度,以及相机的绝对位姿。可以想象,如果将相机和地图同时扩大一个尺度,或者同时作一次旋转和平移,整个目标函数应该不发生改变。零空间的存在也会导致在优化过程中,线性方程的解不唯一。尽管每次迭代的步长都很小,但是时间长了,也容易让整个系统在这个零空间中游荡,令尺度发生漂移。&/p&&p&另一方面,由于边缘化的存在,如果一个点被边缘化,那它的雅可比等矩阵就要被固定于被边缘化之时刻,而其他点的雅可比还会随着时间更新,就使得整个系统中不同变量被线性化的时刻是不同的。这会导致零空间的降维——本应存在的零空间,由于线性化时刻的不同,反而消失了!而我们的估计也会变得过于乐观。&/p&&p&DSO作者提出了一个很好的例子以展现这件事情。见下图。&/p&&img src=&/v2-5cbd2ee0441_b.png& data-rawwidth=&1484& data-rawheight=&820& class=&origin_image zh-lightbox-thumb& width=&1484& data-original=&/v2-5cbd2ee0441_r.png&&&p&在这个例子中,我们最小化 &img src=&/equation?tex=E%3DE_1%2BE_2%3D%28xy-1%29%5E2%2B%28xy-1%29%5E2& alt=&E=E_1+E_2=(xy-1)^2+(xy-1)^2& eeimg=&1&& ,那么显然 &img src=&/equation?tex=xy%3D1& alt=&xy=1& eeimg=&1&& 这条曲线就是优化问题的最优解,正好是一维的零空间。但是,如果 &img src=&/equation?tex=E_1& alt=&E_1& eeimg=&1&& 和 &img src=&/equation?tex=E_2& alt=&E_2& eeimg=&1&& 在不同点上线性化,那么求得的 &img src=&/equation?tex=E& alt=&E& eeimg=&1&& 可能会让这一维的零空间消失(如图例),这时最优解变成了一个点。&/p&&p&因此,在DSO实际使用时,仅在优化的初始时刻计算几何和光度的雅可比,并让它们在随后的迭代过程中保持不变,即First-Estimate-Jacobian。FEJ强制让每个点在同一个时刻线性化,从而回避了零空间降维的问题,同时可以降低很多计算量。DSO中的每个地图点,由前面定义的pattern产生8个残差项,这些残差项也会共享FEJ。由于几何和光度函数都比较光滑,实践当中FEJ近似是十分好用的。&/p&&p&3.4 其他零散的模块和算法&/p&&p&除去上述主干以外,DSO还有一些枝节上的算法,例如:&/p&&ul&&li&DSO是怎么初始化的?&/li&&li&DSO的CoarseTracker如何估计新帧的位姿?&/li&&li&未成熟点是如何转换到正常地图点的?&/li&&/ul&&p&(TODO: 待更新)&/p&&hr&&p&4. 光度标定&/p&&p&我发现已经有一些文章介绍DSO的光度标定了[11],所以我考虑不再重复介绍一遍了。如果需要的话我会补上。&/p&&hr&&p&5. 评述&/p&&p&DSO的出现将直接法推进到一个相当成熟可用的地位,许多实验已表明它的精度与鲁棒性均优于现在的ORB-SLAM2,而相比之下LSD-SLAM则显然没有那么成熟。在我自己的实物相机实验中,我发现LSD-SLAM很难一次上手即通,而DSO则鲁棒的多。&/p&&p&在大部分数据集上,DSO均有较好的表现。虽然DSO要求全局曝光相机,但即使是卷帘快门的相机,只要运动不快,模糊不明显,DSO也能顺利工作。但是,如果出现明显的模糊、失真,DSO也会丢失。&/p&&p&我认为,直接法相比传统特征点法,最大的贡献在于,直接法以更整体、更优雅的方式处理了数据关联问题。特征点法需要依赖重复性较强的特征提取器,以及正确的特征匹配,才能得正确地计算相机运动。在环境纹理较好,角点较多时,这当然是可行的——不过直接法在这种环境下也能正常工作。然而,如果环境中出现了下列情况,对特征点法就不那么友善:&/p&&ul&&li&环境中存在许多重复纹理;&/li&&li&环境中缺乏角点,出现许多边缘或光线变量不明显区域;&/li&&/ul&&p&这在实际图像中很常见,我们以道路环境为例(取自kitti):&/p&&img src=&/v2-a5a85cb7a6d96d7f0aefb_b.png& data-rawwidth=&1242& data-rawheight=&375& class=&origin_image zh-lightbox-thumb& width=&1242& data-original=&/v2-a5a85cb7a6d96d7f0aefb_r.png&&&p&显然,路面上角点甚少,仅有车道线的起始/终止处存在角点,其他地方纹理不足;天空通常也没有纹理;路旁栏杆和障碍物重复纹理非常明显。这些都是特征点法必须面对的问题,所以特征点法通常只能依赖一些车辆、行人、交通告示板来确定明显的特征匹配,这会影响整个SLAM系统的稳定性。其根本原因在于:无法找到有用的匹配点、或者容易找到错误的匹配点。例如,车道线边缘上的点外观都非常相似,栏杆附近的点则由于栏杆本身纹理重复,容易出现错配。&/p&&p&而直接法,如前所示,则并不要求一一对应的匹配。只要先前的点在当前图像当中具有合理的投影残差,我们就认为这次投影是成功的。而成功与否,主要取决于我们对地图点深度以及相机位姿的判断,并不在于图像局部看起来是什么样子。举个例子,如果用特征法或光流法追踪某个位于边缘的像素,由于沿着边缘方向图像局部很相似,所以这个匹配或追踪的结果,可能被计算成此边缘方向的另一个点——这主要是因为图像局部的相似性;而直接法的约束则来自更为整体的相机位姿,所以即使单个点无法给出足够的信息,还可以靠其他点来修正它的投影关系,从而找到正确的投影点。&/p&&p&这是一把双刃剑。直接法给予我们追踪边缘、平滑区块的能力,但同时也要付出代价——正确的直接法追踪需要有一个相当不错的初始估计,还需要一个质量较好的图像。由于DSO严重依赖于使用梯度下降的优化问题求解,而它成功的前提,是目标函数从初始值到最优值之间一直是下降的。在图像质量不佳或者相机初始位姿给的不对的情况下,这件事情往往无法得到保证,所以DSO也会丢失。&/p&&p&这种做法一个显而易见的后果是,除非存储所有的关键帧图像,否则很难利用先前建好的地图。退一步说,即使有办法存储所有关键帧的图像,那么在重用地图时,我们还需要对位姿有一个比较准确的初始估计——这通常是困难的,因为你不知道误差已经累计到了多大的程度。而在特征点法中,地图重用则相对简单。我们只需存储空间中所有的特征点和它们的特征描述,然后匹配当前图像中看到的特征,计算位姿即可。&/p&&p&我们看到,数据关联和位姿估计,在直接法中是耦合的,而在特征点法中则是解耦的。耦合的好处,在于能够更整体性地处理数据关联;而解耦的好处,在于能够在位姿不确定的情况下,仅利用图像信息去解数据关联问题。所以直接法理应更擅长求解连续图像的定位,而特征点法则更适和全局的匹配与回环检测。读者应该明了二者优缺点的来由。&/p&&p&当然DSO也不是万能的。最容易看到的缺点,就是它不是个完整的SLAM——它没有回环检测、地图重用、丢失后的重定位,而这些在实际场景中往往又是必不可少的功能。DSO的初始化部分也比较慢,当然双目或RGBD相机会容易很多。如果你想要拓展DSO的功能,首先你需要十分了解DSO的代码结构。希望本文能够起到一定的作用。&/p&&hr&&p&资料与参考文献:&/p&&p&[1]. Engel J, Koltun V, Cremers D. Direct sparse odometry[J]. IEEE Transactions on Pattern Analysis and Machine Intelligence, 2017.&/p&&p&[2]. Forster, C.; Pizzoli, M. & Scaramuzza, D., SVO: Fast semi-direct monocular visual odometry, &i&Robotics and Automation (ICRA), 2014 IEEE International Conference on, &/i&. &/p&&p&[3]. Mur-Artal, R.; Montiel, J. & Tardós, J. D. ORB-slam: a versatile and accurate monocular slam system, &i&IEEE Transactions on Robotics, IEEE, &/i&2015&i&, 31&/i&, .&/p&&p&[4]. Bowman, S. L.; Atanasov, N.; Daniilidis, K. & Pappas, G. J. Probabilistic data association for semantic SLAM &i&Robotics and Automation (ICRA), 2017 IEEE International Conference on, &/i&-1729.&/p&&p&[5]. Civera, J.; Davison, A. J. & Montiel, J. M. Inverse depth parametrization for monocular SLAM, &i&IEEE transactions on robotics, IEEE, &/i&2008&i&, 24&/i&, 932-945.&/p&&p&[6]. Engel, J.; Sturm, J. & Cremers, D. Semi-dense visual odometry for a monocular camera &i&Proceedings of the IEEE international conference on computer vision, &/i&-1456&/p&&p&[7]. 高翔, 张涛, 刘毅, 颜沁睿, 视觉SLAM十四讲:从理论与实践,电子工业出版社, 2017&/p&&p&[8]. Leutenegger, S.; Lynen, S.; Bosse, M.; Siegwart, R. & Furgale, P. Keyframe-based visual-inertial odometry using nonlinear optimization &i&INTERNATIONAL JOURNAL OF ROBOTICS RESEARCH, &/i&2015&i&, 34: &/i&314-334&/p&&p&[9]. Barfoot, T. State Estimation for Robotics: A Matrix Lie Group Approach, &i&Cambridge University Press, &/i&2017&/p&&p&[10]. &a href=&/?target=http%3A//blog.csdn.net/heyijia0327/article/details/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&SLAM中的marginalization 和 Schur complement&i class=&icon-external&&&/i&&/a& &/p&&p&[11]. &a href=&/?target=http%3A///luyb/p/6077478.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&DSO之光度标定 - 路游侠 - 博客园&i class=&icon-external&&&/i&&/a&&/p&
朋友,过去的时代对于我们 好比打着七重封印的密籍 你称为时代精神的那东西 它终归不过是过去的时代 反映在学究先生的精神里。 ——《浮士德》 他掘了坑,又挖深了,竟掉在自己所挖的阱裡。 ——《圣经 诗篇 7.15》DSO(Direct Sparse Odometry),是慕尼黑…
&p&没有卸腰,我是被领导逼着来答的,只为骗赞。&/p&&p&如果要评价一个slam算法,最直接的是看跑出来的map。&/p&&p&官方提供的数据集大家应该都跑了,但是答案里目前没人分享&b&官方外的数据测试,&/b&而一个算法的好坏,需要看它是否经得起不同数据集的考验。下面以此出发,倒叙记录一下:&/p&&ol&&li&数据测试和分析&/li&&li&cartographer配置与使用&/li&&li&cartographer有用的参考文献和代码核心结构&/li&&/ol&&p&&br&&/p&&p&即是在&b&粗略地&/b&回答:&/p&&ol&&li&cartographer能做到,不能做到什么,符合我的(老板的)需求吗?&/li&&li&激光雷达买不起,kinect很流行,怎么用非官方的传感器方案跑cartographer?&/li&&li&我关心how it works,但是那么多参考文献和代码,高亮在哪里?&/li&&/ol&&p&&i&小说明&/i& &i&:&b&所有的认识都停留在2017年6月,&/b&那之后的commits就没有再跟进了,所以可能会和官方当前内容&b&相当&/b&有出入&/i&&/p&&p&&i&---------------------------------&/i&&/p&&p&&br&&/p&&p&&br&&/p&&p&&b&Part1 :数据测试和简单分析&/b&&/p&&p&&b&测试1:某电厂局部&/b&&/p&&p&传感器配置:里程计,SICK激光雷达,imu&/p&&p&场景规模:500*100&/p&&img src=&/v2-b9abb27bcaf3_b.png& data-rawwidth=&1560& data-rawheight=&918& class=&origin_image zh-lightbox-thumb& width=&1560& data-original=&/v2-b9abb27bcaf3_r.png&&&p&&br&&/p&&p&(数据只跑了一小部分),该场景是某个电厂,规模非常大,所以激光雷达对环境的观测相当稀疏。对一个很粗的圆柱,在某一侧时只能采到很短很平的一段弧。对这样一个场景的建图,用Gmapping等(据测过的人说)里面的圆是建不出来的,然而,用Cartographer可以看到,里面的矩形,圆形,墙形状保持得很好,边缘也相当sharp,但图似乎渐渐有歪的趋势。&/p&&p&&br&&/p&&p&&b&测试2:&/b& &b&深圳梧桐岛内外圈&/b&&/p&&p&传感器配置: 里程计,SICK激光雷达,imu&/p&&p&场景:有很多树,玻璃墙, 中间是湖, 大约400*200m&/p&&img src=&/v2-a16ca1a42dcade29fcdcb4f06d4511ba_b.png& data-rawwidth=&1221& data-rawheight=&714& class=&origin_image zh-lightbox-thumb& width=&1221& data-original=&/v2-a16ca1a42dcade29fcdcb4f06d4511ba_r.png&&&p&&br&&/p&&img src=&/v2-dc090b759faa3c8f476a71a90c8a90ea_b.jpg& data-rawwidth=&1369& data-rawheight=&800& class=&origin_image zh-lightbox-thumb& width=&1369& data-original=&/v2-dc090b759faa3c8f476a71a90c8a90ea_r.jpg&&&p&&br&&/p&&img src=&/v2-ab6fcb35a0c_b.png& data-rawwidth=&1788& data-rawheight=&877& class=&origin_image zh-lightbox-thumb& width=&1788& data-original=&/v2-ab6fcb35a0c_r.png&&&p&&br&&/p&&img src=&/v2-4c410adc198c2bf46c07b59e6a67b915_b.png& data-rawwidth=&1658& data-rawheight=&916& class=&origin_image zh-lightbox-thumb& width=&1658& data-original=&/v2-4c410adc198c2bf46c07b59e6a67b915_r.png&&&p&&br&&/p&&p&第一、二张是用cartographer跑的,第三四张是公司的算法跑的。&/p&&p&那时候,我对cartographer的研究还处于走火入魔与水深火热之间,等着看完代码变成大神,这个心里过程一直持续到这个数据跑了二分之一时。 瞎了。辣鸡slam,毁我青春&/p&&p&明显地,回环失败了,线条也很差,而cartographer的论文主题还是loop,造成回环失败的原因可能有:&/p&&ul&&li&&b&没有调参 &/b&lua里需要调整些参数,比如ceres_scan_matcher的各种weight,最近官方出了一个&a href=&///?target=https%3A//google-cartographer-ros.readthedocs.io/en/latest/tuning.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&tuning文档&i class=&icon-external&&&/i&&/a&,表示:Tuning Cartographer is unfortunately really difficult。 (这个tuning文档至少17年6月的时候还没有,&b&写得很好&/b&,比我这答案有用多了)好吧,我们用的时候,根本没tuning。做过产品的人可能有所体会,调参那整容般的效果。&/li&&li&&b&环境不是目标应用场景 &/b&它自己论文说cartographer是一种&real-time&br&solution for indoor mapping&,这种户外较大型(一定动态的)环境,一开始算法就不是为此设计的,所有某些能力上显得欠缺。室内环境的结构化程度比户外好得多,即便有环可能也不会出现这样只能走一圈的超大环。所以,是数据的错,cartographer还是棒的。&/li&&li&&b&算法限制 &/b&角度的累计误差对这样的大环造成的影响是难以接受的,直接合不上。即便imu提供了较好的初值,甚至3d时还在后端设计优化imu的状态提高准确度,但环境太大了,对观测(点云)的利用和闭环算法对累计误差很重要。你可能会觉得,它既有submap,又有全局几乎遍历的查找loop,怎么还会偏到这种地步呢? submap主要是降低计算的复杂度,环境没有变小,对累计误差的消除帮助不大,毕竟一个submap的位置取决于之前的submap; 另外它在全局找loop,不存在什么策略,任何pair的match的分数足够高就加到graph里,检查不必要的匹配太多,可能也会增加引进错误loop的风险,而且它所有所有(前端后端)的match都是基于raw measurement的,信息足够冗余但是不够有效,鲁棒性不够。至于分支界定只是加速的,不影响效果。(这只是我自己的想法,懂的同学请分析一下它的loop算法)。有同学之前提到能不能纯视觉用cartographer,如果手持,不管2d3d都不能; 如果固定平地,效果跟其他开源比我也不知道优势在哪。&/li&&/ul&&p&希望大家也测评一下,尤其是那些kinect的同学,期待。&/p&&p&跑了一些数据,以及结合代码和论文,我们尝试整理一下cartographer的能力和限制&/p&&p&&br&&/p&&p&&b&能&/b&: &/p&&ul&&li&实现精度要求不高的室内SLAM,论文说5cm,有人评论说能3cm;&/li&&li&兼容多种传感器方案,可以激光雷达,相机;甚至能同时用;支持多trajectory似乎能有一些玩法。&/li&&li&一直在更新,实现得很好,有诚意,值得学习和支持。但看了之后,看其他开源的实现眼睛要瞎,建议不要最先看。&/li&&/ul&&p&&br&&/p&&p&&b&不能&/b&: (需要指正补充)&/p&&ul&&li&如果走丢了(定位失败),算法里似乎没有恢复的方法,不能全局定位,它写了个PerformGlobalLocalization,但是没看见使用;&/li&&li&如果环境动态一些,环境有玻璃等,算法里没作处理,定位精度还能行吗,它对scan的过滤就只用最短距离最长距离来判断;&/li&&li&在长走廊中,实际机器人在走,由于观测没有变化,因此定位不动,在缺乏里程计时,此时误差很大;&/li&&li&不用IMU,大环或者多环就基本废了,loop算法不太好使[17-08的版本在没有imu时会用odometry估计角度,不知道效果]&/li&&li&调参困难,参数也不少。精度虽然不低,但离工业产品要求差几厘米,工业中没法用&/li&&li&理论上结构整洁却单调,三十几年来slam里涌现的优秀想法和技巧,选取组合得稍微有点简单。&/li&&/ul&&p&在实际开发时结合一下别的思想也许能把它带到更广泛的场景中去。&/p&&p&&br&&/p&&p&&b&Part2:&/b& &b&配置Cartographer与使用&/b&&/p&&p&也不是什么教程,为刚接触cartographer的朋友简单说点。 主要参照&a href=&///?target=https%3A//google-cartographer-ros.readthedocs.io/en/latest/ros_api.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&官方configuration&i class=&icon-external&&&/i&&/a&和代码data.h,&br&sensor_bridge.cc, node.cc, node_constants.h等&/p&&ul&&li&cartographer需要的数据:Imu的linear_acceleration和angular_velocity; Odometry的当前时刻Pose; Rangefinder的&b&origin和ranges&/b&&/li&&li&关于Rangefinder:雷达相机等都行,origin是rangefinder在robot坐标系下的位置, ranges是robot坐标系下的点云(3维)。原始观测是&b&传感器坐标系&/b&下的,为了给cartographer使用,必须由几何关系转换到&b&robot三维欧式坐标系&/b&下(cartographer_ros为你做了,但是需要些配置数据)。 即便你的雷达是2d,你想做2d slam,给它的数据也必须是点云。&/li&&li&关于imu和里程计: 2d可以不要imu,3d必须要有imu; 里程计始终是可选的; 注意使用的传感器用的什么数据,比如imu没有直接用角度。&/li&&li&官方&b&2d&/b& demo的传感器配置:&br&imu+multi_echo_laser_scan(多回波雷达),2d只用了horizontal_laser_2d,垂直方向的没用&/li&&li&从cartographer_ros到cartographer:&br&cartographer_ros的lua文件是在配置平台, cartographer的lua文件是在配置算法(调参)。 用ros的lua配置使用什么传感器非常显然,可能会出现问题的是launch文件,怎么play数据,启动哪种node,配置static transform(这个似乎可以改对应的urdf?), remap topics等。 node_constants。h里有cartographer_ros需要的topics, 比如你用雷达就要把你雷达发布数据的topic(如果不是scan就要) remap成scan。值得说的是,是否使用imu是在cartographer而不是cartographer_ros里配置的。&/li&&/ul&&p&这么大个框架的cartographer,哪些才是需要关心(看,改)的?&/p&&p&如果只用2d可以砍掉mapping_3d和kalman_filter,只有3d用了kalman_filter(有几个小地方需要保留);如果不用correlative_scan_matcher也可以不管,默认的就是不使用,但是似乎使用会好些;官方对传感器的使用可能发挥得不够,你可以根据自己用的传感器去改前端的定位,甚至后端优化;有人为了快速,干脆不用它后端的spa优化,觉得它前端的精度就够了,于是把后端也砍了; 还有一些写了但是实际运行时没用,可能只是用来确定参数的函数,如果觉得看着累也可以先搁那。 真正可能需要看的代码不算多,但比起精简它,&b&扩展它&/b&才有意义。&/p&&p&&br&&/p&&p&&b&Part3:&/b& &b&论文和代码重点&/b&&/p&&p&主要参考文献: (主要是2d mapping相关,3d可能用到的比如ukf等没列)&/p&&ol&&li&submap: 随便找&a href=&///?target=http%3A//rmatik.uni-freiburg.de/teaching/ws15/mapping/pdf/slam10-gridmaps.pdf& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&occpancy grid map&i class=&icon-external&&&/i&&/a&的内容看看就能明白; 官方论文里公式中的clamp是把概率限制到min max里。&/li&&li&ceres_scan_match: 来自[5] a flexible&br&and scalabel SLAM system with full 3D motion estimation。&/li&&li&spa: 来自[2] Sparse pose&br&adjustment for 2D mapping 原作者也有实现,但是cartographer重写了,完全没用别人的。后端的大型稀疏graph的优化问题你懂的,自以为看懂了也。。。。。值得说的是cartographer加全局约束,是在所有的submap和所有的scan能组成的所有submap-scan pair里找好的match。 scan在不在这个submap里会影响约束的类型。更高一层是还要跨trajectory里找约束。&/li&&li&correlative_scan_match: 论文没怎么提,是Olson的[15] real-time correlative scan matching,能为ceres scan match提供一个还行的初值。&/li&&/ol&&p&可以看到,跟cartographer实现内容相关的文件很少,没有数据关联,计算协方差,特征提取,粒子滤波,重定位,动态环境,先验信息等等,都不需要。参考文献有一些相关的内容,但是没有用到cartographer里。&/p&&p&&br&&/p&&p&主要代码:(2d 相关)&/p&&ol&&li&map_builder是最顶层,cartographer_ros用cartographer就是通过这个。&/li&&li&global_trajectory_builder: 使用了全库核心,数据给到&b&local_trajectory_builder,&/b& 结果再给&b&sparse_pose_graph&/b&(local是相对于global的,是指没有全局优化,并不是说robot坐标系; )&/li&&li&submaps 可以看到怎么管理子图,子图的position和robot pose的关系 (submap的local pose指的submap在世界下的位置)&/li&&li&ceres_scan_matcher和几个使用的functor可以看到怎么在做scan to map match。 它的优化除了论文上的损失函数,还加了对初值的约束;计算residual查找grid中的值时用了插值ha。&/li&&li&probability_grid和range_data_inserter写了grid map是在怎么迭代更新的,写成查表很快。&/li&&/ol&&p&3d和2d在同一个框架下,差别不大,主要是: 3d前端用了ukf,代码中写了参考文献的; 另外在优化时,3d多了些优化,包括优化imu的重力方向。3d没有那么多拧巴的维度转换,不需要水平化,应该会看得通畅些。&/p&&p&---------------------------------------------&/p&&p&暂时想到了这些,我扫了一眼官方最新的,在imu和里程计上改动有点大,local_trajectory_builder改得多,多了个pose_extropolator,ros那边也变得多。对这些,我选择闭上双眼。年轻人还是要好好学,对,就是那帮大三大四的。&/p&&p&&br&&/p&&p&点题:这个回答写得很不够,但是某种程度上能为新了解cartographer的人提供帮助,如果你能感受到这份诚意,请不要大意地点赞,送我上天啊啊!&/p&&p&另外,大家很关注我司的算法,呵呵,此篇只是为了回答&b&Cartographer&/b&的问题,所以你懂的。对比图是为了硬广一波,欢迎感兴趣的大家来我司交流,加入我司,咱们一起搞事情!&/p&
没有卸腰,我是被领导逼着来答的,只为骗赞。如果要评价一个slam算法,最直接的是看跑出来的map。官方提供的数据集大家应该都跑了,但是答案里目前没人分享官方外的数据测试,而一个算法的好坏,需要看它是否经得起不同数据集的考验。下面以此出发,倒叙记…
&p&利益相关回复,作为科赛网 &a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&&i class=&icon-external&&&/i&&/a& 的创始人,我也来谈谈这次携程举办的算法比赛的历程,作为项目复盘和教训总结。目前携程、科赛、植物大神的Baseline团队、10Data已经找到了解决方案,达到了各方满意的结果。&/p&&p&阿里、腾讯、京东、滴滴、今日头条最近都陆续开始办算法赛事,相比之下,携程赛事在竞赛圈比较下来确实做得还不够好,携程和科赛的准备和投入都不够,这次房型预测的比赛又出现了协调、组织、沟通的问题,我作为科赛网的创始人首先是要反省的。&/p&&p&回到本次又出现了问题的房型预测的赛题中来,就像植物大神所说的,确实整个过程出现了很多问题,过程也很复杂,我这里复盘一遍,防止以后再出现类似的问题。&/p&&p&Data Leakage的问题确实很常见,会影响赛事的公平性以及算法的可复用性,对于选手和主办方都是不好的,但又很难完全避免,经常参加比赛的人都知道这一点,科赛当然也碰到过很多次。Leakage问题发生,科赛作为竞赛平台的承办方,主要是和主办方共同讨论,由主办方决策如何处理。&/p&&p&科赛过去总结出来的办法,主要是办一个现场答辩,让排行榜成绩靠前的选手们通过答辩来呈现算法的思路和价值(这个办法不一定最好,相比重新清洗数据再办一场比赛,或者把所有人的leak信息手动去掉,成本会低一些,也能够创造一个相互交流学习的环境)。选手们在决赛现场,也都会承认有leak现象的存在,会开诚布公进行讨论,但更多是讨论思路、讨论方法、探究应用价值,评选最终名次也是会综合排行榜的成绩,和答辩的表现,Leakage对于赛事的不利影响也就相对可控。&/p&&p&但是携程的系列比赛,因为缺少预算、缺少人手,刚好都没有安排答辩,就直接按照排行榜的前三名,把奖项给在网站和社区都公布了出来了。&/p&&p&本来以为这个房型预测的比赛圆满结束了,这,没想此后又发生了一系列的意料之外。&/p&&p&科赛不仅是个竞赛平台,也在努力成为一个数据技术社区,就希望借鉴Kaggle、Github的开源精神,把选手的优秀作品发布到科赛今年3月份上线的K-Lab产品上(类似Kaggle的Kernel功能),帮助更多的社区用户学习技术。可这次房型预测比赛的第一名和第二名都公布了自己参赛的算法代码,第三名作为是一家公司(10Data),需要保护自身知识产权,就没有公开自己的代码用于交流。&/p&&p&成绩公布后的一周,科赛的邮箱接收到了第三名的投诉,表示他们研究了第一、第二名的代码后,认为存在data leakage,要求重新评定比赛的成绩,因为他们为了确保算法的商业实际价值,没有使用data leakage。&/p&&p&这个data leak的特征确实存在,可是在比赛的选手QQ群里面,选手和携程的数据分析师对此已经展开过很充分的讨论,选手询问是否可以在赛事中使用这个data leak的特征信息,得到了“不建议使用,但是也不反对”的回应,但是第三名的团队也确实刚好没有看到这个讨论,所以认为这个局部的声明是缺少效力。比赛QQ群讨论,往往在半夜也很激烈,这段对话则发生在凌晨一点(科赛的工作人员当时也没有看到,没有把这个很重要的信息置顶在公告区)。&/p&&p&所以第三名团队提出要重新评定成绩,因为携程制定的比赛规则中,确实有一条叫做““参赛者禁止在指定考核技术能力的范围外利用规则漏洞或技术漏洞等不良途径提高成绩排名,经发现将取消比赛成绩并严肃处理”,虽然Data Leakage是不是属于这个规则的适用范围,本身是有争议的,加上本次赛事确实在QQ群官方表示了不反对这个Leak信息,这个争议就更大了。&/p&&p&既然携程的出题者已经说了“不反对使用Leak信息”,那这个成绩作为携程主办方来说就要认可了。但是第三名团队认为允许Leak使用的做法本身是不够专业的、不公平,表示需要携程的技术领导妥善处理这个问题,要给出一个明确的处理方案。&/p&&p&领导考虑到携程确实在赛事中得到了比较好的算法结果,产生了实质的经济效益,也希望携程云海系列赛事能够持续举办下去,不希望携程赛事的口碑坏掉,也在努力和第三名团队进行沟通。最后携程的领导拍板,拿出的解决方案是,首先认可前两名有Leakage的团队的成绩,同时,在更新数据后再组织一场附加赛,定向邀请此前排名靠前的团队,提供额外的两万元奖金,额外的两周比赛时间,要求是不再使用Leakage信息。第三名团队对此安排,最终也表示了认可。&/p&&p&这个附加赛到了结束的时候,植物大神的团队又是第一,第三名的团队又是第三名。&/p&&p&于是情况变成了这样:&/p&&ul&&li&一个很复杂的房型预测的题目,本身容易产生leak现象。&/li&&li&这个比赛没有通过答辩来规避Leakage的不利影响,直接公布了前三名的最终成绩和奖项。&/li&&li&一个公司参赛团队是第三名,自己很注意不去使用leak信息。&/li&&li&前两名团队的代码在科赛社区开源共享了,而且前两名使用到了leak信息,刚好被第三名团队看到了,所以要提出对于Leakage现象的公平性申诉。&/li&&li&这个leak信息在QQ群的讨论并且被出题方认可使用,而第三名团队又没有看到这个发生在凌晨的聊天记录。&/li&&li&这个赛题给携程带来了不错的效益,相关技术负责人希望可以鼓励选手不用leakage再做一次附加赛,探索更大的商业价值。&/li&&li&这次附加赛的第一名,又是第一次比赛的第一名,第三名又是第三名。&/li&&li&第一名选取的特征不小心包含了很难发现的Leak,而去掉这个Leak的特征后,第一名还是性能表现的第一名。&/li&&li&而主办方在附加赛的规则中,又着重强调了不允许使用leak信息,而这个leak信息又是很隐蔽的,很难直接规避。&/li&&li&附加赛的第二名的代码不能够复现,所以如果取消有Leak的情况的成绩,那第三名就可以成为第一名,而第三名的代码中又没有包含Leak信息。&/li&&li&携程的领导认为既然强调了附加赛不能够使用Leak,那就要严格执行,就有了后面的事故,携程认为植物大神的成绩是无效的。&/li&&li&出现leak常常不是主观能够避免的

我要回帖

更多关于 团队训练论文 的文章

 

随机推荐