Beispiel #1
0
/*---------------------------------------------------------------
					jacobiansPoseComposition
 ---------------------------------------------------------------*/
void CPosePDF::jacobiansPoseComposition(
	const CPose2D &x,
	const CPose2D &u,
	CMatrixDouble33			 &df_dx,
	CMatrixDouble33			 &df_du,
	const bool compute_df_dx,
	const bool compute_df_du )

{
	const double   spx = sin(x.phi());
	const double   cpx = cos(x.phi());
	if (compute_df_dx)
	{
	/*
		df_dx =
		[ 1, 0, -sin(phi_x)*x_u-cos(phi_x)*y_u ]
		[ 0, 1,  cos(phi_x)*x_u-sin(phi_x)*y_u ]
		[ 0, 0,                              1 ]
	*/
		df_dx.unit(3,1.0);

		const double   xu = u.x();
		const double   yu = u.y();

		df_dx.get_unsafe(0,2) = -spx*xu-cpx*yu;
		df_dx.get_unsafe(1,2) =  cpx*xu-spx*yu;
	}

	if (compute_df_du)
	{
	/*
		df_du =
		[ cos(phi_x) , -sin(phi_x) ,  0  ]
		[ sin(phi_x) ,  cos(phi_x) ,  0  ]
		[         0  ,          0  ,  1  ]
	*/
		// This is the homogeneous matrix of "x":
		df_du.get_unsafe(0,2) =
		df_du.get_unsafe(1,2) =
		df_du.get_unsafe(2,0) =
		df_du.get_unsafe(2,1) = 0;
		df_du.get_unsafe(2,2) = 1;

		df_du.get_unsafe(0,0) =  cpx;
		df_du.get_unsafe(0,1) = -spx;
		df_du.get_unsafe(1,0) =  spx;
		df_du.get_unsafe(1,1) =  cpx;
	}
}
Beispiel #2
0
/*---------------------------------------------------------------
	HornMethod
  ---------------------------------------------------------------*/
