1.在代码中分析VINS---图解feature_tracker.cpp

该文件的主要函数为void FeatureTracker::readImage(const cv::Mat &_img, double _cur_time)
该文件的中文注释代码以放到我的github上,代码结合我下面画的图更容易理解,欢迎大家star!,本人也是vi-slam新手,分析不到位的地方,欢迎大家批评指正!

1. 第一帧图像进来

当第一帧图像进来时,执行函数` cv::goodFeaturesToTrack(forw_img, n_pts, MAX_CNT - forw_pts.size(), 0.01, MIN_DIST, mask),其中forw_img表示当前图像(这里表示第一帧图像),n_pts表示存储的角点坐标集合,MAX_CNT - forw_pts.size() 表示要检测的角点个数,在这里为MAX_CNT;下图表示提取的150个角点,存放到n_pts

2.角点集合处理

在步骤1里检测到角点(n_pts)后,通过函数addPoints()是将n_pts中的角点放到forw_pts中,ids表示每个角点的编号,track_cnt表示每个角点的跟踪次数,addPoints()是将检测到的新的角点ID初始化和跟踪次数初始化如下图所示:

3.迭代处理

    prev_img = cur_img;//在第一帧处理中还是等于当前帧forw_img
    prev_pts = cur_pts;//在第一帧中不做处理
    prev_un_pts = cur_un_pts;//在第一帧中不做处理
    cur_img = forw_img; //将当前帧赋值给上一帧
    cur_pts = forw_pts;//如下图所示

4.第二帧图像进来

第二帧图像forw_img与上一帧图像cur_img进行光流跟踪cv::calcOpticalFlowPyrLK(cur_img, forw_img, cur_pts, forw_pts, status, err, cv::Size(21, 21), 3); cur_pts表示步骤3中存储的角点,forw_img表示在当前图像中跟踪成功的点的集合,status表示 cur_ptsforw_pts中对应点对是否跟踪成功。如下图所示:

光流跟踪结束后,还要判断跟踪成功的角点是否都在图像内,源码:

for (int i = 0; i < int(forw_pts.size()); i++)
            if (status[i] && !inBorder(forw_pts[i]))
                status[i] = 0;

如图所示:

5.对跟踪成功的点及其对应的id和track_cnt进行重组

对步骤5中的点根据状态status进行重组,将staus中为1的对应点对在原点对中保存下来,为0的对应点对去除掉,对应代码:

        //将光流跟踪后的点的集合,根据跟踪的状态(status)进行重组
        reduceVector(prev_pts, status);
        reduceVector(cur_pts, status);
        reduceVector(forw_pts, status);

        //将光流跟踪后的点的id和跟踪次数,根据跟踪的状态(status)进行重组
        reduceVector(ids, status);
        reduceVector(cur_un_pts, status);
        reduceVector(track_cnt, status);

如图所示:

因为在第二张图像中成功跟踪了四个点(p1,p6,p8,p150),所以要对该点对应的跟踪次数(track_cnt)进行加1操作,代码:

  //将track_cnt中的每个数进行加一处理,代表又跟踪了一次
    for (auto &n : track_cnt)
        n++;

6.去除光流跟踪错误的点对

该部分用到的函数主要是rejectWithF();借助基础矩阵计算函数cv::findFundamentalMat(un_cur_pts, un_forw_pts, cv::FM_RANSAC, F_THRESHOLD, 0.99, status);来去除去匹配点,然后在根据状态量staus对匹配的点对,与步骤5进行相似的操作。

7.设置角点检测函数的mask

该部分用到的函数主要是setMask();,该函数主要有两个作用,
1.对跟踪到的特征点对依据跟踪次数进行从多到少的排序,并放到原集合中,对应代码:

 // prefer to keep features that are tracked for long time
    //保存长时间跟踪到的特征点
    //vector<pair<某一点跟踪次数,pair<某一点,某一点的id>>> cnt_pts_id
    vector<pair<int, pair<cv::Point2f, int>>> cnt_pts_id;

    for (unsigned int i = 0; i < forw_pts.size(); i++)
        cnt_pts_id.push_back(make_pair(track_cnt[i], make_pair(forw_pts[i], ids[i])));

   //对给定区间的所有元素进行排序,按照点的跟踪次数,从多到少进行排序
    sort(cnt_pts_id.begin(), cnt_pts_id.end(), [](const pair<int, pair<cv::Point2f, int>> &a, const pair<int, pair<cv::Point2f, int>> &b)
         {
            //降序排列
            return a.first > b.first;
         });

    forw_pts.clear();
    ids.clear();
    track_cnt.clear();
    for (auto &it : cnt_pts_id)
    {
        if (mask.at<uchar>(it.second.first) == 255) //检测新建的mask在该点是否为255
        {
            //将跟踪到的点按照跟踪次数重新排列,并返回到forw_pts,ids,track_cnt
            forw_pts.push_back(it.second.first);
            ids.push_back(it.second.second);
            track_cnt.push_back(it.first);
            //图片,点,半径,颜色为0表示在角点检测在该点不起作用,粗细(-1)表示填充
            cv::circle(mask, it.second.first, MIN_DIST, 0, -1);
        }
    }

2.在已跟踪到角点的位置上,将mask对应位置上设为0,意为在cv::goodFeaturesToTrack(forw_img, n_pts, MAX_CNT - forw_pts.size(), 0.01, MIN_DIST, mask);进行操作时在该点不再重复进行角点检测,这样可以使角点分布更加均匀。

8返回步骤2进行循环处理

再一次进行角点检测,只不过这次角点检测的角点个数会改变,变为MAX_CNT - forw_pts.size()

9.畸变矫正

从第二张图像输入后每进行一次循环,最后还需要对匹配的特征点对进行畸变矫正,主要函数为undistortedPoints();

`

全部评论

相关推荐

投递拼多多等公司10个岗位
点赞 评论 收藏
转发
点赞 2 评论
分享
牛客网
牛客企业服务