/* * icp6Dhelix implementation * * Copyright (C) Peter Schneider, Andreas Nuechter * * Released under the GPL version 3. * */ /** @file * @brief Implementation of the ICP error function minimization via helix-translation * @author Peter Schneider. Institute of Computer Science, University of Koblenz and Landau, Germany. * @author Andreas Nuechter. Jacobs University Bremen gGmbH, Germany */ #include "slam6d/icp6Dhelix.h" #include "slam6d/globals.icc" #include using std::ios; using std::resetiosflags; using std::setiosflags; #include "newmat/newmat.h" #include "newmat/newmatap.h" using namespace NEWMAT; #include /** * computes a rotation matrix that rotates the points around an axis * and a translation vector, that translates the points along a vector * that is parallel to the rotation axis. Thus the result is a helical * translation of the points that can be resolved thru a vector field * v(x) = cs + c cross x, where cs and c can be build out of an error * minimization function. * * See: * H. Pottmann, S. Leopoldseder, and M. Hofer. Simultaneous * registration of multiple views of a 3D object. * ISPRS Archives 34/3A (2002), 265-270. * * @param Pairs Vector of point pairs (pairs of corresponding points) * @param alignxf The resulting transformation matrix * @return Error estimation of the matching (rms) */ double icp6D_HELIX::Point_Point_Align(const vector& Pairs, double *alignxf, const double centroid_m[3], const double centroid_d[3]) { int n = Pairs.size(); int i; double sum = 0; double error; Matrix matB(6,6); ColumnVector bdVec(6), ccs(6), c(3), cs(3); matB = 0.0; double p2x, p2y, p2z, pDistX, pDistY, pDistZ; double B[6][3]; memset(&B[0][0], 0, 18 * sizeof(double)); double bd[6]; memset(&bd[0], 0, 6 * sizeof(double)); for (i = 0; i < n; i++) { p2x = Pairs[i].p2.x; p2y = Pairs[i].p2.y; p2z = Pairs[i].p2.z; B[4][0] += -p2z; B[3][1] += p2z; B[5][0] += p2y; B[3][2] += -p2y; B[4][2] += p2x; B[5][1] += -p2x; B[0][0] += p2z*p2z + p2y*p2y; B[1][0] += p2y*-p2x; B[2][0] += -p2z*p2x; B[1][1] += p2z*p2z + p2x*p2x; B[2][1] += p2z*-p2y; B[2][2] += p2x*p2x + p2y*p2y; pDistX = p2x - Pairs[i].p1.x; pDistY = p2y - Pairs[i].p1.y; pDistZ = p2z - Pairs[i].p1.z; bd[0] += -p2z*pDistY + p2y*pDistZ; bd[1] += p2z*pDistX - p2x*pDistZ; bd[2] += -p2y*pDistX + p2x*pDistY; bd[3] += pDistX; bd[4] += pDistY; bd[5] += pDistZ; sum += pDistX*pDistX + pDistY*pDistY + pDistZ*pDistZ; } matB(4,4) = matB(5,5) = matB(6,6) = n; matB(1,5) = matB(5,1) = B[4][0]; matB(2,4) = matB(4,2) = B[3][1]; matB(1,6) = matB(6,1) = B[5][0]; matB(3,4) = matB(4,3) = B[3][2]; matB(3,5) = matB(5,3) = B[4][2]; matB(2,6) = matB(6,2) = B[5][1]; matB(1,2) = matB(2,1) = B[1][0]; matB(1,3) = matB(3,1) = B[2][0]; matB(2,3) = matB(3,2) = B[2][1]; matB(1,1) = B[0][0]; matB(2,2) = B[1][1]; matB(3,3) = B[2][2]; bdVec(1) = bd[0]; bdVec(2) = bd[1]; bdVec(3) = bd[2]; bdVec(4) = bd[3]; bdVec(5) = bd[4]; bdVec(6) = bd[5]; error = sqrt( sum / (double) n ); if (!quiet) { cout.setf(ios::basefield); cout << "HELIX RMS point-to-point error = " << resetiosflags(ios::adjustfield) << setiosflags(ios::internal) << resetiosflags(ios::floatfield) << setiosflags(ios::fixed) << std::setw(10) << std::setprecision(7) << error << " using " << std::setw(6) << n << " points" << endl; } ccs = matB.i() * bdVec; int vectorOffset = 0; computeRt( &ccs, vectorOffset, alignxf); return error; } void icp6D_HELIX::computeRt(const ColumnVector* ccs, const int vectorOffset, double *alignxf) { ColumnVector c(3), cs(3); c(1) = -(*ccs)(vectorOffset + 1); c(2) = -(*ccs)(vectorOffset + 2); c(3) = -(*ccs)(vectorOffset + 3); cs(1) = -(*ccs)(vectorOffset + 4); cs(2) = -(*ccs)(vectorOffset + 5); cs(3) = -(*ccs)(vectorOffset + 6); double CLength = sqrt(c.SumSquare()); double rotationCheck = c(1)*cs(1) + c(2)*cs(2) + c(3)*cs(3); //c.t() * cs; Matrix R (3,3); double angle = atan(CLength); //bemerkung: hier minus gesetzt ColumnVector g = c / CLength; double b0, b1, b2, b3; double sinAngle = sin(-angle/2); b0 = cos(-angle/2); b1 = g(1) * sinAngle; b2 = g(2) * sinAngle; b3 = g(3) * sinAngle; R(1,1) = b0*b0 + b1*b1 - b2*b2 - b3*b3; R(1,2) = 2*(b1*b2 + b0*b3); R(1,3) = 2*(b1*b3 - b0*b2); R(2,1) = 2*(b1*b2 - b0*b3); R(2,2) = b0*b0 - b1*b1 + b2*b2 - b3*b3; R(2,3) = 2*(b2*b3 + b0*b1); R(3,1) = 2*(b1*b3 + b0*b2); R(3,2) = 2*(b2*b3 - b0*b1); R(3,3) = b0*b0 - b1*b1 - b2*b2 + b3*b3; R = R / (b0*b0 + b1*b1 + b2*b2 + b3*b3); double skewValue = rotationCheck / (CLength*CLength); ColumnVector gs = (cs - (c * skewValue)) / CLength; ColumnVector pTemp(3); pTemp(1) = g(2)*gs(3) - g(3)*gs(2); pTemp(2) = g(3)*gs(1) - g(1)*gs(3); pTemp(3) = g(1)*gs(2) - g(2)*gs(1); ColumnVector t = R * -pTemp + g*(skewValue * angle) + pTemp; alignxf[0] = R(1,1); alignxf[1] = R(2,1); alignxf[2] = R(3,1); alignxf[3] = 0; alignxf[4] = R(1,2); alignxf[5] = R(2,2); alignxf[6] = R(3,2); alignxf[7] = 0; alignxf[8] = R(1,3); alignxf[9] = R(2,3); alignxf[10] = R(3,3); alignxf[11] = 0; alignxf[12] = t(1); alignxf[13] = t(2); alignxf[14] = t(3); alignxf[15] = 1; }