Advertisement

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

阅读量:

1 前言

在上一部分我们已经探讨了计算特征点时涉及的缩放与旋转处理,在这一部分我们进一步探讨如何去除不良特征点的方法。

2 最后步骤分析

vote的核心理念就是这些关键特征点相对于中心的相对位置在经过缩放和旋转处理后保持稳定不变;从理论上讲,在下一帧中这些关键特征点相对于中心的位置应当保持一致。

然而受图像自身变化的影响[公式...]无法达到完全一致的相对位置[标点]此时一些点离中心区域较近[标点]另一些则偏离较大[标点]为此作者采用了聚类分析的方法[标点]将占据数据最大比例的一类归为最佳特征点集合[标点]其余数据不再考虑

上面这个图可以帮助很好地理解这个过程。另外看看作者自己官网上的图吧,大家也可以试着理解和掌握它。

代码上作者找了一个聚类的库来做,具体我没有深入分析了:

复制代码
 void Consensus::findConsensus(const vector<Point2f> & points, const vector<int> & classes,

    
     const float scale, const float rotation,
    
     Point2f & center, vector<Point2f> & points_inlier, vector<int> & classes_inlier)
    
 {
    
  
    
     //If no points are available, reteurn nan
    
     if (points.size() == 0)
    
     {
    
     center.x = numeric_limits<float>::quiet_NaN();
    
     center.y = numeric_limits<float>::quiet_NaN();
    
  
    
     return;
    
     }
    
  
    
     //Compute votes 计算投票:基本方法就是计算点相对于正规化且计算其旋转加缩放后的点的相对位置 保持相对一致
    
     vector<Point2f> votes(points.size());
    
     for (size_t i = 0; i < points.size(); i++)
    
     {
    
     votes[i] = points[i] - scale * rotate(points_normalized[classes[i]], rotation);
    
     }
    
  
    
     t_index N = points.size();
    
  
    
     float * D = new float[N*(N-1)/2]; //This is a lot of memory, so we put it on the heap
    
     cluster_result Z(N-1);
    
  
    
     //Compute pairwise distances between votes
    
     //计算votes点之间的相对距离
    
     int index = 0;
    
     for (size_t i = 0; i < points.size(); i++)
    
     {
    
     for (size_t j = i+1; j < points.size(); j++)
    
     {
    
         //TODO: This index calculation is correct, but is it a good thing?
    
         //int index = i * (points.size() - 1) - (i*i + i) / 2 + j - 1;
    
         // 计算相对距离
    
         D[index] = norm(votes[i] - votes[j]);
    
         index++;
    
     }
    
     }
    
  
    
     MST_linkage_core(N,D,Z);
    
  
    
     union_find nodes(N);
    
  
    
     //Sort linkage by distance ascending
    
     std::stable_sort(Z[0], Z[N-1]);
    
  
    
     //S are cluster sizes
    
     int * S = new int[2*N-1];
    
     //TODO: Why does this loop go to 2*N-1? Shouldn't it be simply N? Everything > N gets overwritten later
    
     for(int i = 0; i < 2*N-1; i++)
    
     {
    
     S[i] = 1;
    
     }
    
  
    
     t_index parent = 0; //After the loop ends, parent contains the index of the last cluster
    
     for (node const * NN=Z[0]; NN!=Z[N-1]; ++NN)
    
     {
    
     // Get two data points whose clusters are merged in step i.
    
     // Find the cluster identifiers for these points.
    
     t_index node1 = nodes.Find(NN->node1);
    
     t_index node2 = nodes.Find(NN->node2);
    
  
    
     // Merge the nodes in the union-find data structure by making them
    
     // children of a new node
    
     // if the distance is appropriate
    
     if (NN->dist < thr_cutoff)
    
     {
    
         parent = nodes.Union(node1, node2);
    
         S[parent] = S[node1] + S[node2];
    
     }
    
     }
    
  
    
     //Get cluster labels
    
     int * T = new int[N];
    
     for (t_index i = 0; i < N; i++)
    
     {
    
     T[i] = nodes.Find(i);
    
     }
    
  
    
     //Find largest cluster
    
     int S_max = distance(S, max_element(S, S + 2*N-1));
    
  
    
     //Find inliers, compute center of votes
    
     points_inlier.reserve(S[S_max]);
    
     classes_inlier.reserve(S[S_max]);
    
     center.x = center.y = 0;
    
  
    
     for (size_t i = 0; i < points.size(); i++)
    
     {
    
     //If point is in consensus cluster
    
     if (T[i] == S_max)
    
     {
    
         points_inlier.push_back(points[i]);
    
         classes_inlier.push_back(classes[i]);
    
         center.x += votes[i].x;
    
         center.y += votes[i].y;
    
     }
    
  
    
     }
    
  
    
     center.x /= points_inlier.size();
    
     center.y /= points_inlier.size();
    
  
    
     delete[] D;
    
 	delete[] S;
    
 	delete[] T;
    
  
    
 }

