Advertisement

计算机视觉CV 之 CMT跟踪算法分析3

阅读量:

1 前言

在最近的文章里,我们探讨了CMT这一算法的整体架构,并对其基础实现进行了深入研究。随后我们将深入探讨剩下的步骤。

2 Step 4,5,6 特征点匹配与数据融合

这些步骤主要是利用追踪和特征对应的方法来进行这一帧特征点的提取,并将其与原始图像的数据进行融合处理。

上一篇文章分析了光流,这里再分析一下特征匹配。源代码如下:

复制代码
    //Detect keypoints, compute descriptors 计算当前图像的关键点
    vector<KeyPoint> keypoints;
    detector->detect(im_gray, keypoints);
    // 计算当前图像特征点的描述
    Mat descriptors;
    descriptor->compute(im_gray, keypoints, descriptors);
    //Match keypoints globally 在全局和之前的数据库匹配特征点,计算出匹配的特征点
    vector<Point2f> points_matched_global;
    vector<int> classes_matched_global;
    matcher.matchGlobal(keypoints, descriptors, points_matched_global, classes_matched_global);
    
      
      
      
      
      
      
      
      
      
      
    
    AI写代码

主要过程在matchGlobal函数中,分析如下:

复制代码
    void Matcher::matchGlobal(const vector<KeyPoint> & keypoints, const Mat descriptors,
        vector<Point2f> & points_matched, vector<int> & classes_matched)
    {
    
    if (keypoints.size() == 0)
    {
        return;
    }
    
    vector<vector<DMatch> > matches;
    // 使用knnMatch进行特征匹配,每一个特征描述匹配最佳的2个特征
    bfmatcher->knnMatch(descriptors, database, matches, 2);
    
    for (size_t i = 0; i < matches.size(); i++)
    {
        vector<DMatch> m = matches[i];
        // 这里的distance是两个特征描述之间的距离不是点与点的距离,距离越大,匹配度越低
        float distance1 = m[0].distance / desc_length;
        float distance2 = m[1].distance / desc_length;
        int matched_class = classes[m[0].trainIdx];
    
        // 如果匹配的是背景,则跳过
        if (matched_class == -1) continue;
        // 距离要小于一个阈值0.25,表示匹配程度高,大了则跳过
        if (distance1 > thr_dist) continue;
        // 比率也要小于阈值0.8,表示匹配1比匹配2好很多,从而可以将匹配1作为最佳匹配。
        if (distance1/distance2 > thr_ratio) continue;
    
        points_matched.push_back(keypoints[i].pt);
        classes_matched.push_back(matched_class);
    }
    
    }
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    AI写代码

上面的距离是Hamming距离:

这里写图片描述

距离越小,表示匹配程度越高。

接下来是融合跟踪和匹配的点,分析代码如下:

复制代码
    //Fuse tracked and globally matched points
    //融合跟踪和匹配的点 将两种点都放在一起,并且不重复
    vector<Point2f> points_fused;
    vector<int> classes_fused;
    fusion.preferFirst(points_tracked, classes_tracked, points_matched_global, classes_matched_global,
            points_fused, classes_fused);
    
    
      
      
      
      
      
      
      
    
    AI写代码

主要逻辑集中在 preferFirst 函数内部。其主要目标是确保不会在同一时间窗口内多次插入同一特征点这一设计思路较为直观易懂

复制代码
    void Fusion::preferFirst(const vector<Point2f> & points_first, const vector<int> & classes_first,
    const vector<Point2f> & points_second, const vector<int> & classes_second,
    vector<Point2f> & points_fused, vector<int> & classes_fused)
    {
    
    points_fused = points_first;
    classes_fused = classes_first;
    
    // 目的是不重复添加相同的特征点
    for (size_t i = 0; i < points_second.size(); i++)
    {
        int class_second = classes_second[i];
    
        bool found = false;
        for (size_t j = 0; j < points_first.size(); j++)
        {
            int class_first = classes_first[j];
            if (class_first == class_second) found = true;
        }
    
        if (!found)
        {
            points_fused.push_back(points_second[i]);
            classes_fused.push_back(class_second);
        }
    
    }
    
    }
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    AI写代码

3 Step 8,9 估计缩放比率和旋转角度

首先探讨如何进行计算的问题时会发现这个原理并不复杂它指的是在初始阶段我们已经存储了标准化的特征点points_normalized通过计算每对点之间的相对距离与相对角度其本质就是将复杂的几何关系简化为可量化的指标这一思路可见上文图示部分具体的代码实现如下

复制代码
    for (size_t i = 0; i < num_points; i++)
    {
        for (size_t j = 0; j < num_points; j++)
        {
            Point2f v = points_normalized[i] - points_normalized[j];
    
            float distance = norm(v);
            float angle = atan2(v.y,v.x);
    
            distances_pairwise.at<float>(i,j) = distance;
            angles_pairwise.at<float>(i,j) = angle;
        }
    
    }
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    AI写代码

同样地,在处理新增的特征点时,我们也会计算其相对间距及角度,并通过与原始数据进行差值运算来获得变化量。最终取这些数值的中位数来确定整体缩放比例以及旋转参数。

复制代码
    void Consensus::estimateScaleRotation(const vector<Point2f> & points, const vector<int> & classes,
        float & scale, float & rotation)
    {
    
    //Compute pairwise changes in scale/rotation
    // 从缩放和旋转尺度上计算Pairwise改变
    vector<float> changes_scale;
    if (estimate_scale) changes_scale.reserve(points.size()*points.size());
    vector<float> changes_angles;
    if (estimate_rotation) changes_angles.reserve(points.size()*points.size());
    
    for (size_t i = 0; i < points.size(); i++)
    {
        for (size_t j = 0; j < points.size(); j++)
        {
            if (classes[i] != classes[j])
            {
                // 计算任何两个特征点的相对位置
                Point2f v = points[i] - points[j];
    
                if (estimate_scale)
                {
                    // 计算距离
                    float distance = norm(v);
                    // 获取特征点的初始距离
                    float distance_original = distances_pairwise.at<float>(classes[i],classes[j]);
                    // 相除得到改变的比率
                    float change_scale = distance / distance_original;
                    changes_scale.push_back(change_scale);
                }
    
                if (estimate_rotation)
                {
                    // 计算相对角度
                    float angle = atan2(v.y,v.x);
                    // 计算初始角度
                    float angle_original = angles_pairwise.at<float>(classes[i],classes[j]);
                    // 计算角度改变
                    float change_angle = angle - angle_original;
    
                    //Fix long way angles
                    if (fabs(change_angle) > M_PI) {
                        change_angle = sgn(change_angle) * 2 * M_PI + change_angle;
                    }
    
                    changes_angles.push_back(change_angle);
                }
            }
    
        }
    
    }
    
    //Do not use changes_scale, changes_angle after this point as their order is changed by median()
    // 计算中位数作为结果
    if (changes_scale.size() < 2) scale = 1;
    else scale = median(changes_scale);
    
    if (changes_angles.size() < 2) rotation = 0;
    else rotation = median(changes_angles);
    
    }
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    AI写代码

时间关系,先分析到缩放和旋转这一步,下一篇文章分析CMT最后几步。

本文为原创文章,转载请注明出处:<>

全部评论 (0)

还没有任何评论哟~