[再再再次续]关于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.csdn.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);
		}
	}

	// 对矩阵进行尺度缩放,使第三行第三列为1
	float F33 = LS.at<float>(2, 2);
	for (size_t i = 0; i < 3; i++)
	{
		for (size_t j = 0; j < 3; j++)
		{
			cout << "i" << "  " << F.at<double>(i, j) << endl;
			LS.at<float>(i, j) = LS.at<float>(i, j) / F33;
		}
	}

	std::vector<cv::Vec3f> lines2; //存储外极线
	cv::computeCorrespondEpilines(cv::Mat(queryInliers), 1, LS, lines1);//获取图像1中的二维特征点 在图像2中对应的外极线
	for (std::vector<cv::Vec3f>::const_iterator it1 = lines1.begin();
		it1 != lines1.end(); ++it1)
	{
		cv::line(imagekeyPt2,
			cv::Point(0, -(*it1)[2] / (*it1)[1]),
			cv::Point(imagekeyPt2.cols, -((*it1)[2] + (*it1)[0] * imagekeyPt2.cols) / (*it1)[1]),
			cv::Scalar(0, 0, 255));
	}
	cv::imshow("Epilines", imagekeyPt2);

猜你喜欢

转载自blog.csdn.net/baidu_40840693/article/details/83215140