Homography算法无法按预期工作

时间:2015-10-05 21:15:44

标签: algorithm matrix openframeworks homography

最近,我一直试图通过从4个检测到的4个真实2D点生成单应性3x3矩阵来完成项目的一个阶段。 我尝试了一些不同的算法和一些不同的SVD实现,但仍然无法获得良好的结果。

我已经Openframework's homography implementation(IIRC取自opencv)并且接近......但仍然没有正确的结果。我很确定所有的矩阵用法都是正确的,但是我已经弄乱了某些地方(甚至可能是最终的变换?)

这是我想要匹配的点的图像,左边的src(匹配),右边的dst(真值)。 (如果需要,我可以获得坐标,但图像大小约为640x1000)。最右边(在白色上着色)是转换到dst / truth上的匹配,并且由测试代码中使用的相同单应性扭曲成像。 enter image description here

注意:忽略opencl类型,这些都是正确使用的(这里只是为了简洁而减少)。 std :: Debug只是一个ostream。它是一个16浮点数组,但我只是使用前9个

void gaussian_elimination(float *input, int n)
{
	// ported to c from pseudocode in
	// http://en.wikipedia.org/wiki/Gaussian_elimination
	
	float * A = input;
	int i = 0;
	int j = 0;
	int m = n-1;
	while (i < m && j < n){
		// Find pivot in column j, starting in row i:
		int maxi = i;
		for(int k = i+1; k<m; k++){
			if(fabs(A[k*n+j]) > fabs(A[maxi*n+j])){
				maxi = k;
			}
		}
		if (A[maxi*n+j] != 0){
			//swap rows i and maxi, but do not change the value of i
			if(i!=maxi)
				for(int k=0;k<n;k++){
					float aux = A[i*n+k];
					A[i*n+k]=A[maxi*n+k];
					A[maxi*n+k]=aux;
				}
			//Now A[i,j] will contain the old value of A[maxi,j].
			//divide each entry in row i by A[i,j]
			float A_ij=A[i*n+j];
			for(int k=0;k<n;k++){
				A[i*n+k]/=A_ij;
			}
			//Now A[i,j] will have the value 1.
			for(int u = i+1; u< m; u++){
				//subtract A[u,j] * row i from row u
				float A_uj = A[u*n+j];
				for(int k=0;k<n;k++){
					A[u*n+k]-=A_uj*A[i*n+k];
				}
				//Now A[u,j] will be 0, since A[u,j] - A[i,j] * A[u,j] = A[u,j] - 1 * A[u,j] = 0.
			}
			
			i++;
		}
		j++;
	}
	
	//back substitution
	for(int i=m-2;i>=0;i--){
		for(int j=i+1;j<n-1;j++){
			A[i*n+m]-=A[i*n+j]*A[j*n+m];
			//A[i*n+j]=0;
		}
	}
}
                                  
                                  
                                  
