[再再再次续]关于opencv2.4.10-3.3.1左右版本的特征点剔除与显示问题
解决一个问题,关于在博客:
关于opencv2.4.10-3.3.1左右版本的特征点剔除与显示问题
中的论文实现:
随机抽取8个不同点,使用上图公式(5),求取F矩阵和H矩阵
公式中左边F那一块最小值为0,右边H那一块最小值为0,整体公式E其实是一个优化问题
方式通过最小二乘估计求解方程组,AX=0
#include<cv.h>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
Mat A(7, 3, CV_64FC1);
Mat vec(3, 1, CV_64FC1);//最后的答案
for(int i=0;i<7;i++)
{
for(int j=0;j<3;++j)
{
A.at<double>(i,j)=i*j-i;//初始化A的值
}
}
SVD::solveZ(A,vec );
}
为什么H矩阵的自由度为8:
假设两张图像中的对应点对齐次坐标为(x',y',1)和(x,y,1),单应矩阵H定义为:
矩阵展开后有3个等式,将第3个等式代入前两个等式中可得:
(下面的式子这么写是因为要除以1,那个1的表示就是下面式子中的分母,为什么除以1,因为齐次坐标系)
也就是说,一个点对对应两个等式。在此插入一个讨论:单应矩阵H有几个自由度?
或许有人会说,9个啊,H矩阵不是9个参数吗?从h11到h33总共9个。真的是这样吗?实际上并不是,因为这里使用的是齐次坐标系,也就是说可以进行任意尺度的缩放。比如我们把hij乘以任意一个非零常数k并不改变等式结果:
如果这里,存在一种情况,k的值,正好等于,1/h33,仅仅是值相等
就是不管h33是什么未知数,因为k可以是任意非0数,所以肯定有一种尺度的缩放,使其k的值和1/h33相等
所以实际上单应矩阵H只有8个自由度。8自由度下H计算过程有两种方法。
通过上述讲解,我相信大家已经明白了,H的自由度为8,所以,实际运算中,方便理解期间,我们直接把h33设为1
接着,我们把F矩阵写出来:
F矩阵的自由度为7,和H矩阵有一点一样,可以将f9,直接设置为1,因为F矩阵也是在齐次坐标系下
H矩阵有两个公式,4个匹配对,就可解决8自由度的H矩阵的问题
F矩阵只有一个公式,我们一般去解决问题时,
视F矩阵为8自由度,不去管F矩阵还应该找到的一个自由度了,直接把f9设置为1,8个匹配对,就可解决8自由度的F矩阵的问题
这种方法,很多博客称为8点法,求解F矩阵
别的博客公开的GitHub代码:
https://blog.****.net/kokerf/article/details/72630863?locationNum=2&fps=1
https://github.com/kokerf/vision_kit/blob/master/module/epipolar_geometry/src/homography.cpp
https://github.com/kokerf/vision_kit/blob/master/module/epipolar_geometry/src/fundamental.cpp
Mat F_H(18, 1, CV_32F, Scalar(0));//最后的答案
std::vector<cv::Point2f> pts_prev;
std::vector<cv::Point2f> pts_next;
for (size_t H_F_i = 0; H_F_i < 8; H_F_i++)
{
pts_prev.push_back(srcInliers[H_F_i]);
pts_next.push_back(dstInliers[H_F_i]);
}
F_H_run8point(pts_prev, pts_next, F_H);
void F_H_run8point(const std::vector<cv::Point2f>& pts_prev, const std::vector<cv::Point2f>& pts_next, cv::Mat& F_H)
{
const int N = pts_prev.size();
assert(N >= 8);
std::vector<cv::Point2f> pts_prev_norm;
std::vector<cv::Point2f> pts_next_norm;
pts_prev_norm = pts_prev;
pts_next_norm = pts_next;
//Normalize(pts_prev, pts_prev_norm, T1);
//Normalize(pts_next, pts_next_norm, T2);
cv::Mat A(N, 18, CV_32F, Scalar(0));
for (int i = 0; i < N; ++i)
{
const float u1 = pts_prev_norm[i].x;
const float v1 = pts_prev_norm[i].y;
const float u2 = pts_next_norm[i].x;
const float v2 = pts_next_norm[i].y;
float* ai = A.ptr<float>(i);
//F
ai[0] = u1*u2;//xx'
ai[1] = u1*v2;//xy'
ai[2] = u1;//x
ai[3] = v1*u2;//yx'
ai[4] = v1*v2;//yy'
ai[5] = v1;//y
ai[6] = u2;//x'
ai[7] = v2;//y'
ai[8] = 1;//1
//H
ai[9] = 1;
ai[10] = 1;
ai[11] = 1;
ai[12] = 1;
ai[13] = 1;
ai[14] = 1;
ai[15] = 1;
ai[16] = 1;
ai[17] = 1;
}
SVD::solveZ(A, F_H);
}
H这里我还没有相通,代码没法继续下去,
或许,
他其实就是把8个点代入F公式,求出最小误差的F,误差为dif_F,然后8个点带入H公式,误差为dif_H
然后求dif = dif_F+dif_H,
每次都迭代输入8个点,求出最小误差dif
想到了一点的
void F_H_run8point(const std::vector<cv::Point2f>& pts_prev, const std::vector<cv::Point2f>& pts_next, cv::Mat& F_H)
{
const int N = pts_prev.size();
assert(N >= 8);
std::vector<cv::Point2f> pts_prev_norm;
std::vector<cv::Point2f> pts_next_norm;
pts_prev_norm = pts_prev;
pts_next_norm = pts_next;
//Normalize(pts_prev, pts_prev_norm, T1);
//Normalize(pts_next, pts_next_norm, T2);
cv::Mat A(N, 18, CV_32F, Scalar(0));
for (int i = 0; i < N; ++i)
{
const float u1 = pts_prev_norm[i].x;
const float v1 = pts_prev_norm[i].y;
const float u2 = pts_next_norm[i].x;
const float v2 = pts_next_norm[i].y;
float* ai = A.ptr<float>(i);
//F u1=x u2=x' v1=y v2=y'
ai[0] = u1*u2;//xx'
ai[1] = u1*v2;//xy'
ai[2] = u1;//x
ai[3] = v1*u2;//yx'
ai[4] = v1*v2;//yy'
ai[5] = v1;//y
ai[6] = u2;//x'
ai[7] = v2;//y'
ai[8] = 1;//1
//H u1=x u2=x' v1=y v2=y'
ai[9] = u1;//x
ai[10] = v1;//y
ai[11] = 1;//1
ai[12] = u1;//x
ai[13] = v1;//y
ai[14] = 1;//1
ai[15] = -(u1*u2 + u1*v2);//-xx'-xy'
ai[16] = -(v1*u2 + v1*v2);//-yx'-yy'
ai[17] = -(u2 + v2);//-x'-y'
}
SVD::solveZ(A, F_H);
}
Mat F_H(18, 1, CV_32F, Scalar(0));//最后的答案
std::vector<cv::Point2f> pts_prev;
std::vector<cv::Point2f> pts_next;
for (size_t H_F_i = 0; H_F_i < 8; H_F_i++)
{
pts_prev.push_back(srcInliers[H_F_i]);
pts_next.push_back(dstInliers[H_F_i]);
}
F_H_run8point(pts_prev, pts_next, F_H);
Mat LS(9, 1, CV_32F, Scalar(0));
for (size_t i = 0; i < 9; i++)
{
cout << "i" << " " << F_H.at<float>(i, 0) << endl;
LS.at<float>(i, 0) = F_H.at<float>(i, 0);
}
LS = LS.reshape(1,3);
cout << "====================="<< endl;
Mat F_H_toF(3, 3, CV_64F, Scalar(0));
for (size_t i = 0; i < 3; i++)
{
for (size_t j = 0; j < 3; j++)
{
cout << "i" << " " << F.at<double>(i, j) << endl;
F_H_toF.at<double>(i, j) = F.at<double>(i, j);
}
}
哎不管了,再用画出极线试一试,如果不行,就实在没办法了。