Consensus-based Matching and Tracking of Keypoints for Object Tracking

基于特征点的目标跟踪算法,加入了投票算法,原理比较简单,算法流程如图所示。

Consensus-based Matching and Tracking of Keypoints for Object Tracking_第1张图片
Step1:在样本图像检测Keypoint,根据人工选择的区域划分前景Keypoint与背景Keypoint,分别计算相应的描述子descriptor,存储在feature的数据库的矩阵中。
Step2:给前景Keypoint分配从1开始的序列号,给背景Keypoint分配成统一的0序列号。并将它们存在class分类(前景)数据库的向量(矩阵)中。同时Keypoint中包含该点图像中的绝对坐标系中的位置。
Step3:进入循环(主要是初步选取活动的Keypoint和根据评估投票结果精选Keypoint和一些运动信息)
Step4: 初选Keypoint分为Track和Match的两个过程:(实际代码中与上述算法有所出入,这里先讲述上述算法)
在当前图像帧中检测Keypoint;
Step5:计算当前Keypoint与样本图像中的所有Keypoint(含前景与背景)的特征的距离或等同量,特征匹配程度较高的Keypoint作为Active Keypoint,即有效Keypoint。
Step6:
Track 过程:光流法计算相邻图像帧的关键点移动情况,倘若前向计算与后向计算结果相差不大且没有离开图像视野,则认为该点为active Keypoint;
Step7:合并上述的active Keypoint;
Step8: 根据Active Keypoint之间的距离和相应的样本中Keypoint之间的距离的比例,计算相应的尺寸变化的比例向量,取其中值。
Step9:类似的得到旋转角度。
Step10:根据样本Keypoint与目标中心之间的偏移,和已得到的尺寸变化,角度变化,将Active Keypoint的坐标点转换成新目标(待选)中心点(由于Active Keypoint可能产生错动,转换成新的对应目标中心点亦存在偏差,这正是引入投票决策的原因)
Step11-14:基于大部分Keypoint偏差较小的假设,因此大部分目标(待选)中心点都会指向实际中心附近,因此它们会聚集在较小的区域。这里采用自下而上的聚类的方法,将待选中心点聚类。其中某类数目最多而且占总体比例较高,则认为该类是指向实际新中心附近的,计算它们的中心,认为新的目标中心点。
Step15:根据新的目标中心点和之前得到的变形参数,确定新的目标边界。
Step11-14中自下而上的聚类方法和统计各类参数等处的编程代码质量较高。粘出来



//该段函数主要用于将坐标点集合根据之间的距离大小聚类
std::vector linkage(const std::vector& list)
{
    float inf = 10000000;0;
    std::vector used;
    for(int i = 0; i < 2*list.size(); i++)
        used.push_back(false);
    std::vector > dist;
//以下实际构建2n*2n的矩阵(其中n为数据点数目)
//其中只有n*n的左上角的矩阵块存储了两个点的之间的距离,由于坐标点本身之间不存在聚类,不纳入考虑范围之内,
//因此对角线上的元素为无穷大(我们要在矩阵中不断寻找最小距离然后聚类,因此无穷大可以避免这种原本不存在的情况)
    for(int i = 0; i < list.size(); i++)
    {
        std::vector line;
        for(int j = 0; j < list.size(); j++)
        {
            if(i == j)
                line.push_back(inf);
            else
            {
                cv::Point2f p = list[i]-list[j];
                line.push_back(sqrt(p.dot(p)));
            }
        }
        for(int j = 0; j < list.size(); j++)
            line.push_back(inf);
        dist.push_back(line);
    }
    for(int i = 0; i < list.size(); i++)
    {
        std::vector line;
        for(int j = 0; j < 2*list.size(); j++)
            line.push_back(inf);
        dist.push_back(line);
    }
//下面进行正式聚类,这一段要和findMinSymetric子函数一起看。
//主要思想为:以第一次聚类来看,取当前矩阵中的中最小的距离的两个点作为一类,一旦作为一类之后,原先的距离矩阵的距离立即作废,标记为used,同时计算其他的点到该类中的最小距离(这里该类只有两个点,即两个距离中的较小值),而这两个点到该类的距离应再次标为无穷大。这也是为什么事先给的距离矩阵是个2n*2n的矩阵的原因,用于存储类与类(或者点与类的距离),每次只能减少一个点或者一个类,这样总共需要减少n次才能将所有点聚类。同时记录该类中数目,用于将来比较。
    std::vector clusters;
    while(clusters.size() < list.size()-1)
    {
        int x, y;
        float min = findMinSymetric(dist, used, list.size()+clusters.size(), x, y);
        Cluster cluster;
        cluster.first = x;
        cluster.second = y;
        cluster.dist = min;
        cluster.num = (x < list.size() ? 1 : clusters[x-list.size()].num) + (y < list.size() ? 1 : clusters[y-list.size()].num);
        used[x] = true;
        used[y] = true;
        int limit = list.size()+clusters.size();
        for(int i = 0; i < limit; i++)
        {
            if(!used[i])
                dist[i][limit] = dist[limit][i] = std::min(dist[i][x], dist[i][y]);
        }
        clusters.push_back(cluster);
    }
    return clusters;
}

float findMinSymetric(const std::vector >& dist, const std::vector& used, int limit, int &i, int &j)
{
    float min = dist[0][0];
    i = 0;
    j = 0;
    for(int x = 0; x < limit; x++)
    {
        if(!used[x])
        {
            for(int y = x+1; y < limit; y++)
                if(!used[y] && dist[x][y] <= min)
                {
                    min = dist[x][y];
                    i = x;
                    j = y;
                }
        }
    }
    return min;
}
//根据要求的距离阈值,对坐标点标记类的ID号,思想为:往每一个数据点上挨个标记ID,距离过近的两类认为是同一类。这里使用了递归的方法,递归的目的寻找所有的坐标点
void fcluster_rec(std::vector& data, const std::vector& clusters, float threshold, const Cluster& currentCluster, int& binId)
{
    int startBin = binId;
    if(currentCluster.first >= data.size())
        fcluster_rec(data, clusters, threshold, clusters[currentCluster.first - data.size()], binId);
    else data[currentCluster.first] = binId;

    if(startBin == binId && currentCluster.dist >= threshold)
        binId++;
    startBin = binId;

    if(currentCluster.second >= data.size())
        fcluster_rec(data, clusters, threshold, clusters[currentCluster.second - data.size()], binId);
    else data[currentCluster.second] = binId;

    if(startBin == binId && currentCluster.dist >= threshold)
        binId++;
}
std::vector fcluster(const std::vector& clusters, float threshold)
{
    std::vector data;
    for(int i = 0; i < clusters.size()+1; i++)
        data.push_back(0);
    int binId = 0;
    fcluster_rec(data, clusters, threshold, clusters[clusters.size()-1], binId);
    return data;
}

std::vector binCount(const std::vector& T)
{
    std::vector result;
    for(int i = 0; i < T.size(); i++)
    {
        while(T[i] >= result.size())
            result.push_back(0);
        result[T[i]]++;
    }
    return result;
}



你可能感兴趣的:(Consensus-based Matching and Tracking of Keypoints for Object Tracking)