cl_float16 of_findHomography(cl_float2 src[4], cl_float2 dst[4])
{
	// create the equation system to be solved
	//
	// from: Multiple View Geometry in Computer Vision 2ed
	//       Hartley R. and Zisserman A.
	//
	// x' = xH
	// where H is the homography: a 3 by 3 matrix
	// that transformed to inhomogeneous coordinates for each point
	// gives the following equations for each point:
	//
	// x' * (h31*x + h32*y + h33) = h11*x + h12*y + h13
	// y' * (h31*x + h32*y + h33) = h21*x + h22*y + h23
	//
	// as the homography is scale independent we can let h33 be 1 (indeed any of the terms)
	// so for 4 points we have 8 equations for 8 terms to solve: h11 - h32
	// after ordering the terms it gives the following matrix
	// that can be solved with gaussian elimination:
	
	float P[8][9]={
		{-src[0][0], -src[0][1], -1,   0,   0,  0, src[0][0]*dst[0][0], src[0][1]*dst[0][0], -dst[0][0] }, // h11
		{  0,   0,  0, -src[0][0], -src[0][1], -1, src[0][0]*dst[0][1], src[0][1]*dst[0][1], -dst[0][1] }, // h12
		
		{-src[1][0], -src[1][1], -1,   0,   0,  0, src[1][0]*dst[1][0], src[1][1]*dst[1][0], -dst[1][0] }, // h13
		{  0,   0,  0, -src[1][0], -src[1][1], -1, src[1][0]*dst[1][1], src[1][1]*dst[1][1], -dst[1][1] }, // h21
		
		{-src[2][0], -src[2][1], -1,   0,   0,  0, src[2][0]*dst[2][0], src[2][1]*dst[2][0], -dst[2][0] }, // h22
		{  0,   0,  0, -src[2][0], -src[2][1], -1, src[2][0]*dst[2][1], src[2][1]*dst[2][1], -dst[2][1] }, // h23
		
		{-src[3][0], -src[3][1], -1,   0,   0,  0, src[3][0]*dst[3][0], src[3][1]*dst[3][0], -dst[3][0] }, // h31
		{  0,   0,  0, -src[3][0], -src[3][1], -1, src[3][0]*dst[3][1], src[3][1]*dst[3][1], -dst[3][1] }, // h32
	};
	
	gaussian_elimination(&P[0][0],9);
/*
	// gaussian elimination gives the results of the equation system
	// in the last column of the original matrix.
	// opengl needs the transposed 4x4 matrix:
	float aux_H[]=
	{
		P[0][8],P[3][8],0,P[6][8], // h11  h21 0 h31
		P[1][8],P[4][8],0,P[7][8], // h12  h22 0 h32
		0      ,      0,0,0,       // 0    0   0 0
		P[2][8],P[5][8],0,1 // h13  h23 0 h33
	};
*/
	//	non transposed 3x3
	cl_float16 Result;
	Result.s[0] = P[0][8];
	Result.s[1] = P[1][8];
	Result.s[2] = P[2][8];
	
	Result.s[3] = P[3][8];
	Result.s[4] = P[4][8];
	Result.s[5] = P[5][8];
	
	Result.s[6] = P[6][8];
	Result.s[7] = P[7][8];
	Result.s[8] = 1;
	//Result.s[8] = P[8][8];

	
	//	test
	for ( int i=0;	i<4;	i++ )
	{
		auto H = Result.s;
		float x = H[0]*src[i][0] + H[1]*src[i][1] + H[2];
		float y = H[3]*src[i][0] + H[4]*src[i][1] + H[5];
		float z = H[6]*src[i][0] + H[7]*src[i][1] + H[8];
		
		x /= z;
		y /= z;
		
		float diffx = dst[i][0] - x;
		float diffy = dst[i][1] - y;
		std::Debug << "err src->dst #" << i << ": " << diffx << "," << diffy << std::endl;
	}
	for ( int i=0;	i<4;	i++ )
	{
		auto H = Result.s;
		float x = H[0]*dst[i][0] + H[1]*dst[i][1] + H[2];
		float y = H[3]*dst[i][0] + H[4]*dst[i][1] + H[5];
		float z = H[6]*dst[i][0] + H[7]*dst[i][1] + H[8];
		
		x /= z;
		y /= z;
		
		float diffx = src[i][0] - x;
		float diffy = src[i][1] - y;
		std::Debug << "err src->dst #" << i << ": " << diffx << "," << diffy << std::endl;
	}

	
	return Result;
}

图像的输出是

  

错误src-&gt; dst#0:0.00195,0.0132

     

错误src-&gt; dst#1:0,6.1e-05

     

错误src-&gt; dst#2:-0.00161,-8.96e-05

     

错误src-&gt; dst#3:1.91e-06,0.000122

     

错误dst-&gt; src#0:2.31e + 03,551

     

错误dst-&gt; src#1:-3.34e + 03,-4.23e + 03

     

错误dst-&gt; src#2:1.07e + 03,1.25e + 04

     

err dst-&gt; src#3:456,771

我的矩阵变换代码有什么明显的错误吗? 或者我是否以错误的行/列顺序将SVD结果放入矩阵中? 也许整个算法不是我需要的? (当然它应该生成一个非常简单的小旋转矩阵?)

1 个答案:

答案 0 :(得分:0)

我和往常一样糟糕。这种实现似乎完美(到目前为止)并且对GPU并行化很有用。

我正在用不好的坐标喂食。渲染的点与输入算法的点(新代码与旧代码)不同。

警告未来总是首先生成数据,然后渲染,而不是使用[曾经]相同的代码生成和生成。