码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-08-21 11:27:41      阅读:309      评论:0      收藏:0      [点我收藏+]

标签:计算机视觉   算法   cmt   

1 前言

在上一篇blog中,我们分析了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);

主要过程在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);
    }

}

上面的距离是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);

核心代码在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);
        }

    }

}

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

首先就如何计算的问题,这个其实原理非常简单,就是一开始我们已经存储了初始的特征点,而且是正规化的特征点points_normalized,先计算两两之间的相对距离和相对角度,具体思想见上一篇blog的图,初始的代码如下:

    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;
        }

    }

那么对于新的特征点,同样也是计算他们的相对距离和相对角度,并与初始的数据相除或相减,就得到变化。
最后取他们的中位数作为整体的缩放比率和旋转。
代码如下:

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);

}

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

本文为原创文章,转载请注明出处:https://blog.csdn.net/songrotek

版权声明:本文为博主原创文章,未经博主允许不得转载。

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

标签:计算机视觉   算法   cmt   

原文地址:http://blog.csdn.net/songrotek/article/details/47830463

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!