通过这样的算法得到inlier

随后,在代码实现中,
作者又进行了进一步的操作,
即调用matchlocal函数,
从我的角度来看,
其目的与findconsensus一致,
都是基于两点之间的距离来判断是否属于关键特征。
随后,
会对这些关键特征进行一次额外匹配,
满足条件后才会被选入结果集合。
最后,
将属于inlier类别的点与matchlocal的结果进行整合,
从而得到最终的关键特征集合。

matchlocal的代码如下:

复制代码
 void Matcher::matchLocal(const vector<KeyPoint> & keypoints, const Mat descriptors,

    
     const Point2f center, const float scale, const float rotation,
    
     vector<Point2f> & points_matched, vector<int> & classes_matched)
    
 {
    
  
    
     if (keypoints.size() == 0) {
    
     return;
    
     }
    
  
    
     //Transform initial points
    
     vector<Point2f> pts_fg_trans;
    
     pts_fg_trans.reserve(pts_fg_norm.size());
    
     for (size_t i = 0; i < pts_fg_norm.size(); i++)
    
     {
    
     // 同样是计算相对位置
    
     pts_fg_trans.push_back(scale * rotate(pts_fg_norm[i], -rotation));
    
     }
    
  
    
     //Perform local matching
    
     for (size_t i = 0; i < keypoints.size(); i++)
    
     {
    
     //Normalize keypoint with respect to center
    
     Point2f location_rel = keypoints[i].pt - center;
    
  
    
     //Find potential indices for matching
    
     vector<int> indices_potential;
    
     for (size_t j = 0; j < pts_fg_trans.size(); j++)
    
     {
    
         // 计算位置偏差
    
         float l2norm = norm(pts_fg_trans[j] - location_rel);
    
  
    
         // 设置一个阈值
    
         if (l2norm < thr_cutoff) {
    
             indices_potential.push_back(num_bg_points + j);
    
         }
    
  
    
     }
    
  
    
     //If there are no potential matches, continue
    
     if (indices_potential.size() == 0) continue;
    
  
    
     //Build descriptor matrix and classes from potential indices
    
     Mat database_potential = Mat(indices_potential.size(), database.cols, database.type());
    
     for (size_t j = 0; j < indices_potential.size(); j++) {
    
         database.row(indices_potential[j]).copyTo(database_potential.row(j));
    
     }
    
  
    
     //Find distances between descriptors
    
     vector<vector<DMatch> > matches;
    
     // 对选出的特征点进行特征匹配
    
     bfmatcher->knnMatch(descriptors.row(i), database_potential, matches, 2);
    
  
    
     vector<DMatch> m = matches[0];
    
  
    
     float distance1 = m[0].distance / desc_length;
    
     float distance2 = m.size() > 1 ? m[1].distance / desc_length : 1;
    
  
    
     if (distance1 > thr_dist) continue;
    
     if (distance1/distance2 > thr_ratio) continue;
    
  
    
     int matched_class = classes[indices_potential[m[0].trainIdx]];
    
  
    
     points_matched.push_back(keypoints[i].pt);
    
     classes_matched.push_back(matched_class);
    
     }
    
  
    
 }

到此为止了呢?因为时间有限嘛,CMT算法就到这里吧。存在一些不足之处哦,并且可能存在某些不足或错误的地方呢,请各位多多包涵和指导哦!

文章原创,转载麻烦注明出处:blog..net/songrotek

全部评论 (0)

还没有任何评论哟~