double scanmatching::HornMethod(
	const vector_double		&inVector,
	vector_double			&outVector,				// The output vector
	bool forceScaleToUnity )
{
	MRPT_START

	vector_double input;
	input.resize( inVector.size() );
	input = inVector;
	outVector.resize( 7 );

	// Compute the centroids
	TPoint3D	cL(0,0,0), cR(0,0,0);

	const size_t nMatches = input.size()/6;
	ASSERT_EQUAL_(input.size()%6, 0)

	for( unsigned int i = 0; i < nMatches; i++ )
	{
		cL.x += input[i*6+3];
		cL.y += input[i*6+4];
		cL.z += input[i*6+5];

		cR.x += input[i*6+0];
		cR.y += input[i*6+1];
		cR.z += input[i*6+2];
	}

	ASSERT_ABOVE_(nMatches,0)
	const double F = 1.0/nMatches;
	cL *= F;
	cR *= F;

	CMatrixDouble33 S; // S.zeros(); // Zeroed by default

	// Substract the centroid and compute the S matrix of cross products
	for( unsigned int i = 0; i < nMatches; i++ )
	{
		input[i*6+3] -= cL.x;
		input[i*6+4] -= cL.y;
		input[i*6+5] -= cL.z;

		input[i*6+0] -= cR.x;
		input[i*6+1] -= cR.y;
		input[i*6+2] -= cR.z;

		S.get_unsafe(0,0) += input[i*6+3]*input[i*6+0];
		S.get_unsafe(0,1) += input[i*6+3]*input[i*6+1];
		S.get_unsafe(0,2) += input[i*6+3]*input[i*6+2];

		S.get_unsafe(1,0) += input[i*6+4]*input[i*6+0];
		S.get_unsafe(1,1) += input[i*6+4]*input[i*6+1];
		S.get_unsafe(1,2) += input[i*6+4]*input[i*6+2];

		S.get_unsafe(2,0) += input[i*6+5]*input[i*6+0];
		S.get_unsafe(2,1) += input[i*6+5]*input[i*6+1];
		S.get_unsafe(2,2) += input[i*6+5]*input[i*6+2];
	}

	// Construct the N matrix
	CMatrixDouble44 N; // N.zeros(); // Zeroed by default

	N.set_unsafe( 0,0,S.get_unsafe(0,0) + S.get_unsafe(1,1) + S.get_unsafe(2,2) );
	N.set_unsafe( 0,1,S.get_unsafe(1,2) - S.get_unsafe(2,1) );
	N.set_unsafe( 0,2,S.get_unsafe(2,0) - S.get_unsafe(0,2) );
	N.set_unsafe( 0,3,S.get_unsafe(0,1) - S.get_unsafe(1,0) );

	N.set_unsafe( 1,0,N.get_unsafe(0,1) );
	N.set_unsafe( 1,1,S.get_unsafe(0,0) - S.get_unsafe(1,1) - S.get_unsafe(2,2) );
	N.set_unsafe( 1,2,S.get_unsafe(0,1) + S.get_unsafe(1,0) );
	N.set_unsafe( 1,3,S.get_unsafe(2,0) + S.get_unsafe(0,2) );

	N.set_unsafe( 2,0,N.get_unsafe(0,2) );
	N.set_unsafe( 2,1,N.get_unsafe(1,2) );
	N.set_unsafe( 2,2,-S.get_unsafe(0,0) + S.get_unsafe(1,1) - S.get_unsafe(2,2) );
	N.set_unsafe( 2,3,S.get_unsafe(1,2) + S.get_unsafe(2,1) );

	N.set_unsafe( 3,0,N.get_unsafe(0,3) );
	N.set_unsafe( 3,1,N.get_unsafe(1,3) );
	N.set_unsafe( 3,2,N.get_unsafe(2,3) );
	N.set_unsafe( 3,3,-S.get_unsafe(0,0) - S.get_unsafe(1,1) + S.get_unsafe(2,2) );

	// q is the quaternion correspondent to the greatest eigenvector of the N matrix (last column in Z)
	CMatrixDouble44 Z, D;
	vector_double v;

	N.eigenVectors( Z, D );
	Z.extractCol( Z.getColCount()-1, v );

	ASSERTDEB_( fabs( sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3] ) - 1.0 ) < 0.1 );

	// Make q_r > 0
	if( v[0] < 0 ){ v[0] *= -1;	v[1] *= -1;	v[2] *= -1;	v[3] *= -1;	}

	CPose3DQuat q;		// Create a pose rotation with the quaternion
	for(unsigned int i = 0; i < 4; i++ )			// insert the quaternion part
		outVector[i+3] = q[i+3] = v[i];

	// Compute scale
	double	num = 0.0;
	double	den = 0.0;
	for( unsigned int i = 0; i < nMatches; i++ )
	{
		num += square( input[i*6+0] ) + square( input[i*6+1] ) + square( input[i*6+2] );
		den += square( input[i*6+3] ) + square( input[i*6+4] ) + square( input[i*6+5] );
	} // end-for

	// The scale:
	double s = std::sqrt( num/den );

	// Enforce scale to be 1
	if( forceScaleToUnity )
		s = 1.0;

	TPoint3D pp;
	q.composePoint( cL.x, cL.y, cL.z, pp.x, pp.y, pp.z );
	pp*=s;

	outVector[0] = cR.x - pp.x;	// X
	outVector[1] = cR.y - pp.y;	// Y
	outVector[2] = cR.z - pp.z;	// Z

	return s; // return scale
	MRPT_END
}
Beispiel #3
0
/*---------------------------------------------------------------
                    se3_l2  (old "HornMethod()")
  ---------------------------------------------------------------*/
