视觉SLAM十四讲——第九讲实践:设计前端
程序员文章站
2024-03-24 23:48:34
...
@ 《视觉SLAM十四讲》知识点与习题
《视觉SLAM十四讲》第九讲知识点整理+习题
正在学习SLAM相关知识,将一些关键点及时记录下来。
知识点整理
本章很有趣,将前面的知识点都联系在了一起,而且还会通过一系列方法解决诸如:相机运动过快、图像模糊、误匹配等实际问题
- 单目视觉相对复杂,RGB-D最为简单,没有初始化,也没有尺度问题
-
数据单元
- 帧: 将认为重要的帧保存起来,并认为相机轨迹可以用这些关键帧来描述,多基于工程经验
- 路标:图像中的特征点。在相机运动后,还能估计路标的3D位置。通常,将路标点放在一个地图当中,并将新来的帧与地图中的路标点进行匹配,估计相机位姿
- 视觉里程计:Frame, Camera, MapPoint, Map以及Config
代码
- Camera类:注意,根据书本P60页的写法,T_c_w表示世界坐标系到相机坐标系间的变换,即世界坐标系在相机坐标系下的表示,按照顺序记也许比较好记:c在w前,即从相机坐标系变换到世界坐标系。p_c=T_c_w p_w,表示当前点P在相机坐标系中的坐标=(世界坐标系在相机坐标系下的表示)*(P在世界坐标系中的坐标)。每个函数的注解在下方代码中。注意:相机和世界坐标系之间的变换涉及的是相机位姿,而相机坐标系和像素坐标系之间的变换涉及的是相机内参
//输入为P点在世界坐标系下的表示,并且给出相机坐标系在世界坐标系下的位姿,输出为当前变换在相机坐标系下的表示 Vector3d Camera::world2camera ( const Vector3d& p_w, const SE3& T_c_w ) { return T_c_w*p_w; } //输入为P点在相机坐标系下的表示,并且给出相机坐标系在世界坐标系下的位姿,输出为当前变换在世界坐标系下的表示 Vector3d Camera::camera2world ( const Vector3d& p_c, const SE3& T_c_w ) { return T_c_w.inverse() *p_c; } //输入为P点在相机坐标系下的表示,输出为其在像素坐标系中的表示 Vector2d Camera::camera2pixel ( const Vector3d& p_c ) { return Vector2d ( fx_ * p_c ( 0,0 ) / p_c ( 2,0 ) + cx_, fy_ * p_c ( 1,0 ) / p_c ( 2,0 ) + cy_ ); } //输入为P点在像素坐标系下的表示,输出为其在相机坐标系中的表示 Vector3d Camera::pixel2camera ( const Vector2d& p_p, double depth ) { return Vector3d ( ( p_p ( 0,0 )-cx_ ) *depth/fx_, ( p_p ( 1,0 )-cy_ ) *depth/fy_, depth ); } //输入输出上述几个函数中已经介绍过,变换过程为:先得出P点在相机坐标系下的表示,然后再变换到像素坐标系中即可 Vector2d Camera::world2pixel ( const Vector3d& p_w, const SE3& T_c_w ) { return camera2pixel ( world2camera ( p_w, T_c_w ) ); } //输入输出上述几个函数中已经介绍过,变换过程为:先得出P点在相机坐标系下的表示,然后再变换到世界坐标系中即可 Vector3d Camera::pixel2world ( const Vector2d& p_p, const SE3& T_c_w, double depth ) { return camera2world ( pixel2camera ( p_p, depth ), T_c_w ); }
-
Frame类:定义了ID,时间戳,位姿,相机和图像(color和depth)
在帧类中需要注意的点为- 设置了一个静态变量,与类存活时间一致,从而可以保证先后加入的帧的id按序增加
Frame::Ptr Frame::createFrame() { static long factory_id = 0; return Frame::Ptr( new Frame(factory_id++) ); }
- 在findDepth(…)函数中,有一个之前一直强调的点。即对于像素位置x,y处的深度值,应该是访问depth图中第y行的第x个坐标的值
int x = cvRound(kp.pt.x); int y = cvRound(kp.pt.y); ushort d = depth_.ptr<ushort>(y)[x];
- MapPoint类:有ID,在世界坐标系中的位置,可视化方向的法向量,匹配描述符,被观察的次数和被匹配的次数
- Map类:Map类用于管理关键帧和地图点,所以在该类中具有上述两个类类型的unoreded_map的成员变量。每次插入对应值时,只需要首先判断是否已在Map中,若不在,则插入。因为每个帧/地图点的id是唯一的,所以以id为key值,对应的具体的帧/地图点为value