vins前端


参考链接:https://blog.csdn.net/qq_41839222/article/details/86030962
参考链接:https://blog.csdn.net/try_again_later/article/details/104847052
二位博主写的太好了 感谢博主 ~~~O(∩_∩)O哈哈~

理论分析

这部分主要说一下视觉跟踪模块(feature_trackers),先说一下涉及到的具体内容:

  • 对于每一幅新图像,KLT稀疏光流算法对现有特征进行跟踪;
  • 检测新的角点特征以保证每个图像特征的最小数目(100-300)
  • 通过设置两个相邻特征之间像素的最小间隔来执行均匀的特征分布;
  • 利用基本矩阵模型的RANSAC算法进行外点剔除;
  • 对特征点进行去畸变矫正,然后投影到一个单位球面上(对于cata-fisheye camera)。
  • 关键帧选取
    • 当前帧相对最近的关键帧的特征平均视差大于一个阈值就为关键帧(因为视差可以根据平移和旋转共同得到,而纯旋转则导致不能三角化成功,所以这一步需要IMU预积分进行补偿)
    • 当前帧跟踪到的特征点数量小于阈值视为关键帧;

部分理论说明

这里补充一下理论部分的:对特征点进行去畸变矫正,然后投影到一个单位球面上(对于cata-fisheye camera)

m_camera->liftProjective(Eigen::Vector2d(cur_pts[i].x, cur_pts[i].y), tmp_p);

   
   
  • 1

可以根据不同的相机模型将二维坐标转换到三维坐标:
对于CATA(卡特鱼眼相机)将像素坐标投影到单位圆内,这里涉及了鱼眼相机模型
而对于PINHOLE(针孔相机)将像素坐标直接转换到归一化平面(z=1)并采用逆畸变模型(k1,k2,p1,p2)去畸变等。

节点在启动时会先读取相机内参,根据config_file文件中model_type的值决定采用何种相机模型,并创建相应模型的对象指针,读取在该模型下需要的参数。他们之间的调用顺序:
readIntrinsicParameter ------> generateCameraFromYamlFile -----> CameraPtr

for (int i = 0; i < NUM_OF_CAM; i++) 
        trackerData[i].readIntrinsicParameter(CAM_NAMES[i]);//读取相机内参,保存到CAM_NAMES[i],如何获取相机的内呢???

void FeatureTracker::readIntrinsicParameter(const string &calib_file)
{
ROS_INFO(“reading paramerter of camera %s”, calib_file.c_str());
m_camera = CameraFactory::instance()->generateCameraFromYamlFile(calib_file);
}

