由于本人在网上查找SVO代码博客,发现大多都是比较简略大局化的,对新手不友好,因此特开此特记录小白的学习历程。初次学习,希望大家能进行讨论,指出我的错误。
该系列博客会以新手视角以下顺序进行解读,尽量往细了剖析(前几个应该比较简单过得比较快,后面的需要的算法解读篇幅将更大)。然后在最后进行整合介绍,并搭配较为前沿的论文食用,探讨SVO的改进。
大致阅读按如下顺序进行(参考了一个github的建议),对于新手读代码真的很需要顺序,前期我就因为不知道该怎么入手而感到崩溃。。。
1,global.h
2,config.h config.cpp
3,point.h point.cpp
4,frame.h frame.cpp
5,feature.h
6,map.h map.cpp
7,feature_alignment.h feature_alignment.cpp
8,matcher.h matcher.cpp
9,pose_optimizer.h pose_optimizer.cpp
10,reprojector.h reprojector.cpp
11,sparse_img_align.h sparse_img_align.cpp
12,depth_filter.h depth_filter.cpp
13,initialization.h initialization.cpp
14,bundle_adjustment.h bundle_adjustment.cpp
15,frame_handler_base.h frame_handler_base.cpp
16,frame_handler_mono.h frame_handler_mono.cpp
1.global.h
准备工作
这博客本着面向C++基础稍微薄弱的同学(也包括我自己,嘿嘿),因此在这里要看懂第一个代码文件首先要了解宏定义。
#ifndef 作用:防止头文件的重复包含和编译,即防止递归调用。
此语句后面的第一行定义了对应宏,那么在接下来的语句中如果再次出现这个宏的定义则退出,已达到不重复定义的目的。详情可见《21天学通C++》(以后简称书)274页。它和#endif配套使用。
define就是常见的宏的定义,对于我们来说知道define A B代表着代码中将全部将B来替换A,我觉得目前就可以啦。
局部代码分析
/*
很标准的宏定义模式,使用vikit库的变量均用eigen中的向量表示,这里有一个疑问哈(为何define后面有两个参数)
*/
#ifndef RPG_SVO_VIKIT_IS_VECTOR_SPECIALIZED
#define RPG_SVO_VIKIT_IS_VECTOR_SPECIALIZED
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector3d)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector2d)
#endif
/*
当使用到ROS,这里也涉及到了这部分宏的变量改写,基本上就是一些编译输出等
*/
#ifdef SVO_USE_ROS
#include <ros/console.h>
#define SVO_DEBUG_STREAM(x) ROS_DEBUG_STREAM(x)
#define SVO_INFO_STREAM(x) ROS_INFO_STREAM(x)
#define SVO_WARN_STREAM(x) ROS_WARN_STREAM(x)
#define SVO_WARN_STREAM_THROTTLE(rate, x) ROS_WARN_STREAM_THROTTLE(rate, x)
#define SVO_ERROR_STREAM(x) ROS_ERROR_STREAM(x)
#else
#define SVO_INFO_STREAM(x) std::cerr<<"\033[0;0m[INFO] "<<x<<"\033[0;0m"<<std::endl;
#ifdef SVO_DEBUG_OUTPUT
#define SVO_DEBUG_STREAM(x) SVO_INFO_STREAM(x)
#else
#define SVO_DEBUG_STREAM(x)
#endif
#define SVO_WARN_STREAM(x) std::cerr<<"\033[0;33m[WARN] "<<x<<"\033[0;0m"<<std::endl;
#define SVO_ERROR_STREAM(x) std::cerr<<"\033[1;31m[ERROR] "<<x<<"\033[0;0m"<<std::endl;
#include <chrono> // Adapted from rosconsole. Copyright (c) 2008, Willow Garage, Inc.
#define SVO_WARN_STREAM_THROTTLE(rate, x) \
do { \
static double __log_stream_throttle__last_hit__ = 0.0; \
std::chrono::time_point<std::chrono::system_clock> __log_stream_throttle__now__ = \
std::chrono::system_clock::now(); \
if (__log_stream_throttle__last_hit__ + rate <= \
std::chrono::duration_cast<std::chrono::seconds>( \
__log_stream_throttle__now__.time_since_epoch()).count()) { \
__log_stream_throttle__last_hit__ = \
std::chrono::duration_cast<std::chrono::seconds>( \
__log_stream_throttle__now__.time_since_epoch()).count(); \
SVO_WARN_STREAM(x); \
} \
} while(0)
#endif
小结分析
第一块Global.h还是通过宏定义的方式配置了一些文件,我觉得基本上看一下就可以,对于整体框架了解不算是重点,需要了解一下宏的概念,命名空间的简单概念等。