bool se3_l2_internal(
    std::vector<mrpt::math::TPoint3D> & points_this,   // IN/OUT: It gets modified!
    std::vector<mrpt::math::TPoint3D> & points_other,  // IN/OUT: It gets modified!
    mrpt::poses::CPose3DQuat    & out_transform,
    double                     & out_scale,
    bool                         forceScaleToUnity)
{
    MRPT_START

    ASSERT_EQUAL_(points_this.size(),points_other.size())

    // Compute the centroids
    TPoint3D	ct_others(0,0,0), ct_this(0,0,0);
    const size_t nMatches = points_this.size();

    if (nMatches<3)
        return false; // Nothing we can estimate without 3 points!!

    for(size_t i = 0; i < nMatches; i++ )
    {
        ct_others += points_other[i];
        ct_this += points_this [i];
    }

    const double F = 1.0/nMatches;
    ct_others *= F;
    ct_this *= F;

    CMatrixDouble33 S; // Zeroed by default

    // Substract the centroid and compute the S matrix of cross products
    for(size_t i = 0; i < nMatches; i++ )
    {
        points_this[i]  -= ct_this;
        points_other[i] -= ct_others;

        S.get_unsafe(0,0) += points_other[i].x * points_this[i].x;
        S.get_unsafe(0,1) += points_other[i].x * points_this[i].y;
        S.get_unsafe(0,2) += points_other[i].x * points_this[i].z;

        S.get_unsafe(1,0) += points_other[i].y * points_this[i].x;
        S.get_unsafe(1,1) += points_other[i].y * points_this[i].y;
        S.get_unsafe(1,2) += points_other[i].y * points_this[i].z;

        S.get_unsafe(2,0) += points_other[i].z * points_this[i].x;
        S.get_unsafe(2,1) += points_other[i].z * points_this[i].y;
        S.get_unsafe(2,2) += points_other[i].z * points_this[i].z;
    }

    // Construct the N matrix
    CMatrixDouble44 N; // Zeroed by default

    N.set_unsafe( 0,0,S.get_unsafe(0,0) + S.get_unsafe(1,1) + S.get_unsafe(2,2) );
    N.set_unsafe( 0,1,S.get_unsafe(1,2) - S.get_unsafe(2,1) );
    N.set_unsafe( 0,2,S.get_unsafe(2,0) - S.get_unsafe(0,2) );
    N.set_unsafe( 0,3,S.get_unsafe(0,1) - S.get_unsafe(1,0) );

    N.set_unsafe( 1,0,N.get_unsafe(0,1) );
    N.set_unsafe( 1,1,S.get_unsafe(0,0) - S.get_unsafe(1,1) - S.get_unsafe(2,2) );
    N.set_unsafe( 1,2,S.get_unsafe(0,1) + S.get_unsafe(1,0) );
    N.set_unsafe( 1,3,S.get_unsafe(2,0) + S.get_unsafe(0,2) );

    N.set_unsafe( 2,0,N.get_unsafe(0,2) );
    N.set_unsafe( 2,1,N.get_unsafe(1,2) );
    N.set_unsafe( 2,2,-S.get_unsafe(0,0) + S.get_unsafe(1,1) - S.get_unsafe(2,2) );
    N.set_unsafe( 2,3,S.get_unsafe(1,2) + S.get_unsafe(2,1) );

    N.set_unsafe( 3,0,N.get_unsafe(0,3) );
    N.set_unsafe( 3,1,N.get_unsafe(1,3) );
    N.set_unsafe( 3,2,N.get_unsafe(2,3) );
    N.set_unsafe( 3,3,-S.get_unsafe(0,0) - S.get_unsafe(1,1) + S.get_unsafe(2,2) );

    // q is the quaternion correspondent to the greatest eigenvector of the N matrix (last column in Z)
    CMatrixDouble44 Z, D;
    vector<double> v;

    N.eigenVectors( Z, D );
    Z.extractCol( Z.getColCount()-1, v );

    ASSERTDEB_( fabs( sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3] ) - 1.0 ) < 0.1 );

    // Make q_r > 0
    if( v[0] < 0 ) {
        v[0] *= -1;
        v[1] *= -1;
        v[2] *= -1;
        v[3] *= -1;
    }

    // out_transform: Create a pose rotation with the quaternion
    for(unsigned int i = 0; i < 4; i++ )			// insert the quaternion part
        out_transform[i+3] = v[i];

    // Compute scale
    double s;
    if( forceScaleToUnity )
    {
        s = 1.0; // Enforce scale to be 1
    }
    else
    {
        double	num = 0.0;
        double	den = 0.0;
        for(size_t i = 0; i < nMatches; i++ )
        {
            num += square( points_other[i].x ) + square( points_other[i].y ) + square( points_other[i].z );
            den += square( points_this[i].x )  + square( points_this[i].y )  + square( points_this[i].z );
        } // end-for

        // The scale:
        s = std::sqrt( num/den );
    }

    TPoint3D pp;
    out_transform.composePoint( ct_others.x, ct_others.y, ct_others.z, pp.x, pp.y, pp.z );
    pp*=s;

    out_transform[0] = ct_this.x - pp.x;	// X
    out_transform[1] = ct_this.y - pp.y;	// Y
    out_transform[2] = ct_this.z - pp.z;	// Z

    out_scale=s; // return scale
    return true;

    MRPT_END
} // end se3_l2_internal()
Beispiel #4
0
/*---------------------------------------------------------------
			leastSquareErrorRigidTransformation

   Compute the best transformation (x,y,phi) given a set of
	correspondences between 2D points in two different maps.
   This method is intensively used within ICP.
  ---------------------------------------------------------------*/
