[再再再次續]關於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);
		}
	}

哎不管了,再用畫出極線試一試,如果不行,就實在沒辦法了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章