/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef _VCG_MATH_POINTMATCHING_H #define _VCG_MATH_POINTMATCHING_H #include #include #include #include #include namespace vcg { /*! \brief Compute cross covariance It computes the cross covariance matrix of two set of 3D points P and X; it returns also the barycenters of P and X. Ref: Besl, McKay A method for registration of 3d Shapes IEEE TPAMI Vol 14, No 2 1992 */ template void ComputeCrossCovarianceMatrix(const std::vector > &spVec, Point3 &spBarycenter, const std::vector > &tpVec, Point3 &tpBarycenter, Eigen::Matrix3d &m) { assert(spVec.size()==tpVec.size()); m.setZero(); spBarycenter.SetZero(); tpBarycenter.SetZero(); Eigen::Vector3d spe; Eigen::Vector3d tpe; typename std::vector >::const_iterator si,ti; for(si=spVec.begin(),ti=tpVec.begin();si!=spVec.end();++si,++ti){ spBarycenter+=*si; tpBarycenter+=*ti; si->ToEigenVector(spe); ti->ToEigenVector(tpe); m+=spe*tpe.transpose(); } spBarycenter/=spVec.size(); tpBarycenter/=tpVec.size(); spBarycenter.ToEigenVector(spe); tpBarycenter.ToEigenVector(tpe); m/=spVec.size(); m-=spe*tpe.transpose(); } /*! \brief Compute the roto-translation that applied to PMov bring them onto Pfix * Rotation is computed as a quaternion. * * E.g. it find a matrix such that: * * Pfix[i] = res * Pmov[i] * * Ref: * Besl, McKay * A method for registration of 3d Shapes * IEEE TPAMI Vol 14, No 2 1992 */ template < class S > void ComputeRigidMatchMatrix(std::vector > &Pfix, std::vector > &Pmov, Quaternion &q, Point3 &tr) { Eigen::Matrix3d ccm; Point3 bfix,bmov; // baricenter of src e trg ComputeCrossCovarianceMatrix(Pmov,bmov,Pfix,bfix,ccm); Eigen::Matrix3d cyc; // the cyclic components of the cross covariance matrix. cyc=ccm-ccm.transpose(); Eigen::Matrix4d QQ; QQ.setZero(); Eigen::Vector3d D(cyc(1,2),cyc(2,0),cyc(0,1)); Eigen::Matrix3d RM; RM.setZero(); RM(0,0)=-ccm.trace(); RM(1,1)=-ccm.trace(); RM(2,2)=-ccm.trace(); RM += ccm + ccm.transpose(); QQ(0,0) = ccm.trace(); QQ.block<1,3> (0,1) = D.transpose(); QQ.block<3,1> (1,0) = D; QQ.block<3,3> (1,1) = RM; Eigen::SelfAdjointEigenSolver eig(QQ); Eigen::Vector4d eval = eig.eigenvalues(); Eigen::Matrix4d evec = eig.eigenvectors(); // std::cout << "EigenVectors:" << std::endl << evec << std::endl; // std::cout << "Eigenvalues:" << std::endl << eval << std::endl; int ind; eval.cwiseAbs().maxCoeff(&ind); q=Quaternion(evec.col(ind)[0],evec.col(ind)[1],evec.col(ind)[2],evec.col(ind)[3]); Matrix44 Rot; q.ToMatrix(Rot); tr= (bfix - Rot*bmov); } /*! \brief Compute the roto-translation that applied to PMov bring them onto Pfix * Rotation is computed as a quaternion. * * E.g. it find a matrix such that: * * Pfix[i] = res * Pmov[i] * * Ref: * Besl, McKay * A method for registration of 3d Shapes * IEEE TPAMI Vol 14, No 2 1992 */ template < class S > void ComputeRigidMatchMatrix(std::vector > &Pfix, std::vector > &Pmov, Matrix44 &res) { Quaternion q; Point3 tr; ComputeRigidMatchMatrix(Pfix,Pmov,q,tr); Matrix44 Rot; q.ToMatrix(Rot); Matrix44 Trn; Trn.SetTranslate(tr); res=Trn*Rot; } /* Compute a similarity matching (rigid + uniform scaling) simply create a temporary point set with the correct scaling factor */ template void ComputeSimilarityMatchMatrix(std::vector > &Pfix, std::vector > &Pmov, Matrix44 &res) { S scalingFactor=0; for(size_t i=0;i<( Pmov.size()-1);++i) { scalingFactor += Distance(Pmov[i],Pmov[i+1])/ Distance(Pfix[i],Pfix[i+1]); } scalingFactor/=(Pmov.size()-1); std::vector > Pnew(Pmov.size()); for(size_t i=0;i scaleM; scaleM.SetDiagonal(1.0/scalingFactor); res = res * scaleM; } } // end namespace #endif