前言
这部分函数是要对所有的单应矩阵进行一个打分,比较得分,得分最高(误差最小)的选为最优的单应矩阵。
1.函数声明
float Initializer::CheckHomography(const cv::Mat &H21, const cv::Mat &H12, vector<bool> &vbMatchesInliers, float sigma)
2.函数定义
1.单应矩阵描述特征点对之间的关系
2.定义误差(实际上,上述的等式不完全恒等于0)
其中在代码中σ=1。
3.评分公式 (误差越大评分越低)
th表示自由度为2的卡方分布在显著性水平为0.05时对应的临界域值。
/*对给定的homography matrix打分,需要使用到卡方检验的知识H21 从参考帧到当前帧的单应矩阵H12 从当前帧到参考帧的单应矩阵vbMatchesInliers 匹配好的特征点对的Inliers标记sigma 方差,默认为1return float 返回得分*/
float Initializer::CheckHomography(const cv::Mat &H21, //从参考帧到当前帧的单应矩阵const cv::Mat &H12, //从当前帧到参考帧的单应矩阵vector<bool> &vbMatchesInliers, //匹配好的特征点对的Inliers标记float sigma) //估计误差
{// 特点匹配个数const int N = mvMatches12.size();// Step 1 获取从参考帧到当前帧的单应矩阵的各个元素const float h11 = H21.at<float>(0,0);const float h12 = H21.at<float>(0,1);const float h13 = H21.at<float>(0,2);const float h21 = H21.at<float>(1,0);const float h22 = H21.at<float>(1,1);const float h23 = H21.at<float>(1,2);const float h31 = H21.at<float>(2,0);const float h32 = H21.at<float>(2,1);const float h33 = H21.at<float>(2,2);// 获取从当前帧到参考帧的单应矩阵的各个元素const float h11inv = H12.at<float>(0,0);const float h12inv = H12.at<float>(0,1);const float h13inv = H12.at<float>(0,2);const float h21inv = H12.at<float>(1,0);const float h22inv = H12.at<float>(1,1);const float h23inv = H12.at<float>(1,2);const float h31inv = H12.at<float>(2,0);const float h32inv = H12.at<float>(2,1);const float h33inv = H12.at<float>(2,2);// 给特征点对的Inliers标记预分配空间vbMatchesInliers.resize(N);// 初始化score值float score = 0;// 基于卡方检验计算出的阈值(假设测量有一个像素的偏差)// 自由度为2的卡方分布,显著性水平为0.05,对应的临界阈值const float th = 5.991;//信息矩阵,方差平方的倒数const float invSigmaSquare = 1.0/(sigma * sigma);// Step 2 通过H矩阵,进行参考帧和当前帧之间的双向投影,并计算起加权重投影误差// H21 表示从img1 到 img2的变换矩阵// H12 表示从img2 到 img1的变换矩阵 for(int i = 0; i < N; i++){// 一开始都默认为Inlierbool bIn = true;// Step 2.1 提取参考帧和当前帧之间的特征匹配点对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;// Step 2.2 计算 img2 到 img1 的重投影误差// x1 = H12*x2// 将图像2中的特征点通过单应变换投影到图像1中// |u1| |h11inv h12inv h13inv||u2| |u2in1|// |v1| = |h21inv h22inv h23inv||v2| = |v2in1| * w2in1inv// |1 | |h31inv h32inv h33inv||1 | | 1 |// 计算投影归一化坐标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;// 计算重投影误差 = ||p1(i) - H12 * p2(i)||2const float squareDist1 = (u1 - u2in1) * (u1 - u2in1) + (v1 - v2in1) * (v1 - v2in1);const float chiSquare1 = squareDist1 * invSigmaSquare;// Step 2.3 用阈值标记离群点,内点的话累加得分if(chiSquare1>th)bIn = false; else// 误差越大,得分越低score += th - chiSquare1;// 计算从img1 到 img2 的投影变换误差// x1in2 = H21*x1// 将图像2中的特征点通过单应变换投影到图像1中// |u2| |h11 h12 h13||u1| |u1in2|// |v2| = |h21 h22 h23||v1| = |v1in2| * w1in2inv// |1 | |h31 h32 h33||1 | | 1 |// 计算投影归一化坐标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;// 用阈值标记离群点,内点的话累加得分if(chiSquare2>th)bIn = false;elsescore += th - chiSquare2; // Step 2.4 如果从img2 到 img1 和 从img1 到img2的重投影误差均满足要求,则说明是Inlier pointif(bIn)vbMatchesInliers[i]=true;elsevbMatchesInliers[i]=false;}return score;
}
结束语
以上就是我学习到的内容,如果对您有帮助请多多支持我,如果哪里有问题欢迎大家在评论区积极讨论,我看到会及时回复。