bool tfest::se2_l2(
	const TMatchingPairList& in_correspondences, TPose2D& out_transformation,
	CMatrixDouble33* out_estimateCovariance)
{
	MRPT_START

	const size_t N = in_correspondences.size();

	if (N < 2) return false;

	const float N_inv = 1.0f / N;  // For efficiency, keep this value.

// ----------------------------------------------------------------------
// Compute the estimated pose. Notation from the paper:
// "Mobile robot motion estimation by 2d scan matching with genetic and
// iterative
// closest point algorithms", J.L. Martinez Rodriguez, A.J. Gonzalez, J. Morales
// Rodriguez, A. Mandow Andaluz, A. J. Garcia Cerezo,
// Journal of Field Robotics, 2006.
// ----------------------------------------------------------------------

// ----------------------------------------------------------------------
//  For the formulas of the covariance, see:
//   http://www.mrpt.org/Paper:Occupancy_Grid_Matching
//   and Jose Luis Blanco's PhD thesis.
// ----------------------------------------------------------------------
#if MRPT_HAS_SSE2
	// SSE vectorized version:

	//{
	//	TMatchingPair dumm;
	//	MRPT_COMPILE_TIME_ASSERT(sizeof(dumm.this_x)==sizeof(float))
	//	MRPT_COMPILE_TIME_ASSERT(sizeof(dumm.other_x)==sizeof(float))
	//}

	__m128 sum_a_xyz = _mm_setzero_ps();  // All 4 zeros (0.0f)
	__m128 sum_b_xyz = _mm_setzero_ps();  // All 4 zeros (0.0f)

	//   [ f0     f1      f2      f3  ]
	//    xa*xb  ya*yb   xa*yb  xb*ya
	__m128 sum_ab_xyz = _mm_setzero_ps();  // All 4 zeros (0.0f)

	for (TMatchingPairList::const_iterator corrIt = in_correspondences.begin();
		 corrIt != in_correspondences.end(); corrIt++)
	{
		// Get the pair of points in the correspondence:
		//   a_xyyx = [   xa     ay   |   xa    ya ]
		//   b_xyyx = [   xb     yb   |   yb    xb ]
		//      (product)
		//            [  xa*xb  ya*yb   xa*yb  xb*ya
		//                LO0    LO1     HI2    HI3
		// Note: _MM_SHUFFLE(hi3,hi2,lo1,lo0)
		const __m128 a_xyz = _mm_loadu_ps(&corrIt->this_x);  // *Unaligned* load
		const __m128 b_xyz =
			_mm_loadu_ps(&corrIt->other_x);  // *Unaligned* load

		const __m128 a_xyxy =
			_mm_shuffle_ps(a_xyz, a_xyz, _MM_SHUFFLE(1, 0, 1, 0));
		const __m128 b_xyyx =
			_mm_shuffle_ps(b_xyz, b_xyz, _MM_SHUFFLE(0, 1, 1, 0));

		// Compute the terms:
		sum_a_xyz = _mm_add_ps(sum_a_xyz, a_xyz);
		sum_b_xyz = _mm_add_ps(sum_b_xyz, b_xyz);

		//   [ f0     f1      f2      f3  ]
		//    xa*xb  ya*yb   xa*yb  xb*ya
		sum_ab_xyz = _mm_add_ps(sum_ab_xyz, _mm_mul_ps(a_xyxy, b_xyyx));
	}

	alignas(MRPT_MAX_ALIGN_BYTES) float sums_a[4], sums_b[4];
	_mm_store_ps(sums_a, sum_a_xyz);
	_mm_store_ps(sums_b, sum_b_xyz);

	const float& SumXa = sums_a[0];
	const float& SumYa = sums_a[1];
	const float& SumXb = sums_b[0];
	const float& SumYb = sums_b[1];

	// Compute all four means:
	const __m128 Ninv_4val =
		_mm_set1_ps(N_inv);  // load 4 copies of the same value
	sum_a_xyz = _mm_mul_ps(sum_a_xyz, Ninv_4val);
	sum_b_xyz = _mm_mul_ps(sum_b_xyz, Ninv_4val);

	// means_a[0]: mean_x_a
	// means_a[1]: mean_y_a
	// means_b[0]: mean_x_b
	// means_b[1]: mean_y_b
	alignas(MRPT_MAX_ALIGN_BYTES) float means_a[4], means_b[4];
	_mm_store_ps(means_a, sum_a_xyz);
	_mm_store_ps(means_b, sum_b_xyz);

	const float& mean_x_a = means_a[0];
	const float& mean_y_a = means_a[1];
	const float& mean_x_b = means_b[0];
	const float& mean_y_b = means_b[1];

	//      Sxx   Syy     Sxy    Syx
	//    xa*xb  ya*yb   xa*yb  xb*ya
	alignas(MRPT_MAX_ALIGN_BYTES) float cross_sums[4];
	_mm_store_ps(cross_sums, sum_ab_xyz);

	const float& Sxx = cross_sums[0];
	const float& Syy = cross_sums[1];
	const float& Sxy = cross_sums[2];
	const float& Syx = cross_sums[3];

	// Auxiliary variables Ax,Ay:
	const float Ax = N * (Sxx + Syy) - SumXa * SumXb - SumYa * SumYb;
	const float Ay = SumXa * SumYb + N * (Syx - Sxy) - SumXb * SumYa;

#else
	// Non vectorized version:
	float SumXa = 0, SumXb = 0, SumYa = 0, SumYb = 0;
	float Sxx = 0, Sxy = 0, Syx = 0, Syy = 0;

	for (TMatchingPairList::const_iterator corrIt = in_correspondences.begin();
		 corrIt != in_correspondences.end(); corrIt++)
	{
		// Get the pair of points in the correspondence:
		const float xa = corrIt->this_x;
		const float ya = corrIt->this_y;
		const float xb = corrIt->other_x;
		const float yb = corrIt->other_y;

		// Compute the terms:
		SumXa += xa;
		SumYa += ya;

		SumXb += xb;
		SumYb += yb;

		Sxx += xa * xb;
		Sxy += xa * yb;
		Syx += ya * xb;
		Syy += ya * yb;
	}  // End of "for all correspondences"...

	const float mean_x_a = SumXa * N_inv;
	const float mean_y_a = SumYa * N_inv;
	const float mean_x_b = SumXb * N_inv;
	const float mean_y_b = SumYb * N_inv;

	// Auxiliary variables Ax,Ay:
	const float Ax = N * (Sxx + Syy) - SumXa * SumXb - SumYa * SumYb;
	const float Ay = SumXa * SumYb + N * (Syx - Sxy) - SumXb * SumYa;

#endif

	out_transformation.phi =
		(Ax != 0 || Ay != 0)
			? atan2(static_cast<double>(Ay), static_cast<double>(Ax))
			: 0.0;

	const double ccos = cos(out_transformation.phi);
	const double csin = sin(out_transformation.phi);

	out_transformation.x = mean_x_a - mean_x_b * ccos + mean_y_b * csin;
	out_transformation.y = mean_y_a - mean_x_b * csin - mean_y_b * ccos;

	if (out_estimateCovariance)
	{
		CMatrixDouble33* C = out_estimateCovariance;  // less typing!

		// Compute the normalized covariance matrix:
		// -------------------------------------------
		double var_x_a = 0, var_y_a = 0, var_x_b = 0, var_y_b = 0;
		const double N_1_inv = 1.0 / (N - 1);

		// 0) Precompute the unbiased variances estimations:
		// ----------------------------------------------------
		for (TMatchingPairList::const_iterator corrIt =
				 in_correspondences.begin();
			 corrIt != in_correspondences.end(); corrIt++)
		{
			var_x_a += square(corrIt->this_x - mean_x_a);
			var_y_a += square(corrIt->this_y - mean_y_a);
			var_x_b += square(corrIt->other_x - mean_x_b);
			var_y_b += square(corrIt->other_y - mean_y_b);
		}
		var_x_a *= N_1_inv;  //  /= (N-1)
		var_y_a *= N_1_inv;
		var_x_b *= N_1_inv;
		var_y_b *= N_1_inv;

		// 1) Compute  BETA = s_Delta^2 / s_p^2
		// --------------------------------
		const double BETA = (var_x_a + var_y_a + var_x_b + var_y_b) *
							pow(static_cast<double>(N), 2.0) *
							static_cast<double>(N - 1);

		// 2) And the final covariance matrix:
		//  (remember: this matrix has yet to be
		//   multiplied by var_p to be the actual covariance!)
		// -------------------------------------------------------
		const double D = square(Ax) + square(Ay);

		C->get_unsafe(0, 0) =
			2.0 * N_inv + BETA * square((mean_x_b * Ay + mean_y_b * Ax) / D);
		C->get_unsafe(1, 1) =
			2.0 * N_inv + BETA * square((mean_x_b * Ax - mean_y_b * Ay) / D);
		C->get_unsafe(2, 2) = BETA / D;

		C->get_unsafe(0, 1) = C->get_unsafe(1, 0) =
			-BETA * (mean_x_b * Ay + mean_y_b * Ax) *
			(mean_x_b * Ax - mean_y_b * Ay) / square(D);

		C->get_unsafe(0, 2) = C->get_unsafe(2, 0) =
			BETA * (mean_x_b * Ay + mean_y_b * Ax) / pow(D, 1.5);

		C->get_unsafe(1, 2) = C->get_unsafe(2, 1) =
			BETA * (mean_y_b * Ay - mean_x_b * Ax) / pow(D, 1.5);
	}

	return true;

	MRPT_END
}