ORB2单目读代码笔记13--卡方检验原理及其在ORB-SLAM2中的用处_不能再吃了OvO的博客-CSDN博客_orbslam 卡方检验
卡方检验详解分析与实例_bitcarmanlee的博客-CSDN博客_卡方检验例题与解析
cvlife
Version:0.9 StartHTML:0000000105 EndHTML:0000004169 StartFragment:0000000141 EndFragment:0000004129
LocalMapping.cc
// Step 6.6:计算3D点在当前关键帧下的重投影误差
const float &sigmaSquare1 = mpCurrentKeyFrame->mvLevelSigma2[kp1.octave];
const float x1 = Rcw1.row(0).dot(x3Dt)+tcw1.at(0);
const float y1 = Rcw1.row(1).dot(x3Dt)+tcw1.at(1);
const float invz1 = 1.0/z1;
if(!bStereo1)
{
// 单目情况下
float u1 = fx1*x1*invz1+cx1;
float v1 = fy1*y1*invz1+cy1;
float errX1 = u1 - kp1.pt.x;
float errY1 = v1 - kp1.pt.y;
// 假设测量有一个像素的偏差,2自由度卡方检验阈值是5.991
if((errX1*errX1+errY1*errY1)>5.991*sigmaSquare1)
continue;
}
else
{
// 双目情况
float u1 = fx1*x1*invz1+cx1;
// 根据视差公式计算假想的右目坐标
float u1_r = u1 - mpCurrentKeyFrame->mbf*invz1;
float v1 = fy1*y1*invz1+cy1;
float errX1 = u1 - kp1.pt.x;
float errY1 = v1 - kp1.pt.y;
float errX1_r = u1_r - kp1_ur;
// 自由度为3,卡方检验阈值是7.8
if((errX1*errX1+errY1*errY1+errX1_r*errX1_r)>7.8*sigmaSquare1)
continue;
}
B站5小时orbslam
CheckFundamental()
、CheckHomography()
卡方检验通过构造检验统计量
来比较期望结果和实际结果之间的差别,从而得出观察频数极值的发生概率.
根据重投影误差构造统计量
,其值越大,观察结果和期望结果之间的差别越显著,某次计算越可能用到了外点.
统计量置信度阈值与被检验变量自由度有关: 单目特征点重投影误差的自由度为2
(u
,v
),双目特征点重投影误差自由度为3
(u
,v
,ur
).
取95%置信度下的卡方检验统计量阈值
0
.
float Initializer::CheckHomography(const cv::Mat &H21, const cv::Mat &H12,vector &vbMatchesInliers, float sigma) {
const int N = mvMatches12.size();
// 取出单应矩阵H各位上的值
const float h11 = H21.at(0, 0);
const float h12 = H21.at(0, 1);
const float h13 = H21.at(0, 2);
const float h21 = H21.at(1, 0);
const float h22 = H21.at(1, 1);
const float h23 = H21.at(1, 2);
const float h31 = H21.at(2, 0);
const float h32 = H21.at(2, 1);
const float h33 = H21.at(2, 2);
const float h11inv = H12.at(0, 0);
const float h12inv = H12.at(0, 1);
const float h13inv = H12.at(0, 2);
const float h21inv = H12.at(1, 0);
const float h22inv = H12.at(1, 1);
const float h23inv = H12.at(1, 2);
const float h31inv = H12.at(2, 0);
const float h32inv = H12.at(2, 1);
const float h33inv = H12.at(2, 2);
vbMatchesInliers.resize(N); // 标记是否是内点
float score = 0; // 置信度得分
const float th = 5.991; // 自由度为2,显著性水平为0.05的卡方分布对应的临界阈值
const float invSigmaSquare = 1.0 / (sigma * sigma); // 信息矩阵,方差平方的倒数
// 双向投影,计算加权投影误差
for (int i = 0; i < N; i++) {
bool bIn = true;
// step1. 提取特征点对
const cv::KeyPoint &kp1 = mvKeys1[mvMatches12[i].first];
const cv::KeyPoint &kp2 = mvKeys2[mvMatches12[i].second];
const float u1 = kp1.pt.x;
const float v1 = kp1.pt.y;
const float u2 = kp2.pt.x;
const float v2 = kp2.pt.y;
// step2. 计算img2到img1的重投影误差
const float w2in1inv = 1.0 / (h31inv * u2 + h32inv * v2 + h33inv);
const float u2in1 = (h11inv * u2 + h12inv * v2 + h13inv) * w2in1inv;
const float v2in1 = (h21inv * u2 + h22inv * v2 + h23inv) * w2in1inv;
const float squareDist1 = (u1 - u2in1) * (u1 - u2in1) + (v1 - v2in1) * (v1 - v2in1);
const float chiSquare1 = squareDist1 * invSigmaSquare;
// step3. 离群点标记上,非离群点累加计算得分
if (chiSquare1 > th)
bIn = false;
else
score += th - chiSquare1;
// step4. 计算img1到img2的重投影误差
const float w1in2inv = 1.0 / (h31 * u1 + h32 * v1 + h33);
const float u1in2 = (h11 * u1 + h12 * v1 + h13) * w1in2inv;
const float v1in2 = (h21 * u1 + h22 * v1 + h23) * w1in2inv;
const float squareDist2 = (u2 - u1in2) * (u2 - u1in2) + (v2 - v1in2) * (v2 - v1in2);
const float chiSquare2 = squareDist2 * invSigmaSquare;
// step5. 离群点标记上,非离群点累加计算得分
if (chiSquare2 > th)
bIn = false;
else
score += th - chiSquare2;
if (bIn)
vbMatchesInliers[i] = true;
else
vbMatchesInliers[i] = false;
}
return score;
}