您的位置:首页 > 移动开发 > Objective-C

Consensus-based Matching and Tracking of Keypoints for Object Tracking

2015-04-18 20:33 543 查看
基于特征点的目标跟踪算法,加入了投票算法,原理比较简单,算法流程如图所示。



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<Cluster> linkage(const std::vector<cv::Point2f>& list)
{
float inf = 10000000;0;
std::vector<bool> used;
for(int i = 0; i < 2*list.size(); i++)
used.push_back(false);
std::vector<std::vector<float> > dist;
//以下实际构建2n*2n的矩阵(其中n为数据点数目)
//其中只有n*n的左上角的矩阵块存储了两个点的之间的距离,由于坐标点本身之间不存在聚类,不纳入考虑范围之内,
//因此对角线上的元素为无穷大(我们要在矩阵中不断寻找最小距离然后聚类,因此无穷大可以避免这种原本不存在的情况)
for(int i = 0; i < list.size(); i++)
{
std::vector<float> 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<float> 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<Cluster> 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;
}
<pre name="code" class="cpp">

float findMinSymetric(const std::vector<std::vector<float> >& dist, const std::vector<bool>& 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<int>& data, const std::vector<Cluster>& 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<int> fcluster(const std::vector<Cluster>& clusters, float threshold)
{
std::vector<int> 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<int> binCount(const std::vector<int>& T)
{
std::vector<int> result;
for(int i = 0; i < T.size(); i++)
{
while(T[i] >= result.size())
result.push_back(0);
result[T[i]]++;
}
return result;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