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

1 前言

在上一篇文章中,我对CMT算法做了初步的介绍,并且初步分析了一下CppMT的代码,在本篇文章中,我将结合作者的论文更全面细致的分析CMT算法。

这里先说明一下,作者关于CMT算法写了两篇文章:

Consensus-based Matching and Tracking of Keypoints for Object Tracking (wacv2014 best paper reward)

Clustering of Static-Adaptive Correspondences for Deformable Object Tracking (cvpr 2015)

其中wacv的文章从更工程的角度来分析CMT的算法,写出来其详细的流程,比较推荐阅读。

2 CMT 算法流程

这里我直接截取了文章中的原图。

我把它翻译一下:

算法 CMT

输入: 视频帧,初始的物体框

输出:每一帧视频的物体框

要求:后继的物体框能够保持框住初始框框住的物体

步骤:

Step 1:检测初始视频帧的所有特征点和特征描述,不仅仅是框内的点而是整个图像的点,所以在代码中可以看到,初始的database数据库的特征描述包含了前景(框内)和背景(框外)的特征

Step 2:将初始框内的特征描述赋给K1

Step 3:从第二帧开始

Step 4:检测视频帧的特征点P

Step 5:将特征点P与O匹配,获取匹配的特征点M

Step 6:利用上一帧的特征点使用光流法跟踪得到这一帧的特征点的位置T

Step 7:融合特征点M和特征点T得到这一帧的总的特征点K’

Step 8:根据K’估计特征点相对初始帧特征的缩放比例

Step 9:根据K’估计特征点相对初始帧特征的旋转比例

Step 10:根据Step7,8,9得到的数据计算每一个特征点的Vote

Step 11:采用聚类的方法选取最大的类也就是最一致的VoteC

Step 12:将VoteC转换回特征点得到最后这一帧的有效特征点

Step 13:判断VoteC的长度是否大于最小阈值,如果是则计算最后新的旋转矩形框的参数,如果不是也就是框太小了则输出0

下面结合代码及论文分析每一步

Step 1,2 初始化

在CMT.cpp的代码中可以比较清晰的理解,就是使用openCV的Fast或者BRISK特征检测及特征描述。然后关键是存储有效的数据在数据库用于之后的匹配,主要在以下两个代码

    //Initialize matcher 初始化匹配器
    matcher.initialize(points_normalized, descs_fg, classes_fg, descs_bg, center);

    //Initialize consensus 初始化一致器
    consensus.initialize(points_normalized);

进去看一下细节:

void Matcher::initialize(const vector<Point2f> & pts_fg_norm, const Mat desc_fg, const vector<int> & classes_fg,
        const Mat desc_bg, const Point2f center)
{

    //Copy normalized points 存储 正规化的点
    this->pts_fg_norm = pts_fg_norm;

    //Remember number of background points 存储背景的特征点的数量
    this->num_bg_points = desc_bg.rows;

    //Form database by stacking background and foreground features
    // 合成前景和背景的特征到一个Mat文件中
    if (desc_bg.rows > 0 && desc_fg.rows > 0)
        vconcat(desc_bg, desc_fg, database);
    else if (desc_bg.rows > 0)
        database = desc_bg;
    else
        database = desc_fg;

    //Extract descriptor length from features 根据特征抽取描述其长度
    desc_length = database.cols*8;

    // classes的作用就是为了对应找到的特征,从而可以知道上一帧的特征位置计算一致性
    //Create background classes (-1) 创建背景索引
    vector<int> classes_bg = vector<int>(desc_bg.rows,-1);

    //Concatenate fg and bg classes 连接前景和背景的索引
    classes = classes_bg;
    classes.insert(classes.end(), classes_fg.begin(), classes_fg.end());

    //Create descriptor matcher 创建描述匹配器BruteForce-Hamming
    bfmatcher = DescriptorMatcher::create("BruteForce-Hamming");

}
void Consensus::initialize(const vector<Point2f> & points_normalized)
{

    //Copy normalized points 复制正规化的点
    this->points_normalized = points_normalized;

    size_t num_points = points_normalized.size();

    //Create matrices of pairwise distances/angles 创建矩阵用于计算任何两个点之间的距离和角度
    distances_pairwise = Mat(num_points, num_points, CV_32FC1);
    angles_pairwise = Mat(num_points, num_points, CV_32FC1);

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

    }

}

