Exemplo n.º 1
0
CvMat *Morphining::GetAffineMatrix(vector<Coordinate> coord1,vector<Coordinate>coord2,bool debug)
{
	//b_temp:affine transformation,b_temp_inv:inverse of affine transform
	CvMat *b_temp	  = cvCreateMat(3, 3, CV_32FC1);
	CvMat *b_temp_inv = cvCreateMat(3, 3, CV_32FC1);
	CvMat *B		  = cvCreateMat(3, 3, CV_32FC1);
	CvMat *X		  = cvCreateMat(3, 3, CV_32FC1);
	CvMat *X_Inv	  = cvCreateMat(3, 3, CV_32FC1);
     // x1' = w11 * x1 + w12 * y1 + w13
     // y1' = w21 * x1 + w22 * y1 + w13
     // x2' = w11 * x2 + w12 * y2 + w13
     // y2' = w21 * x2 + w22 * y2 + w13
	 // x3' = w11 * x3 + w12 * y3 + w13
     // y3' = w21 * x3 + w22 * y3 + w13
	 // Ax = b  x:left or right b:front face 

	for(int i = 0;i < 3;i++)
	{
		cvSetReal2D(B, 0, i, coord1[i].x);
		cvSetReal2D(B, 1, i, coord1[i].y);
		cvSetReal2D(B, 2, i, 1);
	}

	for(int i = 0;i < 3;i++)
	{
		cvSetReal2D(X, 0 , i, coord2[i].x);
		cvSetReal2D(X, 1 , i, coord2[i].y);
		cvSetReal2D(X, 2 , i, 1);
	}

	cvInv(X, X_Inv);
	cvmMul(B,X_Inv,b_temp);
	cvInv(b_temp,b_temp_inv);
	if(debug)
	{
		cout << "b_temp:\n";
		PrintMatrix(b_temp,3,3);
		cout << "b_temp_inv:\n";
		PrintMatrix(b_temp_inv,3,3);
	}
	cvReleaseMat(&B);
	cvReleaseMat(&X);
	cvReleaseMat(&X_Inv);
	cvReleaseMat(&b_temp);
	//return b_temp;
	return b_temp_inv;
}
Exemplo n.º 2
0
CvMat* Panoramic::GetAffineMatrix(vector<Coordinate> adjustCoord,vector<Coordinate> adjustedCoord)
{
	//affineMatrix:affine transformation,b_temp_inv:inverse of affine transform
	// x1' = w11 * x1 + w12 * y1 + w13
    // y1' = w21 * x1 + w22 * y1 + w13
    // x2' = w11 * x2 + w12 * y2 + w13
    // y2' = w21 * x2 + w22 * y2 + w13
	// x3' = w11 * x3 + w12 * y3 + w13
    // y3' = w21 * x3 + w22 * y3 + w13
	// Ax = b  x:left or right b:front face 

			m_affineMatrix	= cvCreateMat(3, 3, CV_32FC1);
	CvMat *invAffineMatrix  = cvCreateMat(3, 3, CV_32FC1);
	CvMat *B				= cvCreateMat(3, 3, CV_32FC1);
	CvMat *X				= cvCreateMat(3, 3, CV_32FC1);
	CvMat *X_Inv			= cvCreateMat(3, 3, CV_32FC1);

	for(int i = 0;i < 3;i++)
	{
		cvSetReal2D(B, 0, i, adjustCoord[i].x);
		cvSetReal2D(B, 1, i, adjustCoord[i].y);
		cvSetReal2D(B, 2, i, 1);

		cvSetReal2D(X, 0 , i, adjustedCoord[i].x);
		cvSetReal2D(X, 1 , i, adjustedCoord[i].y);
		cvSetReal2D(X, 2 , i, 1);
	}

	cvInv(X, X_Inv);
	cvmMul(B,X_Inv,m_affineMatrix);
	cvInv(m_affineMatrix,invAffineMatrix);

	if(m_debug)
	{
		cout << "inverse affine matrix\n";
		PrintMatrix(invAffineMatrix,3,3);
	}

	cvReleaseMat(&B);
	cvReleaseMat(&X);	
	cvReleaseMat(&X_Inv);	
	cvReleaseMat(&m_affineMatrix);
	return invAffineMatrix;
}
Exemplo n.º 3
0
/*
 * \param Intrinsic  : 3 by 3 camera intrinsic matrix  
 * \param bazProjMat : 3 by 4 projection matrix  = K[RT] obtained by calling "augment.GetProjectionMatrix(0)" function
 * \arRT : 4 by 4 [R t] matrix for rendering
*/
	void BazARTracker::GetARToolKitRTfromBAZARProjMat(CvMat *Intrinsic, CvMat *bazProjMat, CvMat *arRT)
	{
		int i, j;
		CvMat *temps = cvCreateMat(3, 4, CV_64F);
		
		// inverse matrix with intrinsic camera parameters
		CvMat *invK = cvCloneMat(Intrinsic);
		cvInv(Intrinsic, invK);
		// multiply bazProjMat with inverted intrinsic camera parameter matrix -> extract intrinsic parameters
		cvMatMul(invK, bazProjMat, temps);

		cvmSetIdentity(arRT);
		for(i=0; i<temps->rows; i++)
		{
			for(j=0; j<temps->cols;j++)  cvmSet(arRT, i, j, cvmGet(temps, i,j));
		}
	
		cvReleaseMat(&temps);
		cvReleaseMat(&invK);
	}