CameraPtr
CameraFactory::generateCameraFromYamlFile(const std::string& filename)
{
cv::FileStorage fs(filename, cv::FileStorage::READ);
if (!fs.isOpened())
{
return CameraPtr();
}
Camera::ModelType modelType = Camera::MEI;
if (!fs[“model_type”].isNone())
{
std::string sModelType;
fs[“model_type”] >> sModelType;
if (boost::iequals(sModelType, “kannala_brandt”))
{
modelType = Camera::KANNALA_BRANDT;
}
else if (boost::iequals(sModelType, “mei”))
{
modelType = Camera::MEI;
}
else if (boost::iequals(sModelType, “scaramuzza”))
{
modelType = Camera::SCARAMUZZA;
}
else if (boost::iequals(sModelType, “pinhole”))
{
modelType = Camera::PINHOLE;
}
else
{
std::cerr << "# ERROR: Unknown camera model: " << sModelType << std::endl;
return CameraPtr();
}
}
switch (modelType)
{
case Camera::KANNALA_BRANDT:
{
EquidistantCameraPtr camera(new EquidistantCamera);
EquidistantCamera::Parameters params = camera->getParameters();
params.readFromYamlFile(filename);
camera->setParameters(params);
return camera;
}
case Camera::PINHOLE:
{
PinholeCameraPtr camera(new PinholeCamera);
PinholeCamera::Parameters params = camera->getParameters();
params.readFromYamlFile(filename);
camera->setParameters(params);
return camera;
}
case Camera::SCARAMUZZA:
{
OCAMCameraPtr camera(new OCAMCamera);
OCAMCamera::Parameters params = camera->getParameters();
params.readFromYamlFile(filename);
camera->setParameters(params);
return camera;
}
case Camera::MEI:
default:
{
CataCameraPtr camera(new CataCamera);
CataCamera::Parameters params = camera->getParameters();
params.readFromYamlFile(filename);
camera->setParameters(params);
return camera;
}
}
return CameraPtr();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

数据预处理框架

代码流程如下图:主要三个源程序,feature_tracker_node是特征跟踪线程的系统入口,feature_tracker是特征跟踪算法的具体实现,parameters是设备等参数的读取和存放。
在这里插入图片描述
在这里插入图片描述
我们有了整体的理论以及部分理论的补充之后,我们看一下视觉跟踪整体的ROS框架

ROS代码实现

在这里插入图片描述
feature_trackers可被认为是一个单独的模块
输入

  • 图像,即订阅了传感器或者rosbag发布的topic:“/cam0/image_raw”
ros::Subscriber sub_img = n.subscribe(IMAGE_TOPIC, 100, img_callback);

 
 
  • 1

输出

  • 发布topic:“/feature_trackers/feature_img” 即跟踪的特征点图像,主要是之后给RVIZ用和调试用
  • 发布topic:“/feature_trackers/feature” 即跟踪的特征点信息,由/vins_estimator订阅并进行优化
  • 发布topic:“/feature_trackers/restart” 即判断特征跟踪模块是否出错,若有问题则进行复位,由/vins_estimator订阅
pub_img = n.advertise<sensor_msgs::PointCloud>("feature", 1000);
pub_match = n.advertise<sensor_msgs::Image>("feature_img",1000);
pub_restart = n.advertise<std_msgs::Bool>("restart",1000);

 
 
  • 1
  • 2
  • 3

现在我们知道了视觉跟踪的ROS框架, 订阅者和发布者等信息. 接下来一起看一下视觉跟踪的代码结构.

视觉跟踪代码结构

VINS对于视觉跟踪相关的代码在feature_tracker文件夹中。
feature_trackers_node.cpp:main()函数 ROS的程序入口, 进入后配置参数,在parameters.cpp中.
在这里插入图片描述
在这里插入图片描述
feature_trackers_node.cpp 中的局部代码

 //1.读取yaml中的一些配置参数 地址为config->euroc->euroc_config.yaml
    readParameters(n);
    //2.读取每个相机实例对应的相机内参,NUM_OF_CAM 经常为1,单目
    for (int i = 0; i < NUM_OF_CAM; i++)
        trackerData[i].readIntrinsicParameter(CAM_NAMES[i]);//读取相机内参,保存到CAM_NAMES[i],如何获取相机的内呢???
    // 3.判断是否加入鱼眼mask 来去除边缘噪声
    if(FISHEYE)
    {
        for (int i = 0; i < NUM_OF_CAM; i++)
        {
            trackerData[i].fisheye_mask = cv::imread(FISHEYE_MASK, 0);
            if(!trackerData[i].fisheye_mask.data)
            {
                ROS_INFO("load mask fail");
                ROS_BREAK();
            }
            else
                ROS_INFO("load mask success");
        }
    }
    // 4.订阅话题IMAGE_TOPIC(/cam0/image_raw),有图像发布到这个话题时,执行回调函数img_callback
    ros::Subscriber sub_img = n.subscribe(IMAGE_TOPIC, 100, img_callback);

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

feature_trackers.cpp/feature_trackers.h:构建feature_trackers类,实现特征点跟踪的函数 位于feature_tracker.cpp 与feature_tracker.h中,我们看一下各个函数的功能:
在这里插入图片描述
feature_trackers类的成员变量

	cv::Mat mask;//图像掩码
    cv::Mat fisheye_mask;//鱼眼相机mask,用来去除边缘噪点
<span class="token comment">// prev_img是上一次发布的帧的图像数据</span>
<span class="token comment">// cur_img是光流跟踪的前一帧的图像数据</span>
<span class="token comment">// forw_img是光流跟踪的后一帧的图像数据</span>
cv<span class="token operator">::</span>Mat prev_img<span class="token punctuation">,</span> cur_img<span class="token punctuation">,</span> forw_img<span class="token punctuation">;</span>

vector<span class="token operator">&lt;</span>cv<span class="token operator">::</span>Point2f<span class="token operator">&gt;</span> n_pts<span class="token punctuation">;</span><span class="token comment">//每一帧中新提取的特征点</span>
vector<span class="token operator">&lt;</span>cv<span class="token operator">::</span>Point2f<span class="token operator">&gt;</span> prev_pts<span class="token punctuation">,</span> cur_pts<span class="token punctuation">,</span> forw_pts<span class="token punctuation">;</span><span class="token comment">//对应的图像特征点</span>
vector<span class="token operator">&lt;</span>cv<span class="token operator">::</span>Point2f<span class="token operator">&gt;</span> prev_un_pts<span class="token punctuation">,</span> cur_un_pts<span class="token punctuation">;</span><span class="token comment">//归一化相机坐标系下的坐标</span>
vector<span class="token operator">&lt;</span>cv<span class="token operator">::</span>Point2f<span class="token operator">&gt;</span> pts_velocity<span class="token punctuation">;</span><span class="token comment">//当前帧相对前一帧特征点沿x,y方向的像素移动速度</span>
vector<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;</span> ids<span class="token punctuation">;</span><span class="token comment">//能够被跟踪到的特征点的id</span>
vector<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;</span> track_cnt<span class="token punctuation">;</span><span class="token comment">//当前帧forw_img中每个特征点被追踪的时间次数</span>

map<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">,</span> cv<span class="token operator">::</span>Point2f<span class="token operator">&gt;</span> cur_un_pts_map<span class="token punctuation">;</span>
map<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">,</span> cv<span class="token operator">::</span>Point2f<span class="token operator">&gt;</span> prev_un_pts_map<span class="token punctuation">;</span>

camodocal<span class="token operator">::</span>CameraPtr m_camera<span class="token punctuation">;</span><span class="token comment">//相机模型</span>
<span class="token keyword">double</span> cur_time<span class="token punctuation">;</span>
<span class="token keyword">double</span> prev_time<span class="token punctuation">;</span>

<span class="token keyword">static</span> <span class="token keyword">int</span> n_id<span class="token punctuation">;</span><span class="token comment">//用来作为特征点id,每检测到一个新的特征点,就将n_id作为该特征点的id,然后n_id加1</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

可以看到,视觉跟踪的主要实现方法集中在feature_trackers_node.cpp的回调函数和feature_trackers类中,接下来将从main()函数开始对加粗的函数进行具体解读:

一、feature_tracker_node.cpp

主要分为两部分:int main()函数为程序入口,void img_callback()为ROS的回调函数,对图像进行特征点追踪,处理和发布。

int main(int argc, char **argv)
{
    ros::init(argc, argv, "feature_tracker");  //ros初始化和设置句柄
    ros::NodeHandle n("~");// 命名空间为/node_namespace/node_name
<span class="token comment">//设置logger的级别。 只有级别大于或等于level的日志记录消息才会得到处理。</span>
ros<span class="token operator">::</span>console<span class="token operator">::</span><span class="token function">set_logger_level</span><span class="token punctuation">(</span>ROSCONSOLE_DEFAULT_NAME<span class="token punctuation">,</span> ros<span class="token operator">::</span>console<span class="token operator">::</span>levels<span class="token operator">::</span>Info<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 1.读取yaml中的一些配置参数 地址为config-&gt;euroc-&gt;euroc_config.yaml</span>
<span class="token function">readParameters</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 2.读取每个相机实例对应的相机内参,NUM_OF_CAM 经常为1,单目</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> NUM_OF_CAM<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
    trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">readIntrinsicParameter</span><span class="token punctuation">(</span>CAM_NAMES<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 3.判断是否加入鱼眼mask 来去除边缘噪声</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>FISHEYE<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> NUM_OF_CAM<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>fisheye_mask <span class="token operator">=</span> cv<span class="token operator">::</span><span class="token function">imread</span><span class="token punctuation">(</span>FISHEYE_MASK<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>fisheye_mask<span class="token punctuation">.</span>data<span class="token punctuation">)</span>
        <span class="token punctuation">{<!-- --></span>
            <span class="token function">ROS_INFO</span><span class="token punctuation">(</span><span class="token string">"load mask fail"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token function">ROS_BREAK</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">else</span>
            <span class="token function">ROS_INFO</span><span class="token punctuation">(</span><span class="token string">"load mask success"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// 4.订阅话题IMAGE_TOPIC(/cam0/image_raw),有图像发布到这个话题时,执行回调函数img_callback</span>
ros<span class="token operator">::</span>Subscriber sub_img <span class="token operator">=</span> n<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>IMAGE_TOPIC<span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">,</span> img_callback<span class="token punctuation">)</span><span class="token punctuation">;</span>

/*
//创建话题的subscriber
ros::Subscriber subscribe(const string &topic, uint32_t queue_size, void(*)(M));
//第一个参数是订阅话题的名称
//第二个参数是订阅队列的长度,如果受到的消息都没来得及处理,那么新消息入队旧消息就会出队
//第三个参数是回调函数指针,指向回调函数来处理接收到的消息
/

pub_img = n.advertise<sensor_msgs::PointCloud>(“feature”, 1000);
pub_match = n.advertise<sensor_msgs::Image>(“feature_img”,1000);
pub_restart = n.advertise<std_msgs::Bool>(“restart”,1000);
/
if (SHOW_TRACK)
cv::namedWindow(“vis”, cv::WINDOW_NORMAL);
*/

ros::spin();
return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

1、void ing_callback(const sensor_msgs::ImageConstPtr &img_msg)

//ROS的回调函数,主要功能包括:readImage()函数对新来的图像使用光流法进行特征点跟踪,
// 并将追踪的特征点封装成feature_points发布到pub_img的话题下,将图像封装成ptr发布在pub_match下。
//例如
//pub_img.publish(feature_points);
//pub_match.publish(ptr->toImageMsg())

 
 
  • 1
  • 2
  • 3
  • 4
  • 5

我们从流程图可以看到内部函数之间的调用顺序,先看一下各个函数的功能

 // 1.判断是否是第一帧
    if(first_image_flag)
    {
        first_image_flag = false;// 更新:不再是第一帧图像
        first_image_time = img_msg->header.stamp.toSec();//记录第一个图像帧的时间
        last_image_time = img_msg->header.stamp.toSec();
        return;
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
 // 2.通过时间间隔判断相机数据流是否稳定,有问题则restart
    // detect unstable camera stream
    if (img_msg->header.stamp.toSec() - last_image_time > 1.0 || img_msg->header.stamp.toSec() < last_image_time)
    {
        ROS_WARN("image discontinue! reset the feature tracker!");
        first_image_flag = true;
        last_image_time = 0;
        pub_count = 1;
        std_msgs::Bool restart_flag;
        restart_flag.data = true;
        pub_restart.publish(restart_flag); // 复位
        return;
    }
    last_image_time = img_msg->header.stamp.toSec(); // 更新上一帧图像时间戳

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
    // frequency control
    // 3.发布频率控制,保证每秒钟处理的Image小于FREQ,频率控制在10HZ以内
    // 并不是每读入一帧图像,就要发布特征点
    // 判断间隔时间内的发布次数
    if (round(1.0 * pub_count / (img_msg->header.stamp.toSec() - first_image_time)) <= FREQ)
    {
        PUB_THIS_FRAME = true; // 发布当前帧
        // reset the frequency control
        // 时间间隔内的发布频率十分接近设定频率时,更新时间间隔起始时刻,并将数据发布次数置0
        if (abs(1.0 * pub_count / (img_msg->header.stamp.toSec() - first_image_time) - FREQ) < 0.01 * FREQ)
        {
            first_image_time = img_msg->header.stamp.toSec();
            pub_count = 0;
        }
    }
    else
        PUB_THIS_FRAME = false;

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
 //OpenCV中,图像是以Mat矩阵的形式存储的,与ROS定义的图像消息的格式不同,需要利用cv_bridge进行转换
    // 4.将图像编码8UC1转换为mono8,单色8bit
    cv_bridge::CvImageConstPtr ptr;
    if (img_msg->encoding == "8UC1")
    {
        sensor_msgs::Image img; // ROS图像消息
        img.header = img_msg->header;
        img.height = img_msg->height;
        img.width = img_msg->width;
        img.is_bigendian = img_msg->is_bigendian;
        img.step = img_msg->step;
        img.data = img_msg->data;
        img.encoding = "mono8";
        //cv_bridge将ROS的图像消息转换为OpenCV图像格式时都是通过CvImage类实现的。
        //cv_bridge提供了两种方式转换为CvImage类,分别为复制(copy)和共享(share)
        //   CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr& source,
        //                       const std::string& encoding = std::string());
        //   CvImagePtr toCvCopy(const sensor_msgs::Image& source,
        //                       const std::string& encoding = std::string());
    ptr <span class="token operator">=</span> cv_bridge<span class="token operator">::</span><span class="token function">toCvCopy</span><span class="token punctuation">(</span>img<span class="token punctuation">,</span> sensor_msgs<span class="token operator">::</span>image_encodings<span class="token operator">::</span>MONO8<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
    ptr <span class="token operator">=</span> cv_bridge<span class="token operator">::</span><span class="token function">toCvCopy</span><span class="token punctuation">(</span>img_msg<span class="token punctuation">,</span> sensor_msgs<span class="token operator">::</span>image_encodings<span class="token operator">::</span>MONO8<span class="token punctuation">)</span><span class="token punctuation">;</span>
cv<span class="token operator">::</span>Mat show_img <span class="token operator">=</span> ptr<span class="token operator">-</span><span class="token operator">&gt;</span>image<span class="token punctuation">;</span>
TicToc t_r<span class="token punctuation">;</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在这里函数进入readImage(); 读取图像数据并处理,

  // 5. 重要!!!trackerData[i].readImage读取图像数据
    for (int i = 0; i < NUM_OF_CAM; i++)
    {
        ROS_DEBUG("processing camera %d", i);
        if (i != 1 || !STEREO_TRACK) //单目
            //cur_img 上一针图像
            //forw_img 当前针图像
            //cur_pts 上一针的点坐标
            //forw_pts 当前针的点坐标
            //ids 每个点的ids
            //track_cnt 每个点被跟踪的次数
            //cur_un_=ts最新针的归一化相机洗坐标
            trackerData[i].readImage(ptr->image.rowRange(ROW * i, ROW * (i + 1)), img_msg->header.stamp.toSec());
        else //双目
        {
            if (EQUALIZE)
            {
                cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE();
                clahe->apply(ptr->image.rowRange(ROW * i, ROW * (i + 1)), trackerData[i].cur_img);
            }
            else
                trackerData[i].cur_img = ptr->image.rowRange(ROW * i, ROW * (i + 1));
        }

#if SHOW_UNDISTORTION
trackerData[i].showUndistortion(“undistrotion_” + std::to_string(i));
#endif
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
 // 6.更新全局ID
    for (unsigned int i = 0;; i++)
    {
        bool completed = false;
        for (int j = 0; j < NUM_OF_CAM; j++)
            if (j != 1 || !STEREO_TRACK)
                completed |= trackerData[j].updateID(i); // 更新feature的id
        if (!completed)
            break;
    }

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
 // 6.更新全局ID
    // 7、将特征点id,矫正后归一化平面的3D点(x,y,z=1),像素2D点(u,v),像素的速度(vx,vy),
    //封装成sensor_msgs::PointCloudPtr类型的feature_points实例中,发布到pub_img;
<span class="token keyword">if</span> <span class="token punctuation">(</span>PUB_THIS_FRAME<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    pub_count<span class="token operator">++</span><span class="token punctuation">;</span>
    <span class="token comment">// 重要!!! feature_points</span>
    sensor_msgs<span class="token operator">::</span>PointCloudPtr <span class="token function">feature_points</span><span class="token punctuation">(</span><span class="token keyword">new</span> sensor_msgs<span class="token operator">::</span>PointCloud<span class="token punctuation">)</span><span class="token punctuation">;</span>
    sensor_msgs<span class="token operator">::</span>ChannelFloat32 id_of_point<span class="token punctuation">;</span>
    sensor_msgs<span class="token operator">::</span>ChannelFloat32 u_of_point<span class="token punctuation">;</span>
    sensor_msgs<span class="token operator">::</span>ChannelFloat32 v_of_point<span class="token punctuation">;</span>
    sensor_msgs<span class="token operator">::</span>ChannelFloat32 velocity_x_of_point<span class="token punctuation">;</span>
    sensor_msgs<span class="token operator">::</span>ChannelFloat32 velocity_y_of_point<span class="token punctuation">;</span>

    feature_points<span class="token operator">-</span><span class="token operator">&gt;</span>header <span class="token operator">=</span> img_msg<span class="token operator">-</span><span class="token operator">&gt;</span>header<span class="token punctuation">;</span>
    feature_points<span class="token operator">-</span><span class="token operator">&gt;</span>header<span class="token punctuation">.</span>frame_id <span class="token operator">=</span> <span class="token string">"world"</span><span class="token punctuation">;</span>

    vector<span class="token operator">&lt;</span>set<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;&gt;</span> <span class="token function">hash_ids</span><span class="token punctuation">(</span>NUM_OF_CAM<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 哈希表id</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> NUM_OF_CAM<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>   <span class="token comment">// 循环相机数量</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">auto</span> <span class="token operator">&amp;</span>un_pts <span class="token operator">=</span> trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>cur_un_pts<span class="token punctuation">;</span>
        <span class="token keyword">auto</span> <span class="token operator">&amp;</span>cur_pts <span class="token operator">=</span> trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>cur_pts<span class="token punctuation">;</span>
        <span class="token keyword">auto</span> <span class="token operator">&amp;</span>ids <span class="token operator">=</span> trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>ids<span class="token punctuation">;</span>
        <span class="token keyword">auto</span> <span class="token operator">&amp;</span>pts_velocity <span class="token operator">=</span> trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>pts_velocity<span class="token punctuation">;</span>
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> ids<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token comment">// 特征点数量</span>
        <span class="token punctuation">{<!-- --></span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>track_cnt<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">&gt;</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment">// 该特征点被追踪次数大于1</span>
            <span class="token punctuation">{<!-- --></span>
                <span class="token keyword">int</span> p_id <span class="token operator">=</span> ids<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span>
                hash_ids<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span>p_id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 哈希表id  insert</span>
                geometry_msgs<span class="token operator">::</span>Point32 p<span class="token punctuation">;</span> <span class="token comment">// 大规模点云信息</span>
                p<span class="token punctuation">.</span>x <span class="token operator">=</span> un_pts<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">.</span>x<span class="token punctuation">;</span>
                p<span class="token punctuation">.</span>y <span class="token operator">=</span> un_pts<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">.</span>y<span class="token punctuation">;</span>
                p<span class="token punctuation">.</span>z <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>

                feature_points<span class="token operator">-</span><span class="token operator">&gt;</span>points<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><span class="token punctuation">;</span>
                id_of_point<span class="token punctuation">.</span>values<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>p_id <span class="token operator">*</span> NUM_OF_CAM <span class="token operator">+</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>
                u_of_point<span class="token punctuation">.</span>values<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>cur_pts<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">.</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
                v_of_point<span class="token punctuation">.</span>values<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>cur_pts<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span>
                velocity_x_of_point<span class="token punctuation">.</span>values<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>pts_velocity<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">.</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
                velocity_y_of_point<span class="token punctuation">.</span>values<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>pts_velocity<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
    feature_points<span class="token operator">-</span><span class="token operator">&gt;</span>channels<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>id_of_point<span class="token punctuation">)</span><span class="token punctuation">;</span>
    feature_points<span class="token operator">-</span><span class="token operator">&gt;</span>channels<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>u_of_point<span class="token punctuation">)</span><span class="token punctuation">;</span>
    feature_points<span class="token operator">-</span><span class="token operator">&gt;</span>channels<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>v_of_point<span class="token punctuation">)</span><span class="token punctuation">;</span>
    feature_points<span class="token operator">-</span><span class="token operator">&gt;</span>channels<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>velocity_x_of_point<span class="token punctuation">)</span><span class="token punctuation">;</span>
    feature_points<span class="token operator">-</span><span class="token operator">&gt;</span>channels<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>velocity_y_of_point<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">ROS_DEBUG</span><span class="token punctuation">(</span><span class="token string">"publish %f, at %f"</span><span class="token punctuation">,</span> feature_points<span class="token operator">-</span><span class="token operator">&gt;</span>header<span class="token punctuation">.</span>stamp<span class="token punctuation">.</span><span class="token function">toSec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> ros<span class="token operator">::</span>Time<span class="token operator">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toSec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// skip the first image; since no optical speed on frist image</span>
    <span class="token comment">// 第一帧不发布,因为没有光流速度</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>init_pub<span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        init_pub <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span>
        pub_img<span class="token punctuation">.</span><span class="token function">publish</span><span class="token punctuation">(</span>feature_points<span class="token punctuation">)</span><span class="token punctuation">;</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
// 8、将图像封装到cv_bridge::cvtColor类型的ptr实例中发布到pub_match
        if (SHOW_TRACK)
        {
            ptr = cv_bridge::cvtColor(ptr, sensor_msgs::image_encodings::BGR8);
            //cv::Mat stereo_img(ROW * NUM_OF_CAM, COL, CV_8UC3);
            cv::Mat stereo_img = ptr->image;
        <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> NUM_OF_CAM<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
        <span class="token punctuation">{<!-- --></span>
            cv<span class="token operator">::</span>Mat tmp_img <span class="token operator">=</span> stereo_img<span class="token punctuation">.</span><span class="token function">rowRange</span><span class="token punctuation">(</span>i <span class="token operator">*</span> ROW<span class="token punctuation">,</span> <span class="token punctuation">(</span>i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">*</span> ROW<span class="token punctuation">)</span><span class="token punctuation">;</span>
            cv<span class="token operator">::</span><span class="token function">cvtColor</span><span class="token punctuation">(</span>show_img<span class="token punctuation">,</span> tmp_img<span class="token punctuation">,</span> CV_GRAY2RGB<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// show_img灰度图转RGB(tmp_img)</span>
            <span class="token comment">//显示追踪状态,越红越好,越蓝越不行</span>

            <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator">&lt;</span> trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>cur_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span>
            <span class="token punctuation">{<!-- --></span>
                <span class="token keyword">double</span> len <span class="token operator">=</span> std<span class="token operator">::</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token number">1.0</span> <span class="token operator">*</span> trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>track_cnt<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">/</span> WINDOW_SIZE<span class="token punctuation">)</span><span class="token punctuation">;</span>
                cv<span class="token operator">::</span><span class="token function">circle</span><span class="token punctuation">(</span>tmp_img<span class="token punctuation">,</span> trackerData<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>cur_pts<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">255</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">-</span> len<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span> <span class="token operator">*</span> len<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">//draw speed line</span>
                <span class="token comment">/*
                Vector2d tmp_cur_un_pts (trackerData[i].cur_un_pts[j].x, trackerData[i].cur_un_pts[j].y);
                Vector2d tmp_pts_velocity (trackerData[i].pts_velocity[j].x, trackerData[i].pts_velocity[j].y);
                Vector3d tmp_prev_un_pts;
                tmp_prev_un_pts.head(2) = tmp_cur_un_pts - 0.10 * tmp_pts_velocity;
                tmp_prev_un_pts.z() = 1;
                Vector2d tmp_prev_uv;
                trackerData[i].m_camera-&gt;spaceToPlane(tmp_prev_un_pts, tmp_prev_uv);
                cv::line(tmp_img, trackerData[i].cur_pts[j], cv::Point2f(tmp_prev_uv.x(), tmp_prev_uv.y()), cv::Scalar(255 , 0, 0), 1 , 8, 0);
                */</span>
                <span class="token comment">//char name[10];</span>
                <span class="token comment">//sprintf(name, "%d", trackerData[i].ids[j]);</span>
                <span class="token comment">//cv::putText(tmp_img, name, trackerData[i].cur_pts[j], cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token comment">//cv::imshow("vis", stereo_img);</span>
        <span class="token comment">//cv::waitKey(5);</span>
        pub_match<span class="token punctuation">.</span><span class="token function">publish</span><span class="token punctuation">(</span>ptr<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">toImageMsg</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token function">ROS_INFO</span><span class="token punctuation">(</span><span class="token string">"whole feature tracker processing costs: %f"</span><span class="token punctuation">,</span> t_r<span class="token punctuation">.</span><span class="token function">toc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

二、feature_tracker.cpp

在这里插入图片描述

void FeatureTracker::readImage(const cv::Mat &_img, double _cur_time)

主要分为两部分:

1、特征点检测:Frame1,goofFeaturesToTrack()检测MAX_CNT个特征点,添加到forw_pts中

2、特征点跟踪:calOpticalFlowPyrLK跟踪,将跟踪失败的点剔除,跟踪成功的跟踪次数+1,调用goodFeaturesToTracl()再检测出MAX_CNT-forw_pts.size()个特征点,添加到forw_pts中,调用updateID 更新ids。

undistortedPoints()中cur_un_pts为归一化相机坐标系下坐标,pts_velocity为当前帧相对于前一帧特征点沿着x、y方向的像素移动速度。

对图像使用光流法进行特征点跟踪,具体流程有:

①先调用createCLAHE() 对图像进行自适应直方图均衡化(如果EQUALIZE=1,表示太亮或则太暗)

②调用calcOpticalFlowPyrLK()跟踪cur_pts到forw_pts,根据status,把跟踪失败的点剔除(注意:prev, cur,forw, ids, track_cnt都要剔除),这里还加了个inBorder判断,把跟踪到图像边缘的点也剔除掉.

③如果不需要发布特征点,则到这步就完了,把当前帧forw赋给上一帧cur, 然后退出.如果需要发布特征点(PUB_THIS_FRAME=1), 则执行下面的步骤

④先调用rejectWithF()对prev_pts和forw_pts做ransac剔除outlier.(实际就是调用了findFundamentalMat函数), 在光流追踪成功就记被追踪+1,数值代表被追踪的次数,数值越大,说明被追踪的就越久

⑤调用setMask(), 先对跟踪点forw_pts按跟踪次数降排序, 然后依次选点, 选一个点, 在mask中将该点周围一定半径的区域设为0, 后面不再选取该区域内的点. 有点类似与non-max suppression, 但区别是这里保留track_cnt最高的点.

⑥在mask中不为0的区域,调用goodFeaturesToTrack提取新的特征角点n_pts, 通过addPoints()函数push到forw_pts中, id初始化-1,track_cnt初始化为1.

undistortedPoints() 对角点图像坐标去畸变矫正,并计算每个角点的速度

值得注意的是,当前帧为forw_pts,被追踪到的帧;curr_pts实际上是上一帧;

//对图像使用光流法进行特征点跟踪
void FeatureTracker::readImage(const cv::Mat &_img, double _cur_time)
{
    cv::Mat img;
    TicToc t_r;
    cur_time = _cur_time;
   // ①先调用createCLAHE() 对图像进行自适应直方图均衡化(如果EQUALIZE=1,表示太亮或则太暗)
    // 1.如果EQUALIZE=1,表示太亮或太暗,进行直方图均衡化处理
    if (EQUALIZE)
    {
        //自适应直方图均衡
        //createCLAHE(double clipLimit, Size tileGridSize)
        //CLAHE 用来对图像进行灰度变换,以达到提高图像对比度的目的。
        cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(3.0, cv::Size(8, 8));//size类中的两个数据成员叫做width和heigh
        TicToc t_c;
        clahe->apply(_img, img);
        ROS_DEBUG("CLAHE costs: %fms", t_c.toc());
    }
    else
        img = _img;
<span class="token comment">// 2. 判断当前帧图像forw_img是否为空</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>forw_img<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token comment">//如果当前帧的图像数据forw_img为空,说明当前是第一次读入图像数据</span>
    <span class="token comment">//将读入的图像赋给当前帧forw_img,同时还赋给prev_img、cur_img</span>
    prev_img <span class="token operator">=</span> cur_img <span class="token operator">=</span> forw_img <span class="token operator">=</span> img<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token comment">//否则,说明之前就已经有图像读入,只需要更新当前帧forw_img的数据</span>
    forw_img <span class="token operator">=</span> img<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">//此时forw_pts还保存的是上一帧图像中的特征点,所以把它清除</span>
forw_pts<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>cur_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token comment">// 前一帧有特征点</span>
<span class="token punctuation">{<!-- --></span>
    TicToc t_o<span class="token punctuation">;</span>
    vector<span class="token operator">&lt;</span>uchar<span class="token operator">&gt;</span> status<span class="token punctuation">;</span>
    vector<span class="token operator">&lt;</span><span class="token keyword">float</span><span class="token operator">&gt;</span> err<span class="token punctuation">;</span>

    <span class="token comment">// 3. 调用cv::calcOpticalFlowPyrLK()对前一帧的特征点cur_pts进行LK金字塔光流跟踪,得到forw_pts</span>
    <span class="token comment">//status标记了从前一帧cur_img到forw_img特征点的跟踪状态,无法被追踪到的点标记为0</span>
    cv<span class="token operator">::</span><span class="token function">calcOpticalFlowPyrLK</span><span class="token punctuation">(</span>cur_img<span class="token punctuation">,</span> forw_img<span class="token punctuation">,</span> cur_pts<span class="token punctuation">,</span> forw_pts<span class="token punctuation">,</span> status<span class="token punctuation">,</span> err<span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Size</span><span class="token punctuation">(</span><span class="token number">21</span><span class="token punctuation">,</span> <span class="token number">21</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token keyword">int</span><span class="token punctuation">(</span>forw_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>status<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span><span class="token function">inBorder</span><span class="token punctuation">(</span>forw_pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">// 将当前帧跟踪的位于图像边界外的点标记为0</span>
            status<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token comment">// 4. 根据status,把跟踪失败的点剔除</span>
    <span class="token comment">//不仅要从当前帧数据forw_pts中剔除,而且还要从cur_un_pts、prev_pts和cur_pts中剔除</span>
    <span class="token comment">//prev_pts和cur_pts中的特征点是一一对应的</span>
    <span class="token comment">//记录特征点id的ids,和记录特征点被跟踪次数的track_cnt也要剔除</span>

    <span class="token function">reduceVector</span><span class="token punctuation">(</span>prev_pts<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>cur_pts<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>forw_pts<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>ids<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>cur_un_pts<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>track_cnt<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">ROS_DEBUG</span><span class="token punctuation">(</span><span class="token string">"temporal optical flow costs: %fms"</span><span class="token punctuation">,</span> t_o<span class="token punctuation">.</span><span class="token function">toc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 5. 光流追踪成功,特征点被成功跟踪的次数就加1</span>
<span class="token comment">//数值代表被追踪的次数,数值越大,说明被追踪的就越久</span>

<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">auto</span> <span class="token operator">&amp;</span>n <span class="token operator">:</span> track_cnt<span class="token punctuation">)</span>
    n<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token comment">//PUB_THIS_FRAME=1 需要发布特征点</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>PUB_THIS_FRAME<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token comment">// 6. rejectWithF()通过基本矩阵剔除outliers</span>
    <span class="token function">rejectWithF</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token comment">// 7. setMask()保证相邻的特征点之间要相隔30个像素,设置mask</span>
    <span class="token function">ROS_DEBUG</span><span class="token punctuation">(</span><span class="token string">"set mask begins"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    TicToc t_m<span class="token punctuation">;</span>
    <span class="token function">setMask</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">ROS_DEBUG</span><span class="token punctuation">(</span><span class="token string">"set mask costs %fms"</span><span class="token punctuation">,</span> t_m<span class="token punctuation">.</span><span class="token function">toc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 8. 寻找新的特征点 goodFeaturesToTrack()</span>
    <span class="token function">ROS_DEBUG</span><span class="token punctuation">(</span><span class="token string">"detect feature begins"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    TicToc t_t<span class="token punctuation">;</span>

    <span class="token comment">//计算是否需要提取新的特征点</span>
    <span class="token keyword">int</span> n_max_cnt <span class="token operator">=</span> MAX_CNT <span class="token operator">-</span> <span class="token keyword">static_cast</span><span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>forw_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>n_max_cnt <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>mask<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            cout <span class="token operator">&lt;&lt;</span> <span class="token string">"mask is empty "</span> <span class="token operator">&lt;&lt;</span> endl<span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>mask<span class="token punctuation">.</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> CV_8UC1<span class="token punctuation">)</span>
            cout <span class="token operator">&lt;&lt;</span> <span class="token string">"mask type wrong "</span> <span class="token operator">&lt;&lt;</span> endl<span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>mask<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> forw_img<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            cout <span class="token operator">&lt;&lt;</span> <span class="token string">"wrong size "</span> <span class="token operator">&lt;&lt;</span> endl<span class="token punctuation">;</span>
             <span class="token comment">/** 
         *void cv::goodFeaturesToTrack(    在mask中不为0的区域检测新的特征点
         *   InputArray  image,              输入图像
         *   OutputArray     corners,        存放检测到的角点的vector
         *   int     maxCorners,             返回的角点的数量的最大值
         *   double  qualityLevel,           角点质量水平的最低阈值(范围为0到1,质量最高角点的水平为1),小于该阈值的角点被拒绝
         *   double  minDistance,            返回角点之间欧式距离的最小值
         *   InputArray  mask = noArray(),   和输入图像具有相同大小,类型必须为CV_8UC1,用来描述图像中感兴趣的区域,只在感兴趣区域中检测角点
         *   int     blockSize = 3,          计算协方差矩阵时的窗口大小
         *   bool    useHarrisDetector = false,  指示是否使用Harris角点检测,如不指定则使用shi-tomasi算法
         *   double  k = 0.04                Harris角点检测需要的k值
         *)   
         */</span>

        cv<span class="token operator">::</span><span class="token function">goodFeaturesToTrack</span><span class="token punctuation">(</span>forw_img<span class="token punctuation">,</span> n_pts<span class="token punctuation">,</span> MAX_CNT <span class="token operator">-</span> forw_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0.01</span><span class="token punctuation">,</span> MIN_DIST<span class="token punctuation">,</span> mask<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">else</span>
        n_pts<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">ROS_DEBUG</span><span class="token punctuation">(</span><span class="token string">"detect feature costs: %fms"</span><span class="token punctuation">,</span> t_t<span class="token punctuation">.</span><span class="token function">toc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 9. addPoints()向forw_pts添加新的追踪点</span>
    <span class="token function">ROS_DEBUG</span><span class="token punctuation">(</span><span class="token string">"add feature begins"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    TicToc t_a<span class="token punctuation">;</span>

     <span class="token comment">//添将新检测到的特征点n_pts添加到forw_pts中,id初始化-1,track_cnt初始化为1</span>
    <span class="token function">addPoints</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">ROS_DEBUG</span><span class="token punctuation">(</span><span class="token string">"selectFeature costs: %fms"</span><span class="token punctuation">,</span> t_a<span class="token punctuation">.</span><span class="token function">toc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// 10. 更新帧、特征点</span>
<span class="token comment">//当下一帧图像到来时,当前帧数据就成为了上一帧发布的数据</span>
prev_img <span class="token operator">=</span> cur_img<span class="token punctuation">;</span>
prev_pts <span class="token operator">=</span> cur_pts<span class="token punctuation">;</span>
prev_un_pts <span class="token operator">=</span> cur_un_pts<span class="token punctuation">;</span>

<span class="token comment">//把当前帧的数据forw_img、forw_pts赋给上一帧cur_img、cur_pts</span>
cur_img <span class="token operator">=</span> forw_img<span class="token punctuation">;</span>
cur_pts <span class="token operator">=</span> forw_pts<span class="token punctuation">;</span>

<span class="token comment">// 11. 根据不同的相机模型去畸变矫正和转换到归一化坐标系上,计算速度</span>
<span class="token function">undistortedPoints</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
prev_time <span class="token operator">=</span> cur_time<span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137

1 inBorder()函数

//判断跟踪的特特征点是否在图像边界内
bool inBorder(const cv::Point2f &pt)
{
    const int BORDER_SIZE = 1;
    int img_x = cvRound(pt.x);
    int img_y = cvRound(pt.y);
    //cvRound():返回跟参数最接近的整数值,即四舍五入;
    // cvFloor():返回不大于参数的最大整数值,即向下取整;
    // cvCeil():返回不小于参数的最小整数值,即向上取整;
    return BORDER_SIZE <= img_x && img_x < COL - BORDER_SIZE && BORDER_SIZE <= img_y && img_y < ROW - BORDER_SIZE;
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2 reduceVector()函数

//去除无法跟踪的特征点,status为0的点直接跳过,否则v[j++]=v[i]留下来,最后v.resize(j)根据最新的j安排内存
void reduceVector(vector<cv::Point2f> &v, vector<uchar> status)
{
    int j = 0;
    for (int i = 0; i < int(v.size()); i++)
        if (status[i])
            v[j++] = v[i];
    v.resize(j);//resize(),设置大小(size); reserve(),设置容量(capacity);
}

void reduceVector(vector<int> &v, vector<uchar> status)
{
int j = 0;
for (int i = 0; i < int(v.size()); i++)
if (status[i])
v[j++] = v[i];
v.resize(j);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

3 setMask()函数


//对跟踪点进行排序并去除密集点
// 对跟踪到的特征点,按照被追踪到的次数排序并依次选点,使用mask进行类似非极大抑制,半径为30,去掉密集点,
//使特征点分布均匀。对跟踪到的特征点从大到小排序并去除密集的点。
void FeatureTracker::setMask()
{
    // 如果是鱼眼镜头直接clone即可,否则创建空白板
    if(FISHEYE)
        mask = fisheye_mask.clone();
    else
        mask = cv::Mat(ROW, COL, CV_8UC1, cv::Scalar(255));
<span class="token comment">// 倾向于留下被追踪时间很长的特征点</span>
<span class="token comment">// 构造(cnt,pts,id)序列,(追踪次数,当前特征点坐标,id)</span>
vector<span class="token operator">&lt;</span>pair<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">,</span> pair<span class="token operator">&lt;</span>cv<span class="token operator">::</span>Point2f<span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token operator">&gt;&gt;</span><span class="token operator">&gt;</span> cnt_pts_id<span class="token punctuation">;</span>

<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> forw_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
    cnt_pts_id<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span><span class="token function">make_pair</span><span class="token punctuation">(</span>track_cnt<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token function">make_pair</span><span class="token punctuation">(</span>forw_pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> ids<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 对光流跟踪到的特征点forw_pts,按照被跟踪到的次数cnt从大到小排序(lambda表达式)</span>
<span class="token function">sort</span><span class="token punctuation">(</span>cnt_pts_id<span class="token punctuation">.</span><span class="token function">begin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> cnt_pts_id<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">const</span> pair<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">,</span> pair<span class="token operator">&lt;</span>cv<span class="token operator">::</span>Point2f<span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token operator">&gt;&gt;</span> <span class="token operator">&amp;</span>a<span class="token punctuation">,</span> <span class="token keyword">const</span> pair<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">,</span> pair<span class="token operator">&lt;</span>cv<span class="token operator">::</span>Point2f<span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token operator">&gt;&gt;</span> <span class="token operator">&amp;</span>b<span class="token punctuation">)</span>
     <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">return</span> a<span class="token punctuation">.</span>first <span class="token operator">&gt;</span> b<span class="token punctuation">.</span>first<span class="token punctuation">;</span>
     <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token comment">//清空cnt,pts,id并重新存入</span>
forw_pts<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
ids<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
track_cnt<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">auto</span> <span class="token operator">&amp;</span>it <span class="token operator">:</span> cnt_pts_id<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>mask<span class="token punctuation">.</span>at<span class="token operator">&lt;</span>uchar<span class="token operator">&gt;</span><span class="token punctuation">(</span>it<span class="token punctuation">.</span>second<span class="token punctuation">.</span>first<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token comment">// 这个特征点对应的mask值为255,表明点是黑的,还没占有</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token comment">//则保留当前特征点,将对应的特征点位置pts,id,被追踪次数cnt分别存入</span>
        forw_pts<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>it<span class="token punctuation">.</span>second<span class="token punctuation">.</span>first<span class="token punctuation">)</span><span class="token punctuation">;</span>
        ids<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>it<span class="token punctuation">.</span>second<span class="token punctuation">.</span>second<span class="token punctuation">)</span><span class="token punctuation">;</span>
        track_cnt<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>it<span class="token punctuation">.</span>first<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//在mask中将当前特征点周围半径为MIN_DIST的区域设置为0,后面不再选取该区域内的点(使跟踪点不集中在一个区域上)</span>
        cv<span class="token operator">::</span><span class="token function">circle</span><span class="token punctuation">(</span>mask<span class="token punctuation">,</span> it<span class="token punctuation">.</span>second<span class="token punctuation">.</span>first<span class="token punctuation">,</span> MIN_DIST<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

4 addPoints()函数

void FeatureTracker::addPoints()
{
    for (auto &p : n_pts)
    {
        forw_pts.push_back(p);
        ids.push_back(-1);//新提取的特征点id初始化为-1
        track_cnt.push_back(1);//新提取的特征点被跟踪的次数初始化为1
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5 rejectWithF()函数

// 通过F矩阵去除outliers
// 首先把特征点转化到归一化相机坐标系,然后计算F矩阵,再根据status清除为0的特征点。
void FeatureTracker::rejectWithF()
{
    if (forw_pts.size() >= 8)// 当前帧(追踪上)特征点数量足够多
    {
        ROS_DEBUG("FM ransac begins");
        TicToc t_f;
        // 1.遍历所有特征点,转化为归一化相机坐标系
        vector<cv::Point2f> un_cur_pts(cur_pts.size()), un_forw_pts(forw_pts.size());
        for (unsigned int i = 0; i < cur_pts.size(); i++)//遍历上一帧所有特征点
        {
            Eigen::Vector3d tmp_p;
        <span class="token comment">//对于PINHOLE(针孔相机)可将像素坐标转换到归一化平面并去畸变。根据不同的相机模型将二维坐标转换到三维坐标</span>
        m_camera<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">liftProjective</span><span class="token punctuation">(</span>Eigen<span class="token operator">::</span><span class="token function">Vector2d</span><span class="token punctuation">(</span>cur_pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>x<span class="token punctuation">,</span> cur_pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span> tmp_p<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//转换为归一化像素坐标,上一帧和当前帧</span>
        tmp_p<span class="token punctuation">.</span><span class="token function">x</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span> FOCAL_LENGTH <span class="token operator">*</span> tmp_p<span class="token punctuation">.</span><span class="token function">x</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> tmp_p<span class="token punctuation">.</span><span class="token function">z</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> COL <span class="token operator">/</span> <span class="token number">2.0</span><span class="token punctuation">;</span>
        tmp_p<span class="token punctuation">.</span><span class="token function">y</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span> FOCAL_LENGTH <span class="token operator">*</span> tmp_p<span class="token punctuation">.</span><span class="token function">y</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> tmp_p<span class="token punctuation">.</span><span class="token function">z</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> ROW <span class="token operator">/</span> <span class="token number">2.0</span><span class="token punctuation">;</span>
        un_cur_pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> cv<span class="token operator">::</span><span class="token function">Point2f</span><span class="token punctuation">(</span>tmp_p<span class="token punctuation">.</span><span class="token function">x</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> tmp_p<span class="token punctuation">.</span><span class="token function">y</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        m_camera<span class="token operator">-</span><span class="token operator">&gt;</span><span class="token function">liftProjective</span><span class="token punctuation">(</span>Eigen<span class="token operator">::</span><span class="token function">Vector2d</span><span class="token punctuation">(</span>forw_pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>x<span class="token punctuation">,</span> forw_pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>y<span class="token punctuation">)</span><span class="token punctuation">,</span> tmp_p<span class="token punctuation">)</span><span class="token punctuation">;</span>
        tmp_p<span class="token punctuation">.</span><span class="token function">x</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span> FOCAL_LENGTH <span class="token operator">*</span> tmp_p<span class="token punctuation">.</span><span class="token function">x</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> tmp_p<span class="token punctuation">.</span><span class="token function">z</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> COL <span class="token operator">/</span> <span class="token number">2.0</span><span class="token punctuation">;</span>
        tmp_p<span class="token punctuation">.</span><span class="token function">y</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span> FOCAL_LENGTH <span class="token operator">*</span> tmp_p<span class="token punctuation">.</span><span class="token function">y</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> tmp_p<span class="token punctuation">.</span><span class="token function">z</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> ROW <span class="token operator">/</span> <span class="token number">2.0</span><span class="token punctuation">;</span>
        un_forw_pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> cv<span class="token operator">::</span><span class="token function">Point2f</span><span class="token punctuation">(</span>tmp_p<span class="token punctuation">.</span><span class="token function">x</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> tmp_p<span class="token punctuation">.</span><span class="token function">y</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    vector<span class="token operator">&lt;</span>uchar<span class="token operator">&gt;</span> status<span class="token punctuation">;</span>

    <span class="token comment">// 2. 调用cv::findFundamentalMat对un_cur_pts和un_forw_pts计算F矩阵,需要归一化相机系,z=1</span>
    cv<span class="token operator">::</span><span class="token function">findFundamentalMat</span><span class="token punctuation">(</span>un_cur_pts<span class="token punctuation">,</span> un_forw_pts<span class="token punctuation">,</span> cv<span class="token operator">::</span>FM_RANSAC<span class="token punctuation">,</span> F_THRESHOLD<span class="token punctuation">,</span> <span class="token number">0.99</span><span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> size_a <span class="token operator">=</span> cur_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 3. 根据status删除一些特征点</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>prev_pts<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>cur_pts<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>forw_pts<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>cur_un_pts<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>ids<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">reduceVector</span><span class="token punctuation">(</span>track_cnt<span class="token punctuation">,</span> status<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">ROS_DEBUG</span><span class="token punctuation">(</span><span class="token string">"FM ransac: %d -&gt; %lu: %f"</span><span class="token punctuation">,</span> size_a<span class="token punctuation">,</span> forw_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">1.0</span> <span class="token operator">*</span> forw_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> size_a<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">ROS_DEBUG</span><span class="token punctuation">(</span><span class="token string">"FM ransac costs: %fms"</span><span class="token punctuation">,</span> t_f<span class="token punctuation">.</span><span class="token function">toc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

6 updateID()函数

bool FeatureTracker::updateID(unsigned int i)
{
    if (i < ids.size())
    {
        if (ids[i] == -1)
            ids[i] = n_id++;
        return true;
    }
    else
        return false;
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

7 showUndistortion()函数


//显示去畸变矫正后的特征点  name为图像帧名称
void FeatureTracker::showUndistortion(const string &name)
{
    cv::Mat undistortedImg(ROW + 600, COL + 600, CV_8UC1, cv::Scalar(0));
    vector<Eigen::Vector2d> distortedp, undistortedp;
    for (int i = 0; i < COL; i++)
        for (int j = 0; j < ROW; j++)
        {
            Eigen::Vector2d a(i, j);
            Eigen::Vector3d b;
            m_camera->liftProjective(a, b);
            distortedp.push_back(a);
            undistortedp.push_back(Eigen::Vector2d(b.x() / b.z(), b.y() / b.z()));
            //printf("%f,%f->%f,%f,%f\n)\n", a.x(), a.y(), b.x(), b.y(), b.z());
        }
    for (int i = 0; i < int(undistortedp.size()); i++)
    {
        cv::Mat pp(3, 1, CV_32FC1);
        pp.at<float>(0, 0) = undistortedp[i].x() * FOCAL_LENGTH + COL / 2;
        pp.at<float>(1, 0) = undistortedp[i].y() * FOCAL_LENGTH + ROW / 2;
        pp.at<float>(2, 0) = 1.0;
        //cout << trackerData[0].K << endl;
        //printf("%lf %lf\n", p.at<float>(1, 0), p.at<float>(0, 0));
        //printf("%lf %lf\n", pp.at<float>(1, 0), pp.at<float>(0, 0));
        if (pp.at<float>(1, 0) + 300 >= 0 && pp.at<float>(1, 0) + 300 < ROW + 600 && pp.at<float>(0, 0) + 300 >= 0 && pp.at<float>(0, 0) + 300 < COL + 600)
        {
            undistortedImg.at<uchar>(pp.at<float>(1, 0) + 300, pp.at<float>(0, 0) + 300) = cur_img.at<uchar>(distortedp[i].y(), distortedp[i].x());
        }
        else
        {
            //ROS_ERROR("(%f %f) -> (%f %f)", distortedp[i].y, distortedp[i].x, pp.at<float>(1, 0), pp.at<float>(0, 0));
        }
    }
    cv::imshow(name, undistortedImg);
    cv::waitKey(0);
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

8 undistortedPoints()函数


//1.对角点图像坐标进行去畸变矫正,转换到归一化坐标系上,
//2.并计算每个角点的速度。  
void FeatureTracker::undistortedPoints()
{
    cur_un_pts.clear();
    cur_un_pts_map.clear();
    //cv::undistortPoints(cur_pts, un_pts, K, cv::Mat());
    // 1.归一化相机坐标系
    for (unsigned int i = 0; i < cur_pts.size(); i++)// 遍历所有特征点
    {
        Eigen::Vector2d a(cur_pts[i].x, cur_pts[i].y);
        Eigen::Vector3d b;
         //根据不同的相机模型将二维坐标转换到归一化相机三维坐标系
        m_camera->liftProjective(a, b);
    <span class="token comment">//再延伸到深度归一化平面上</span>
    cur_un_pts<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>cv<span class="token operator">::</span><span class="token function">Point2f</span><span class="token punctuation">(</span>b<span class="token punctuation">.</span><span class="token function">x</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> b<span class="token punctuation">.</span><span class="token function">z</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> b<span class="token punctuation">.</span><span class="token function">y</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> b<span class="token punctuation">.</span><span class="token function">z</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    cur_un_pts_map<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token function">make_pair</span><span class="token punctuation">(</span>ids<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> cv<span class="token operator">::</span><span class="token function">Point2f</span><span class="token punctuation">(</span>b<span class="token punctuation">.</span><span class="token function">x</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> b<span class="token punctuation">.</span><span class="token function">z</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> b<span class="token punctuation">.</span><span class="token function">y</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">/</span> b<span class="token punctuation">.</span><span class="token function">z</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//printf("cur pts id %d %f %f", ids[i], cur_un_pts[i].x, cur_un_pts[i].y);</span>
<span class="token punctuation">}</span>

<span class="token comment">// 2.计算每个特征点的速度到pts_velocity</span>
<span class="token comment">// caculate points velocity</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>prev_un_pts_map<span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token comment">// 2.1 地图不是空的判断是否新的点</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token keyword">double</span> dt <span class="token operator">=</span> cur_time <span class="token operator">-</span> prev_time<span class="token punctuation">;</span>
    pts_velocity<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> cur_un_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>ids<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">!=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token comment">// 2.2 通过id判断不是最新的点</span>
        <span class="token punctuation">{<!-- --></span>
            std<span class="token operator">::</span>map<span class="token operator">&lt;</span><span class="token keyword">int</span><span class="token punctuation">,</span> cv<span class="token operator">::</span>Point2f<span class="token operator">&gt;</span><span class="token operator">::</span>iterator it<span class="token punctuation">;</span><span class="token comment">// 地图的迭代器</span>
            it <span class="token operator">=</span> prev_un_pts_map<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span>ids<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 找到对应的id</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span>it <span class="token operator">!=</span> prev_un_pts_map<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// 2.3 在地图中寻找是否出现过id判断是否最新点</span>
            <span class="token punctuation">{<!-- --></span>
                <span class="token keyword">double</span> v_x <span class="token operator">=</span> <span class="token punctuation">(</span>cur_un_pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>x <span class="token operator">-</span> it<span class="token operator">-</span><span class="token operator">&gt;</span>second<span class="token punctuation">.</span>x<span class="token punctuation">)</span> <span class="token operator">/</span> dt<span class="token punctuation">;</span><span class="token comment">// 当前帧-地图点上一帧</span>
                <span class="token keyword">double</span> v_y <span class="token operator">=</span> <span class="token punctuation">(</span>cur_un_pts<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>y <span class="token operator">-</span> it<span class="token operator">-</span><span class="token operator">&gt;</span>second<span class="token punctuation">.</span>y<span class="token punctuation">)</span> <span class="token operator">/</span> dt<span class="token punctuation">;</span>
                pts_velocity<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>cv<span class="token operator">::</span><span class="token function">Point2f</span><span class="token punctuation">(</span>v_x<span class="token punctuation">,</span> v_y<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 之前出现过,push_back即可</span>

            <span class="token punctuation">}</span>
            <span class="token keyword">else</span>
                pts_velocity<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>cv<span class="token operator">::</span><span class="token function">Point2f</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 之前没出现过,先放进去但是速度为0</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">else</span>
        <span class="token punctuation">{<!-- --></span>
            pts_velocity<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>cv<span class="token operator">::</span><span class="token function">Point2f</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 是最新的点,速度为0</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
<span class="token punctuation">{<!-- --></span>
    <span class="token comment">// 如果地图是空的,速度是0</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> cur_pts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
    <span class="token punctuation">{<!-- --></span>
        pts_velocity<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>cv<span class="token operator">::</span><span class="token function">Point2f</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
 <span class="token comment">// 更新地图</span>
prev_un_pts_map <span class="token operator">=</span> cur_un_pts_map<span class="token punctuation">;</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值