VINS-MONO源码学习(二):状态估计器流程processImage

在上一篇文章的预积分完成之后,VINS-MONO执行了estimator::processImage这个函数,实现了视觉与IMU的初始化以及非线性优化的紧耦合,本篇先记录一下这个函数的流程,初始化和非线性优化的内容较多,会在后面写。
1、首先搞清楚这个函数的输入image是个什么东西:
estimator.processImage(image, img_msg->header);
measurement是一组观测(一帧图像和若干IMU数据),数据类型是std::pair<std::vector<sensor_msgs::ImuConstPtr>, sensor_msgs::PointCloudConstPtr>,这pair的一项就是imu_msg,第二项就是img_msg。
传到processImage的参数Image的生成过程如下,img_msg是指向sensor_msgs/PointCloud的指针,PointCloud消息中包括了点云的3D坐标和对应点的一些属性channels

geometry_msgs/Point32[] points
ChannelFloat32[] channels

里面的内容可以在feature_tracker_node.cpp的img_callback中找到,可见,channels中存的是对应3D点的id、图像中的u坐标和v坐标。

feature_points->points.push_back(p);
id_of_point.values.push_back(p_id * NUM_OF_CAM + i);
u_of_point.values.push_back(cur_pts[j].x);
v_of_point.values.push_back(cur_pts[j].y);

feature_points->channels.push_back(id_of_point);
feature_points->channels.push_back(u_of_point);
feature_points->channels.push_back(v_of_point);

这样看来下面代码中的v就是点云的索引(虽说加0.5是为了四舍五入,但我觉得这些量都是整型,不知道会不会出现需要四舍五入的情况)。所以image就是一帧图像中的特征点的集合。

map<int, vector<pair<int, Vector3d>>> image;
for (unsigned int i = 0; i < img_msg->points.size(); i++)
{
    int v = img_msg->channels[0].values[i] + 0.5;
    int feature_id = v / NUM_OF_CAM;
    int camera_id = v % NUM_OF_CAM;
    double x = img_msg->points[i].x;
    double y = img_msg->points[i].y;
    double z = img_msg->points[i].z;
    ROS_ASSERT(z == 1);
    image[feature_id].emplace_back(camera_id, Vector3d(x, y, z));
}

2、在开始看processImage的代码之前,首先需要弄清feature_manager类。
在这里插入图片描述
FeatureManager类含有成员变量list< FeaturePerId > feature,是滑窗中的所有路标点;列表中的每个路标点会在多个frame中出现 ,按照frame分组组成vector< FeaturePerFrame > feature_per_frame;feature_per_frame中存放了每个路标点在一张图像中的信息。
在FeatureManager::addFeatureCheckParallax函数中,把图像特征点放入list< FeaturePerId > feature中。
对于一帧中的每个特征点,建一个feature_per_frame,如果这个特征点中,与目前的滑窗中已有的特征点相同的数量小于20,就认为这是一个关键帧,如果大于20,则计算视差来判断倒数第二帧是不是关键帧(来了最新一帧之后,才把前一帧和这两帧之间的IMU数据合并起来作为一组数据,因此现在判断的是倒数第二帧)。计算倒数第二帧和倒数第三帧的视差:这里的视差相同的特征点在这两帧图像中的像素距离(坐标差平方之和开方)。滑窗中所有的特征点的平均视差如果大于阈值就认为这个倒数第二帧是关键帧。
判断关键帧之后,创建ImageFrame对象,把图像、时间戳、预积分的值存进去,然后把所有的产生的imageFrame都存到名为all_image_frame的map中。重新为预积分指针tmp_pre_integration分配空间(重新预积分)。
3、标定外参:如果需要标定外参(相机和IMU之间的位移和旋转),调用CalibrationExRotation()函数进行标定。
4、初始化:
当还没进行初始化,并且有足够的帧填满滑窗,并且具有外参,并且当前的帧的时间戳-初始时间戳>0.1,则开始初始化。初始化分为两步:纯视觉的sfm、视觉惯导联合,这些内容在下一篇文章中介绍Estimator::initialStructure():

result = initialStructure();
initial_timestamp = header.stamp.toSec();

在这里插入图片描述
如果初始化成功则进行非线性优化,否则执行滑窗操作。非线性优化solveOdometry和滑窗操作slideWindow以后再说,挖个坑。

