/* * elch6Dslerp implementation * * Copyright (C) Jochen Sprickerhof * * Released under the GPL version 3. * */ /** * @file ELCH implementation using SLERP * @author Jochen Sprickerhof. Institute of Computer Science, University of Osnabrueck, Germany. */ #include "slam6d/elch6Dslerp.h" #include "slam6d/metaScan.h" #include "slam6d/lum6Dquat.h" #include "slam6d/globals.icc" #include using std::cout; using std::cerr; using std::endl; #include using std::ofstream; #include #include using boost::graph_traits; using namespace NEWMAT; /** * ELCH loop closing function using SLERP * matches first and last scan of a loop with ICP * distributes the error * * @param allScans all laser scans * @param first index of first laser scan in the loop * @param last indes of last laser scan in the loop * @param g graph for loop optimization */ void elch6Dslerp::close_loop(const vector &allScans, int first, int last, graph_t &g) { int n = num_vertices(g); graph_t grb[4]; graph_traits ::edge_iterator ei = edges(g).first; int num_arcs = num_edges(g); int li = 0; #ifdef _OPENMP #pragma omp parallel for firstprivate(li, ei) #endif for(int i = 0; i < num_arcs; i++) { for(;i > li; li++, ei++) ; for(;i < li; li--, ei--) ; Matrix C(7, 7); int from = source(*ei, g); int to = target(*ei, g); lum6DQuat::covarianceQuat(allScans[from], allScans[to], my_icp6D->get_nns_method(), my_icp6D->get_rnd(), my_icp6D->get_max_dist_match2(), &C); C = C.i(); for(int j = 0; j < 3; j++) { #ifdef _OPENMP #pragma omp critical #endif add_edge(from, to, fabs(C(j + 1, j + 1)), grb[j]); } #ifdef _OPENMP #pragma omp critical #endif add_edge(from, to, fabs(C(4, 4)) + fabs(C(5, 5)) + fabs(C(6, 6)) + fabs(C(7, 7)), grb[3]); li++; ei++; } double *weights[4]; for(int i = 0; i < 4; i++) { weights[i] = new double[n]; graph_balancer(grb[i], first, last, weights[i]); } vector meta_start; for(int i = first - 2; i <= first + 2; i++) { if(i >= 0) { meta_start.push_back(allScans[i]); } } MetaScan *start = new MetaScan(meta_start, false, false); //static size of metascan int offset_last_start = 2; int offset_last_end = 0; vector meta_end; for(int i = last - offset_last_start; i <= last + offset_last_end && i < n; i++) { meta_end.push_back(allScans[i]); } MetaScan *end = new MetaScan(meta_end, false, false); double Pl0[16]; memcpy(Pl0, allScans[last]->get_transMat(), 16 * sizeof(double)); my_icp6D->match(start, end); delete start; delete end; // store ICP double Pp0[16]; memcpy(Pp0, allScans[last]->get_transMat(), 16 * sizeof(double)); //compute Delta double Pf0[16], Pf0_inv[16], tmp1[16], tmp2[16], deltaf[16]; memcpy(Pf0, allScans[first]->get_transMat(), 16 * sizeof(double)); M4inv(Pf0, Pf0_inv); MMult(Pf0_inv, Pl0, tmp1); M4inv(tmp1, tmp2); MMult(Pp0, tmp2, tmp1); MMult(Pf0_inv, tmp1, deltaf); double deltaT[3], deltaQ[4]; Matrix4ToQuat(deltaf, deltaQ, deltaT); if(!quiet) { double axisangle[4]; axisangle[0] = deltaQ[0]; axisangle[1] = deltaQ[1]; axisangle[2] = deltaQ[2]; axisangle[3] = deltaQ[3]; QuatToAA(axisangle); cout << "Delta: " << deltaT[0] << " " << deltaT[1] << " " << deltaT[2] << " " << axisangle[0] << " " << axisangle[1] << " " << axisangle[2] << " " << axisangle[3] << endl; } //transform scans double idQ[4] = {1, 0, 0, 0}, rPos[3], rPosQuat[4], delta0[16]; rPos[0] = deltaT[0] * weights[0][0]; rPos[1] = deltaT[1] * weights[1][0]; rPos[2] = deltaT[2] * weights[2][0]; slerp(idQ, deltaQ, weights[3][0], rPosQuat); QuatToMatrix4(rPosQuat, rPos, tmp1); M4inv(tmp1, tmp2); MMult(Pf0, tmp2, delta0); #ifdef _OPENMP #pragma omp parallel for private(rPos, rPosQuat, tmp1, tmp2) #endif for(int i = 1; i < n; i++) { if(i >= last - offset_last_start && i <= last + offset_last_end) { MMult(delta0, Pf0_inv, tmp1); } else { rPos[0] = deltaT[0] * weights[0][i]; rPos[1] = deltaT[1] * weights[1][i]; rPos[2] = deltaT[2] * weights[2][i]; slerp(idQ, deltaQ, weights[3][i], rPosQuat); QuatToMatrix4(rPosQuat, rPos, tmp1); MMult(delta0, tmp1, tmp2); MMult(tmp2, Pf0_inv, tmp1); } allScans[i]->transform(tmp1, Scan::ELCH, i == n-1 ? 2 : 1); } for(int i = 0; i < 4; i++) { delete [] weights[i]; } }