//我们在从金字塔的图像中获取特征点时为每一个特征点计算了描述子
//现在看看如何计算一个空间的地图点的描述子
void MapPoint::ComputeDistinctiveDescriptors()
{
// Retrieve all observed descriptors
vector<cv::Mat> vDescriptors;
//获取到某一个地图点可以被哪些关键帧观测到以及在这些关键帧上与该地图点对应的特征点的编号
map<KeyFrame*,size_t> observations;
{
unique_lock<mutex> lock1(mMutexFeatures);
if(mbBad)
return;
observations=mObservations;
}
if(observations.empty())
return;
//vDescriptors用来存储这些所有与可以观测到该地图点的特征点的描述子
vDescriptors.reserve(observations.size());
for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
{
//获取可以观测到此地图点的所有关键帧
KeyFrame* pKF = mit->first;
//然后获取,在该关键帧下与该地图点对应的特征点的描述子
//vDescriptors中存储了所有的那些可以观测到该地图点的图像上的与之对应的特征点的描述子。
if(!pKF->isBad())
vDescriptors.push_back(pKF->mDescriptors.row(mit->second));
}
if(vDescriptors.empty())
return;
// Compute distances between them
const size_t N = vDescriptors.size();
//Distances是一个N*N的二维数组
float Distances[N][N];
//计算任意两个描述子之间的海明距离
//Distances[N][N]是一个对称矩阵并且对角线上的元素都为0
for(size_t i=0;i<N;i++)
{
Distances[i][i]=0;
for(size_t j=i+1;j<N;j++)
{
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
Distances[i][j]=distij;
Distances[j][i]=distij;
}
}
// Take the descriptor with least median distance to the rest
//需要找到的是一个最小的中值距离
int BestMedian = INT_MAX;
int BestIdx = 0;
for(size_t i=0;i<N;i++)
{
//将Distences中的每一行单独拿出来
//因为在这个矩阵中第i行表示,第i个描述子与其他所有描述子之间的海明距离
vector<int> vDists(Distances[i],Distances[i]+N);
//将这些距离进行排序
sort(vDists.begin(),vDists.end());
//经过排序之后都要取排序后的中值
int median = vDists[0.5*(N-1)];
//遍历Distances中的所有行找到一个最小的中值,那么该描述子就可以代表这个地图点的描述子
if(median<BestMedian)
{
BestMedian = median;
BestIdx = i;
}
}
{
unique_lock<mutex> lock(mMutexFeatures);
mDescriptor = vDescriptors[BestIdx].clone();
}
}
Take the descriptor with least median distance to the rest
就是在所有的描述子中找到那个与其他所有的描述子之间的距离的中值最小的描述子作为该地图点的描述子,
这里选择的是中值作为衡量标准。