if(result)
            {
                solver_flag = NON_LINEAR;
                solveOdometry();
                slideWindow();
                f_manager.removeFailures();
                ROS_INFO("Initialization finish!");
                last_R = Rs[WINDOW_SIZE];
                last_P = Ps[WINDOW_SIZE];
                last_R0 = Rs[0];
                last_P0 = Ps[0];
                
            }
            else
                slideWindow();
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1) 二值图像: 一幅二值图像的二维矩阵仅由0、1两个值构成,“0”代表黑色,“1”代白色。由于每一像素(矩阵中每一元素)取值仅有0、1两种可能,所以计算机中二值图像的数据类型通常为1个二进制位。二值图像通常用于文字、线条图的扫描识别(OCR)和掩膜图像的存储。 2) 灰度图像: 灰度图像矩阵元素的取值范围通常为[0,255]。因此其数据类型一般为8位无符号整数的(int8),这就是人们经常提到的256灰度图像。“0”表示纯黑色,“255”表示纯白色,中间的数字从小到大表示由黑到白的过渡色。在某些软件中,灰度图像也可以用双精度数据类型(double)表示,像素的值域为[0,1],0代表黑色,1代表白色,0到1之间的小数表示不同的灰度等级。二值图像可以看成是灰度图像的一个特例。 3) 索引图像: 索引图像的文件结构比较复杂,除了存放图像的二维矩阵外,还包括一个称之为颜色索引矩阵MAP的二维数组。MAP的大小由存放图像的矩阵元素值域决定,如矩阵元素值域为[0,255],则MAP矩阵的大小为256Ⅹ3,用MAP=[RGB]表示。MAP中每一行的三个元素分别指定该行对应颜色的红、绿、蓝单色值,MAP中每一行对应图像矩阵像素的一个灰度值,如某一像素的灰度值为64,则该像素就与MAP中的第64行建立了映射关系,该像素在屏幕上的实际颜色由第64行的[RGB]组合决定。也就是说,图像在屏幕上显示时,每一像素的颜色由存放在矩阵中该像素的灰度值作为索引通过检索颜色索引矩阵MAP得到。索引图像的数据类型一般为8位无符号整形(int8),相应索引矩阵MAP的大小为256Ⅹ3,因此一般索引图像只能同时显示256种颜色,但通过改变索引矩阵,颜色的类型可以调整。索引图像的数据类型也可采用双精度浮点型(double)。索引图像一般用于存放色彩要求比较简单的图像,如Windows中色彩构成比较简单的壁纸多采用索引图像存放,如果图像的色彩比较复杂,就要用到RGB真彩色图像。 4) RGB彩色图像: RGB图像与索引图像一样都可以用来表示彩色图像。与索引图像一样,它分别用红(R)、绿(G)、蓝(B)三原色的组合来表示每个像素的颜色。但与索引图像不同的是,RGB图像每一个像素的颜色值(由RGB三原色表示)直接存放在图像矩阵中,由于每一像素的颜色需由R、G、B三个分量来表示,M、N分别表示图像的行列数,三个M x N的二维矩阵分别表示各个像素的R、G、B三个颜色分量。RGB图像的数据类型一般为8位无符号整形,通常用于表示和存放真彩色图像,当然也可以存放灰度图像。 4.图像数字化 通过取样和量化过程将一个以自然形式存在的图像变换为适合计算机处理的数字形式。图像在计算机内部被表示为一个数字矩阵,矩阵中每一元素称为像素。图像数字化需要专门的设备,常见的有各种电子的和光学的扫描设备,还有机电扫描设备和手工操作的数字化仪。图像编码。 对图像信息编码,以满足传输和存储的要求。编码能压缩图像的信息量,但图像质量几乎不变。为此,可以采用模拟处理技术,在通过模-数转换得到编码,不过多数是采用数字编码技术。编码方法有对图像逐点进行加工的方法,也有对图像施加某种变换或基于区域、特征进行编码的方法。脉码调制、微分脉码调制、预测码和各种变换都是常用的编码技术。 5.图像压缩 由数字化得到的一幅图像的数据量十分巨大,一幅典型的数字图像通常由500×500或1000×1000个像素组成。如果是动态图像,是其数据量更大。因此图像压缩对于图像的存储和传输都十分必要。 有两类压缩算法,即不失真的方法和近似的方法。最常用的不失真压缩取空间或时间上相邻像素值的差,再进行编码。游程码就是这类压缩码的例子。近似压缩算法大都采用图像交换的途径,例如对图像进行快速傅里叶变换或离散的余弦变换。著名的、已作为图像压缩国际标准的JPEG和MPEG均属于近似压缩算法。前者用于静态图像,后者用于动态图像。它们已由芯片实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值