那么特征的角度距离是按下图意思计算的,我想对应一下代码还是很好理解的:

接下来分析Step 3,4,5,6.

Step 3,4,5,6 分析

关键是跟踪和匹配

在processFrame函数中可以看到。

跟踪使用:

    //Track keypoints
    vector<Point2f> points_tracked;
    vector<unsigned char> status;
    // 利用光流法计算关键点的当前位置。
    tracker.track(im_prev, im_gray, points_active, points_tracked, status);

深入查看代码发现作者使用了双向的跟踪:

void Tracker::track(const Mat im_prev, const Mat im_gray, const vector<Point2f> & points_prev,
        vector<Point2f> & points_tracked, vector<unsigned char> & status)
{

    if (points_prev.size() > 0)
    {
        vector<float> err; //Needs to be float

        //Calculate forward optical flow for prev_location 计算前向位置的光流(即特征点的移动)
        calcOpticalFlowPyrLK(im_prev, im_gray, points_prev, points_tracked, status, err);

        vector<Point2f> points_back;
        vector<unsigned char> status_back;
        vector<float> err_back; //Needs to be float

        //Calculate backward optical flow for prev_location 计算后向光流
        calcOpticalFlowPyrLK(im_gray, im_prev, points_tracked, points_back, status_back, err_back);

        //Traverse vector backward so we can remove points on the fly 删除掉飞掉的点
        for (int i = points_prev.size()-1; i >= 0; i--)
        {
            float l2norm = norm(points_back[i] - points_prev[i]);

            bool fb_err_is_large = l2norm > thr_fb;

            if (fb_err_is_large || !status[i] || !status_back[i])
            {
                points_tracked.erase(points_tracked.begin() + i);

                //Make sure the status flag is set to 0
                status[i] = 0;
            }

        }

    }

}

基本的思路就是先使用上一帧的特征点points_prev通过光流计算这一帧的对应位置points_tracked,然后反过来使用points_tracked计算对应的上一帧的位置points_back,然后对比points_prev和points_back之间的距离,按道理应该是接近0才对,但是因为光流计算有误差,因此,有的可能比较大,因此作者设置了一个阈值thr_fb 30,如果大于该阈值,表示得到的数据有误,删掉该点。

这么做的目的是为了使跟踪得到的结果更可靠。

由于时间关系,本文先分析到这。下一篇文章分析接下来的步骤。

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

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

时间: 2024-11-12 04:32:16

计算机视觉CV 之 CMT跟踪算法分析二的相关文章

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

1 前言 在上一篇blog中,我们分析了CMT的整体算法流程及前面几步的实现分析,接下来我们继续分析后面的几步. 2 Step 4,5,6 特征点匹配与数据融合 这几步就是通过跟踪和特征匹配来获取这一帧的特征点,将两者融合在一起. 上一篇文章分析了光流,这里再分析一下特征匹配.源代码如下: //Detect keypoints, compute descriptors 计算当前图像的关键点 vector<KeyPoint> keypoints; detector->detect(im_g

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

1 前言 在上一部分我们已经分析到了计算特征点的缩放和旋转,这里最后分析去掉不好的特征点的方法. 2 最后步骤分析 vote的基本思想就是这些特征点相对中心的相对距离在把缩放旋转考虑进去之后是相对不变的,也就是按道理下一帧的特征点相对中心的位置是不变的. 但是由于图像本身的变化,不可能得到完全一样的相对位置,这个时候,有一些会离中心近,有一些会偏差很大.那么,作者就采用聚类的方法,选择最大的一类作为最好的特征点.其他的不要. 上面这个图应该可以很好的理解这个过程.再看作者自己官网上的图大家应该可

[转载+原创]Emgu CV on C# (五) —— Emgu CV on 局部自适应阈值二值化