Exemplo n.º 4
0
int CUKF::UnscentedUpdate(int idf, int idx)
{
	// Set up some variables
	int dim = XX->rows;
	int N = 2*dim+1;
	double scale = 3;
	int kappa = scale-dim;

	// Create samples
	// SVD
	CvSize P = cvGetSize(PX);
	CvMat *D = cvCreateMat(P.height, P.width, CV_64FC1);
	CvMat *U = cvCreateMat(P.height, P.height, CV_64FC1);
	CvMat *V = cvCreateMat(P.width, P.width, CV_64FC1);
	CvMat *Ds = cvCreateMat(P.height, P.width, CV_64FC1);
	CvMat *UD = cvCreateMat(P.height, P.width, CV_64FC1);
	CvMat *Ps = cvCreateMat(P.height, P.width, CV_64FC1);
	cvSVD(PX, D, U, V, CV_SVD_V_T);
	MatSqrt(D, Ds);
	cvMatMul(U, Ds, UD);
	cvScale(UD, Ps, sqrt(scale), 0);

// 	CvMat *ss = cvCreateMat(dim, N, CV_64FC1);
// 	int i,j,jj;
// 	int row = dim;
// 	int col = N;
// 	cvRepeat(XX, ss);
// // 	for (i=0; i<row; i++)	for (j=0; j<col; j++)
// // 		ss->data.db[i*col+j] = XXA->data.db[i];
// 
// 	col -= dim;
// 	for(i=0; i<row; i++)	for(j=1, jj=0; j<col+1; j++, jj++)
// 		ss->data.db[i*col+j] += Ps->data.db[i*col+jj];
// 	for(i=0; i<row; i++)	for(j=1+dim, jj=0; j<col+1+dim; j++, jj++)
//		ss->data.db[i*col+j] -= Ps->data.db[i*col+jj];

	CvMat *ss = cvCreateMat(dim, N, CV_64FC1);
	int i,j,jj;
	int row = dim;
	int col = N;
	cvRepeat(XX, ss);

	double *ssdb = ss->data.db;
	double *Psdb = Ps->data.db;

	for(i=0; i<row; i++)
	{
		for(j=1, jj=0; j<dim+1; j++, jj++)
		{
			ssdb[i*ss->cols+j] += Psdb[i*Ps->cols+jj];
		}
	}

	for(i=0; i<row; i++)
	{
		for(j=1+dim, jj=0; j<ss->cols; j++, jj++)
		{
			ssdb[i*ss->cols+j] -= Psdb[i*Ps->cols+jj];
		}
	}

	// Transform samples according to observation model to obtain the predicted observation samples
	CvMat *zs = cvCreateMat(2, N, CV_64FC1);
//	CvMat *base = cvCreateMat(3, EP, CV_64FC1);
	int Nxv = 3;
	int f = Nxv + idf*2 - 2;

//	PrintCvMat(ss, "ss");
	
	double *zsdb = zs->data.db;

	for(j=0; j<N; j++)
	{
		double dx = ssdb[f*ss->cols+j] - ssdb[0*ss->cols+j];
		double dy = ssdb[(f+1)*ss->cols+j] - ssdb[1*ss->cols+j];
		double d2 = dx*dx + dy*dy;
		double d = sqrt(d2);

		zsdb[0*zs->cols+j] = d;
		zsdb[1*zs->cols+j] = atan2(dy,dx) - ssdb[2*ss->cols+j];
	}

// zz = repvec(z,N);
// dz = feval(dzfunc, zz, zs); % compute correct residual
// zs = zz - dz;               % offset zs from z according to correct residual

//	PrintCvMat(zs, "zs");

	CvMat *zz = cvCreateMat(2, N, CV_64FC1);
	CvMat *dz = cvCreateMat(2, N, CV_64FC1);
	CvMat *zprev = cvCreateMat(2, 1, CV_64FC1);
	zprev->data.db[0] = zf[idx].x;
	zprev->data.db[1] = zf[idx].y;
	cvRepeat(zprev, zz);
	cvSub(zz, zs, dz);
	double *dzdb = dz->data.db;
	for(j=0; j<dz->cols; j++) dzdb[1*dz->cols+j] = PI2PI(dzdb[1*dz->cols+j]);
	cvSub(zz, dz, zs);

//	PrintCvMat(zs, "zs");

	CvMat *zm = cvCreateMat(2, 1, CV_64FC1);
	CvMat *dx = cvCreateMat(dim ,N, CV_64FC1);
//	CvMat *dz = cvCreateMat(2, N, CV_64FC1);
	CvMat *repx = cvCreateMat(dim ,N, CV_64FC1);
	CvMat *repzm = cvCreateMat(2, N, CV_64FC1);
	CvMat *Pxz = cvCreateMat(dim, 2, CV_64FC1);
	CvMat *Pzz = cvCreateMat(2, 2, CV_64FC1);
	CvMat *dxu = cvCreateMat(dim, 1, CV_64FC1);
	CvMat *dxl = cvCreateMat(dim, N-1, CV_64FC1);
	CvMat *dzu = cvCreateMat(2, 1, CV_64FC1);
	CvMat *dzl = cvCreateMat(2, N-1, CV_64FC1);
	CvMat *dztu = cvCreateMat(1, 2, CV_64FC1);
	CvMat *dztl = cvCreateMat(N-1, 2, CV_64FC1);
	CvMat *dxdzu = cvCreateMat(dim, 2, CV_64FC1);
	CvMat *dxdzl = cvCreateMat(dim, 2, CV_64FC1);
	CvMat *dzdzu = cvCreateMat(2, 2, CV_64FC1);
	CvMat *dzdzl = cvCreateMat(2, 2, CV_64FC1);

	double *zmdb = zm->data.db;

	zmdb[0] = kappa*zs->data.db[0*zs->cols];
	zmdb[1] = kappa*zs->data.db[1*zs->cols];

	for(j=1; j<N; j++)
	{
		zm->data.db[0] += 0.5*zsdb[0*zs->cols+j];
		zm->data.db[1] += 0.5*zsdb[1*zs->cols+j];
	}
	cvScale(zm, zm, 1/(double)(scale));

	// Calculate predicted observation mean
	cvRepeat(XX, repx);
	cvRepeat(zm, repzm);

//	PrintCvMat(ss, "ss");
//	PrintCvMat(zs, "zs");
//	PrintCvMat(repx, "repx");
//	PrintCvMat(repzm, "repzm");

	// Calculate observation covariance and the state-observation correlation matrix
	cvSub(ss, repx, dx);
	cvSub(zs, repzm, dz);

//	PrintCvMat(dx, "dx");
//	PrintCvMat(dz, "dz");

	double *dxdb = dx->data.db;
	double *dzudb = dzu->data.db;
	double *dzldb = dzl->data.db;
	double *dxudb = dxu->data.db;
	double *dxldb = dxl->data.db;

	// dx, dz를 1열과 나머지 열로 분할
	for(i=0; i<2; i++)	dzudb[i] = dzdb[i*dz->cols];
	for(i=0; i<2; i++)	for(j=1, jj=0; j<N; j++, jj++)
			dzldb[i*dzl->cols+jj] = dzdb[i*dz->cols+j];

	for(i=0; i<dim; i++)	dxudb[i] = dxdb[i*dx->cols];
	for(i=0; i<dim; i++)	for(j=1, jj=0; j<N; j++, jj++)
			dxldb[i*dxl->cols+jj] = dxdb[i*dx->cols+j];

	cvT(dzu, dztu);
	cvT(dzl, dztl);

//	PrintCvMat(dxu, "dxu");
//	PrintCvMat(dztu, "dztu");
//	PrintCvMat(dxl, "dxl");
//	PrintCvMat(dztl, "dztl");

	cvMatMul(dxu, dztu, dxdzu);
	cvScale(dxdzu, dxdzu, 2*kappa);
	cvMatMul(dxl, dztl, dxdzl);
	cvAdd(dxdzu, dxdzl, Pxz);
	cvScale(Pxz, Pxz, 1/(double)(2*scale));

	cvMatMul(dzu, dztu, dzdzu);
	cvScale(dzdzu, dzdzu, 2*kappa);
	cvMatMul(dzl, dztl, dzdzl);
	cvAdd(dzdzu, dzdzl, Pzz);
	cvScale(Pzz, Pzz, 1/(double)(2*scale));

//	PrintCvMat(dx, "dx");
//	PrintCvMat(dz, "dz");
//	PrintCvMat(dzu, "dzu");
//	PrintCvMat(dztu, "dztu");
//	PrintCvMat(dzl, "dzl");
//	PrintCvMat(dztl, "dztl");
//	PrintCvMat(dxu, "dxu");
//	PrintCvMat(dxl, "dxl");
//	PrintCvMat(dxdzu, "dxdzu");
//	PrintCvMat(dxdzl, "dxdzl");
//	PrintCvMat(dzdzu, "dzdzu");
//	PrintCvMat(dzdzl, "dzdzl");
//	PrintCvMat(Pxz, "Pxz");
//	PrintCvMat(Pzz, "Pzz");

	// Compute Kalman gain
	CvMat *S = cvCreateMat(2, 2, CV_64FC1);
	CvMat *p = cvCreateMat(2, 2, CV_64FC1);
	CvMat *Sct = cvCreateMat(2, 2, CV_64FC1);
	CvMat *Sc = cvCreateMat(2, 2, CV_64FC1);
	CvMat *Sci = cvCreateMat(2, 2, CV_64FC1);
	CvMat *Scit = cvCreateMat(2, 2, CV_64FC1);
	CvMat *Wc = cvCreateMat(dim, 2, CV_64FC1);
	CvMat *W = cvCreateMat(dim, 2, CV_64FC1);
	CvMat *Wz = cvCreateMat(dim, 1, CV_64FC1);
	CvMat *Wct = cvCreateMat(2, dim, CV_64FC1);
	CvMat *WcWc = cvCreateMat(dim, dim, CV_64FC1);

// % Compute Kalman gain
	cvAdd(Pzz, R, S);
	//cholesky decomposition이 실패하면 업데이트는 하지 않는다.
	if(choldc(S, p, Sct) < 0)
	{
		TRACE("idf : %d\n", idf);
		PrintCvMat(UD, "UD");
		PrintCvMat(U, "U");
		PrintCvMat(D, "D");
		PrintCvMat(V, "V");
		PrintCvMat(zprev, "zprev");
		PrintCvMat(XX, "XX");
		PrintCvMat(PX, "PX");
		PrintCvMat(Ps, "Ps");
		PrintCvMat(ss, "ss");
		for(j=0; j<N; j++)
		{
			double dx = ss->data.db[f*ss->cols+j] - ss->data.db[0*ss->cols+j];
			double dy = ss->data.db[(f+1)*ss->cols+j] - ss->data.db[1*ss->cols+j];
			double d2 = dx*dx + dy*dy;
			double d = sqrt(d2);
			double angle = atan2(dy,dx) - ss->data.db[2*ss->cols+j];

			TRACE("%.4f %.4f %.4f %.4f %.4f %.4f %.4f\n", dx, dy, d2, d, angle, atan2(dy, dx), ss->data.db[2*ss->cols+j]);
		}
		PrintCvMat(zs, "zs");
		PrintCvMat(zz, "zz");
		PrintCvMat(zm, "zm");
		PrintCvMat(dx, "dx");
		PrintCvMat(dz, "dz");
		PrintCvMat(Pxz, "Pxz");
		PrintCvMat(Pzz, "Pzz");
		PrintCvMat(R, "R");
		return -1;
	}
	cvT(Sct, Sc);
	cvInv(Sc, Sci);
	cvT(Sci, Scit);

//	PrintCvMat(S, "S");
//	PrintCvMat(Sct, "Sct");
//	PrintCvMat(Sc, "Sc");
//	PrintCvMat(Sci, "Sci");

	cvMatMul(Pxz, Sci, Wc);

//	PrintCvMat(Wc, "Wc");

	cvMatMul(Wc, Scit, W);

//	PrintCvMat(W, "W");
	
	cvSub(zprev, zm, zprev);
	cvMatMul(W, zprev, Wz);
	cvAdd(XX, Wz, XX);
	cvT(Wc, Wct);
	cvMatMul(Wc, Wct, WcWc);
	cvSub(PX, WcWc, PX);
	
// 	PrintCvMat(Pzz, "Pzz");
// 	PrintCvMat(R, "R");
// 	PrintCvMat(S, "S");
// 	PrintCvMat(Pxz, "Pxz");
// 	PrintCvMat(Sc, "Sc");
// 	PrintCvMat(Sct, "Sct");
// 	PrintCvMat(Sci, "Sci");
// 	PrintCvMat(Scit, "Scit");
// 	PrintCvMat(W, "W");	
// 	PrintCvMat(zprev, "zprev");
// 	PrintCvMat(zm, "zm");
// 	PrintCvMat(Wc, "Wc");
// 	PrintCvMat(Wct, "Wct");
// 	PrintCvMat(WcWc, "WcWc");
// 	PrintCvMat(PX, "Px");
// 
// 	PrintCvMat(XX, "XX");
// 	PrintCvMat(PX, "PX");

	cvReleaseMat(&D);
	cvReleaseMat(&U);
	cvReleaseMat(&V);
	cvReleaseMat(&Ds);
	cvReleaseMat(&UD);
	cvReleaseMat(&Ps);
	cvReleaseMat(&ss);
	cvReleaseMat(&zs);
	cvReleaseMat(&zz);
	cvReleaseMat(&dz);
	cvReleaseMat(&zprev);
	cvReleaseMat(&zm);
	cvReleaseMat(&dx);
	cvReleaseMat(&repx);
	cvReleaseMat(&repzm);
	cvReleaseMat(&Pxz);
	cvReleaseMat(&Pzz);
	cvReleaseMat(&dxu);
	cvReleaseMat(&dxl);
	cvReleaseMat(&dzu);
	cvReleaseMat(&dzl);
	cvReleaseMat(&dztu);
	cvReleaseMat(&dztl);
	cvReleaseMat(&dxdzu);
	cvReleaseMat(&dxdzl);
	cvReleaseMat(&dzdzu);
	cvReleaseMat(&dzdzl);
	cvReleaseMat(&S);
	cvReleaseMat(&p);
	cvReleaseMat(&Sct);
	cvReleaseMat(&Sc);
	cvReleaseMat(&Sci);
	cvReleaseMat(&Scit);
	cvReleaseMat(&Wc);
	cvReleaseMat(&W);
	cvReleaseMat(&Wz);
	cvReleaseMat(&Wct);
	cvReleaseMat(&WcWc);

	return 0;
}
CvMat* LineSegmentIntersectionDenormalizer::denormalize(const CvMat* nmodel, const CvMat* T1, const CvMat* T2) {
	cvInv(T1, invT);
	CvMat* model = matMul(invT, nmodel);
	return model;
}
Exemplo n.º 6
0
//coord1:校正用之點 coord2:被校正之點
//可執行四個以上的轉換
CvMat* Morphining::GetProjectionMatrix(vector<Coordinate> adjust,vector<Coordinate> adjusted,bool debug)
{
	//spec://cvSetReal2D(cvMat,row,col);
	if(m_numFeature < 4)
	{
		printf("Not enough tiles points to execute perspective transform!\n");
		exit(0);
	}

	//Element of PerspectiveTransformation 
	CvMat *b			= cvCreateMat( 8   ,  1         , CV_32FC1);
	CvMat *MUL_8_2N		= cvCreateMat( 8   , 2*m_numFeature , CV_32FC1);
	CvMat *b_temp		= cvCreateMat( 3   , 3          , CV_32FC1);
	CvMat *b_temp_inv   = cvCreateMat( 3   , 3          , CV_32FC1);
	//Size:2n*1 
	for(int i = 0;i < m_numFeature;i++)
	{
		cvSetReal2D(U, i,                0, adjusted[i].x);
		cvSetReal2D(U, i + m_numFeature, 0, adjusted[i].y);
	}
	//Size:2n*8
	for(int i = 0; i < m_numFeature;i++)
	{

		double col_6	  = -1.0 * adjust[i].x * cvGetReal2D(U,i,0);
		double col_7      = -1.0 * adjust[i].y * cvGetReal2D(U,i,0);
		double col_6_pair = -1.0 * adjust[i].x * cvGetReal2D(U,i + m_numFeature,0);
		double col_7_pair = -1.0 * adjust[i].y * cvGetReal2D(U,i + m_numFeature,0);

		cvSetReal2D(W, i, 0, adjust[i].x);
		cvSetReal2D(W, i, 1, adjust[i].y);
		cvSetReal2D(W, i, 2, 1);
		cvSetReal2D(W, i, 3, 0);
		cvSetReal2D(W, i, 4, 0);
		cvSetReal2D(W, i, 5, 0);
		cvSetReal2D(W, i, 6, col_6);
		cvSetReal2D(W, i, 7, col_7);
		
		cvSetReal2D(W, i + m_numFeature, 0, 0);
		cvSetReal2D(W, i + m_numFeature, 1, 0);
		cvSetReal2D(W, i + m_numFeature, 2, 0);
		cvSetReal2D(W, i + m_numFeature, 3, adjust[i].x);
		cvSetReal2D(W, i + m_numFeature, 4, adjust[i].y);
		cvSetReal2D(W, i + m_numFeature, 5, 1);
		cvSetReal2D(W, i + m_numFeature, 6, col_6_pair);
		cvSetReal2D(W, i + m_numFeature, 7, col_7_pair);

	}
	if(debug)
	{
		std::cout << "U:\n";
		PrintMatrix(U, 2*m_numFeature,1,1);
		std::cout << "W:\n";
		PrintMatrix(W, 2*m_numFeature,8,1);
	}

	if(W->cols == W->rows )cvInv(W,MUL_8_2N);
	
	else {	//pseudo inverse
			cvTranspose(W,T);
			cvmMul(T,W,MulResult);
			cvInv(MulResult,Inv);
			cvmMul(Inv,T,MUL_8_2N);
			/*printf("T\n");
			PrintMatrix(T, 8,2*m_numFeature,1);*/
			/*printf("MulResult\n");
			PrintMatrix(MulResult, 8,2*m_numFeature,1);*/
			/*printf("Inv\n");
			PrintMatrix(Inv,2*m_numFeature, 8,1);*/
	}
	
	cvmMul(MUL_8_2N,U,b);

	cvSetReal2D(b_temp, 0, 0, cvGetReal2D(b,0,0)); cvSetReal2D(b_temp, 0, 1, cvGetReal2D(b,1,0)); cvSetReal2D(b_temp, 0, 2, cvGetReal2D(b,2,0));
	cvSetReal2D(b_temp, 1, 0, cvGetReal2D(b,3,0)); cvSetReal2D(b_temp, 1, 1, cvGetReal2D(b,4,0)); cvSetReal2D(b_temp, 1, 2, cvGetReal2D(b,5,0));
	cvSetReal2D(b_temp, 2, 0, cvGetReal2D(b,6,0)); cvSetReal2D(b_temp, 2, 1, cvGetReal2D(b,7,0)); cvSetReal2D(b_temp, 2, 2, 1);
	cvInv(b_temp,b_temp_inv);
	if(debug)
	{
		std::cout << "b_temp\n";
		PrintMatrix(b_temp,3, 3,1);
	
		std::cout << "b_temp_inv\n";
		PrintMatrix(b_temp_inv,3, 3,1);
		std::cout << "......................................................................\n";
		std::cout << "......................................................................\n";
	}
	cvReleaseMat(&b);
	cvReleaseMat(&MUL_8_2N);
	cvReleaseMat(&b_temp);
	//return b_temp;
	return b_temp_inv;
}
Exemplo n.º 7
0
ofxPlane ofxPlane::bestFitPlaneEquation(int n, ofPoint pts[]){
    float sum_i_x = 0;
    float sum_i_xx = 0;
    float sum_i_xy = 0;
    float sum_i_yy = 0;
    float sum_i_y = 0;
    float sum_i_xz = 0;
    float sum_i_yz = 0;
    float sum_i_z = 0;

    for(int i = 0; i < n; i++){
        sum_i_x     +=  pts[i].x;
        sum_i_xx    +=  pts[i].x * pts[i].x;
        sum_i_xy    +=  pts[i].x * pts[i].y;
        sum_i_yy    +=  pts[i].y * pts[i].y;
        sum_i_y     +=  pts[i].y;
        sum_i_xz    +=  pts[i].x * pts[i].z;
        sum_i_yz    +=  pts[i].y * pts[i].z;
        sum_i_z     +=  pts[i].z;
    }

    /*
    If you have n data points (x[i], y[i], z[i]), compute the 3x3 symmetric matrix A whose entries are:

    sum_i x[i]*x[i],    sum_i x[i]*y[i],    sum_i x[i]
    sum_i x[i]*y[i],    sum_i y[i]*y[i],    sum_i y[i]
    sum_i x[i],         sum_i y[i],         n

    */
    CvMat* A = cvCreateMat( 3, 3, CV_32FC1 );
    CvMat* invA = cvCreateMat( 3, 3, CV_32FC1 );
    CV_MAT_ELEM(*A,float,0,0) = sum_i_xx;   CV_MAT_ELEM(*A,float,0,1) = sum_i_xy;   CV_MAT_ELEM(*A,float,0,2) = sum_i_x;    
    CV_MAT_ELEM(*A,float,1,0) = sum_i_xy;   CV_MAT_ELEM(*A,float,1,1) = sum_i_yy;   CV_MAT_ELEM(*A,float,1,2) = sum_i_y;    
    CV_MAT_ELEM(*A,float,2,0) = sum_i_x;    CV_MAT_ELEM(*A,float,2,1) = sum_i_y;    CV_MAT_ELEM(*A,float,2,2) = (float)n;   


    /*
    Also compute the 3 element vector b:

    {sum_i x[i]*z[i],   sum_i y[i]*z[i],    sum_i z[i]}

    */

    CvMat* b = cvCreateMat( 3,1, CV_32FC1 );
    CV_MAT_ELEM(*b,float,0,0) = sum_i_xz;   CV_MAT_ELEM(*b,float,1,0) = sum_i_yz;   CV_MAT_ELEM(*b,float,2,0) = sum_i_z;    

    CvMat* x  = cvCreateMat(3,1,CV_32FC1);

    cvInv(A,invA);

    cvMatMul(invA,b,x);

    //cvSolve(&A, &b, &x, CV_LU);    // solve (Ax=b) for x

    float planeA = CV_MAT_ELEM(*x,float,0,0);
    float planeB = CV_MAT_ELEM(*x,float,1,0);
    float planeC = -1;
    float planeD = -1*CV_MAT_ELEM(*x,float,2,0);

    float z = (-planeD/planeC);

    ofPoint pointRes = ofPoint(0,0,z);

    ofxPlane planeRes;

    ofVec3f normalRes = ofVec3f(planeA,planeB,planeC);
    normalRes.normalize();



    /*
    Then solve Ax = b for the given A and b. The three components of the solution vector are the 
    coefficients to the least-square fit plane {a,b,c}.

    Note that this is the "ordinary least squares" fit, which is appropriate only when z is expected to 
    be a linear function of x and y. If you are looking more generally for a "best fit plane" in 3-space, 
    you may want to learn about "geometric" least squares.

    Note also that this will fail if your points are in a line, as your example points are.


    */


    cvReleaseMat(&A);
    cvReleaseMat(&invA);
    cvReleaseMat(&b);
    cvReleaseMat(&x);
    return ofxPlane(pointRes,normalRes);

}