1 前言
2 最後步驟分析
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
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算法就分析到這了。有很多不足,可能也分析不到位甚至有錯的地方,請批評指正。