局部自适应阈值二值化 相对全局阈值二值化,自然就有局部自适应阈值二值化,本文利用Emgu CV实现局部自适应阈值二值化算法,并通过调节block大小,实现图像的边缘检测. 一.理论概述(转载自<OpenCV_基于局部自适应阈值的图像二值化>) 局部自适应阈值则是根据像素的邻域块的像素值分布来确定该像素位置上的二值化阈值.这样做的好处在于每个像素位置处的二值化阈值不是固定不变的,而是由其周围邻域像素的分布来决定的.亮度较高的图像区域的二值化阈值通常会较高,而亮度较低的图像区域的二值化阈值则会相适

自然语言处理(nlp)比计算机视觉(cv)发展缓慢,而且更难!

https://mp.weixin.qq.com/s/kWw0xce4kdCx62AflY6AzQ 1.  抢跑的nlp nlp发展的历史非常早,因为人从计算机发明开始,就有对语言处理的需求.各种字符串算法都贯穿于计算机的发展历史中.伟大的乔姆斯基提出了生成文法,人类拥有的处理语言的最基本框架,自动机(正则表达式),随机上下文无关分析树,字符串匹配算法KMP,动态规划. nlp任务里如文本分类,成熟的非常早,如垃圾邮件分类等,用朴素贝叶斯就能有不错的效果.20年前通过纯统计和规则都可以做机器翻译

【计算机视觉】粒子滤波跟踪

粒子滤波步骤 1.初始化随机选取N个点,权重统一赋值1/N 2.选取目标特征,颜色直方图等等,用于获取先验概率密度,对比相似度 3.确定状态转移矩阵,用于预测下一帧目标位置 循环开始 4.根据状态转移矩阵,对每个粒子,预测目标新位置 5.获得系统观测值,计算观测位置处特征 6.计算每个预测位置处特征,与观测处位置特征对比,相似度高的赋予较大的权重,反之,赋予较小的权重 7.对粒子加权获取当前的目标最佳位置 8.粒子重采样 循环结束 上面是我自己的理解,有些问题仍然不明白: 1.都有观测值了还修正

计算机视觉 之 在iOS上测试跟踪算法Visual Object Tracking Algorithm

前言 在计算机视觉CV领域,视觉跟踪是其中一个重要的子问题.从我的角度看,视觉跟踪就是用在机器人上,用在移动设备上,因此,何不把一些跟踪算法放在iPhone上看看实际的跟踪效果.这才是最真实的对比,使用一些视频毕竟不实际,而且关键是不能很好的对比实时性.对于移动设备而已,实时性是最重要的吧.之所以有跟踪问题的出现,也是因为绝大多数的物体检测Object Detection算法实在是太慢了,根本无法用在视频当中.因此才有了Object Tracking的问题.最终的目标也就是Real Time V

[转]计算机视觉与图像处理、模式识别、机器学习学科之间的关系

在我的理解里,要实现计算机视觉必须有图像处理的帮助,而图像处理倚仗与模式识别的有效运用,而模式识别是人工智能领域的一个重要分支,人工智能与机器学习密不可分.纵观一切关系,发现计算机视觉的应用服务于机器学习.各个环节缺一不可,相辅相成. 计算机视觉(computer vision),用计算机来模拟人的视觉机理获取和处理信息的能力.就是是指用摄影机和电脑代替人眼对目标进行识别.跟踪和测量等机器视觉,并进一步做图形处理,用电脑处理成为更适合人眼观察或传送给仪器检测的图像.计算机视觉研究相关的理论和技术

3直方图与二值化,图像梯度

1直方图 #直方图--增强对比度 def equalHist_demo(image): gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) dst = cv.equalizeHist(gray) cv.imshow("equalHist_demo", dst) def clahe_demo(image): gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) clahe = cv.createCLAHE(clip

安卓实现个性彩色好看的二维码

前言 二维码以前也写过好几篇,今天姑且是对以前知识的总结,顺便复习一下,圣人说过:温故知新. 还是和以前一样先看下效果,再来对着代码讲解. 看效果图: 之前呢,也写过用安卓实现二维码生成彩色的二维码和带logo的二维码,也知道可以使用QRCode和ZXing两种方式,然后这一篇呢也是写二维码使用BarcodeFormat.QR_CODE,主要也是看见很多的非常漂亮的二维码,这里呢主要模仿qq的二维码,并且也高仿实现了长按发送给朋友和保存到图库的功能,觉得不错呢就请多支持下,哪里不好呢也可以说出来