posetracker.cpp
Go to the documentation of this file.
00001 /***************************************************************
00002  * ROS port of ROBULAR implementation
00003  *
00004  * Original header: 
00005  * *
00006  * This source code is part of ROBULAR.
00007  *
00008  * ROBULAR Copyright (c) 2009 Joerg Mueller, Boris Lau, Kai
00009  * Wurm. Autonomous Intelligent Systems, Department of Computer
00010  * Science, University of Freiburg, Germany.
00011  **************************************************************/
00012 
00013 #include "posetracker.h"
00014 #include <fstream>
00015 #include <Eigen/SVD>
00016 #include <eigen_conversions/eigen_msg.h>
00017 
00018   PoseTracker::PoseTracker() :
00019       initialized(false)
00020   {
00021     debug = false;
00022   }
00023 
00024   void PoseTracker::setDebug(bool d)
00025   {
00026     debug = d;
00027   }
00028 
00029   void PoseTracker::init(const std::string &propFile, double scale, tf::TransformBroadcaster* bc, double _sqrErrThreshold, bool _useRansac, unsigned int _numRansacSamples)
00030   {
00031 
00032     broadcaster = bc;
00033 
00034     sqrErrThreshold = _sqrErrThreshold;
00035     useRansac = _useRansac;
00036     numRansacSamples = _numRansacSamples;
00037 
00038     std::cerr << "=== Initialized PoseTracker ===\n";
00039     std::cerr << "scale " << scale << " m (only used for parsing propFile)\n";
00040     std::cerr << "propFile " << propFile << "\n";
00041     std::cerr << "bodyName " << bodyName << "\n";
00042     std::cerr << "sqrErrThreshold " << sqrErrThreshold << " m^2\n";
00043     std::cerr << "useRansac " << useRansac << "\n";
00044     std::cerr << "numRansacSamples " << numRansacSamples << "\n";
00045     std::cerr << "===============================\n";
00046 
00047     parsePropFile(propFile, scale);
00048     initialized = true;
00049   }
00050 
00051 
00052   void PoseTracker::process(const visualization_msgs::MarkerArray::ConstPtr &msg)
00053   {
00054     if (!initialized)
00055       return;
00056 
00057       calculatePose(msg);
00058   }
00059 
00060   bool PoseTracker::calculatePose(const visualization_msgs::MarkerArray::ConstPtr &m)
00061   {
00062 
00063     bool foundBody = false;
00064     unsigned int bodyIdx;
00065     for(unsigned int i=0; i<m->markers.size(); i++){
00066       if(m->markers.at(i).ns == bodyName){
00067         foundBody = true;
00068         bodyIdx = i;
00069         break;
00070       }
00071 
00072       if(!foundBody){
00073         std::cerr << "Error: body " << bodyName << " was not detected\n";
00074         return false;
00075       }
00076     }
00077 
00078     // calculate robot pose from markers and configuration
00079     // collect evaluation data
00080     markerEval.clear();
00081     for(unsigned int i=0; i<m->markers[bodyIdx].points.size(); ++i){
00082 
00083       double posx = m->markers[bodyIdx].points.at(i).x;
00084       double posy = m->markers[bodyIdx].points.at(i).y;
00085       double posz = m->markers[bodyIdx].points.at(i).z;
00086 
00087       if(isnan(posx) || isnan(posy))
00088         continue;
00089 
00090       MarkerEval me;
00091       me.model = bodyMarkerPositions[i];
00092       me.real(0) = posx;
00093       me.real(1) = posy;
00094       me.real(2) = posz;
00095       me.use = false;
00096       markerEval.push_back(me);
00097     }
00098 
00099     if (useRansac) {
00100       std::vector<MarkerEval> best;
00101       int bestInliers = 0;
00102 
00103       if (markerEval.size() > 6) {
00104         // real RANSAC
00105         for (int i=0; i<numRansacSamples; i++) {
00106           int useIdx[3];
00107           useIdx[0] = rand()/(double) RAND_MAX * markerEval.size()-1;
00108           useIdx[1] = rand()/(double) RAND_MAX * markerEval.size()-2;
00109           useIdx[2] = rand()/(double) RAND_MAX * markerEval.size()-3;
00110           if (useIdx[1] >= useIdx[0])
00111             useIdx[1]++;
00112           if (useIdx[2] >= std::min(useIdx[0], useIdx[1]))
00113             useIdx[2]++;
00114           if (useIdx[2] >= std::max(useIdx[0], useIdx[1]))
00115             useIdx[2]++;
00116           std::vector<MarkerEval> sample = markerEval;
00117           sample[useIdx[0]].use = true;
00118           sample[useIdx[1]].use = true;
00119           sample[useIdx[2]].use = true;
00120           Eigen::Affine3d sp;
00121           int si = 0;
00122           getConsensus(sample, sp, si);
00123           if (si > bestInliers) {
00124             best = sample;
00125             bestInliers = si;
00126           }
00127         }
00128       } else {
00129         // try all combinations for model fitting
00130         for (unsigned int i=0; i<markerEval.size(); i++) {
00131           for (unsigned int j=i+1; j<markerEval.size(); j++) {
00132             for (unsigned int k=j+1; k<markerEval.size(); k++) {
00133               std::vector<MarkerEval> sample = markerEval;
00134               sample[i].use = true;
00135               sample[j].use = true;
00136               sample[k].use = true;
00137               Eigen::Affine3d sp;
00138               int si = 0;
00139               getConsensus(sample, sp, si);
00140               if (si > bestInliers) {
00141                 best = sample;
00142                 bestInliers = si;
00143               }
00144             }
00145           }
00146         }
00147       }
00148       if (bestInliers < 3) {
00149         std::cerr << "too less inliers (" << bestInliers << ") - withdraw\n";
00150         return false;
00151       }
00152       markerEval = best;
00153     } else {
00154       for (std::vector<MarkerEval>::iterator it = markerEval.begin();
00155           it != markerEval.end(); it++) {
00156         it->use = true;
00157       }
00158     }
00159 
00160 
00161     Eigen::Affine3d p;
00162     int numInliers = 0;
00163     double sqrErrSum = getConsensus(markerEval, p, numInliers);
00164 
00165     if (sqrErrSum > sqrErrThreshold) {
00166       std::cerr << "Warning: Too high remaining sum of squared position errors: " << sqrErrSum << " - no pose found\n";
00167       return false;
00168     }
00169 
00170     if (debug) {
00171       std::cerr << "Transformation (" << markerEval.size() << ") " << p.translation() <<" " <<p.rotation() << ", num inliers " << numInliers << ", sqrt(squared error sum) " << sqrt(sqrErrSum) << "\n";
00172     }
00173 
00174     geometry_msgs::Pose geo_pose;
00175     tf::poseEigenToMsg(p, geo_pose);
00176 
00177     geometry_msgs::TransformStamped transf;
00178     transf.transform.translation.x = geo_pose.position.x;
00179     transf.transform.translation.y = geo_pose.position.y;
00180     transf.transform.translation.z = geo_pose.position.z;
00181 
00182     transf.transform.rotation = geo_pose.orientation;
00183     transf.header.stamp = m->markers[bodyIdx].header.stamp;
00184     transf.header.frame_id = m->markers[bodyIdx].header.frame_id;
00185     transf.header.seq = m->markers[bodyIdx].header.seq;
00186     transf.child_frame_id = bodyName;
00187 
00188 
00189     broadcaster->sendTransform(transf);
00190     return true;
00191   }
00192 
00193   double PoseTracker::getConsensus(std::vector<MarkerEval> &points, Eigen::Affine3d &p, int &numInliers)
00194   {
00195     int useCount = 0;
00196     Eigen::Vector3d modelSum, realSum;
00197     for (std::vector<MarkerEval>::const_iterator it = points.begin();
00198         it != points.end(); it++) {
00199       if (it->use) {
00200         modelSum += it->model;
00201         realSum += it->real;
00202         useCount++;
00203       }
00204     }
00205 
00206     if (useCount < 3) {
00207       std::cerr << "Error: not enough markers selected for model fitting (" << useCount << ")\n";
00208       return -1;
00209     }
00210 
00211     // get transformation by 1 ICP step
00212     modelSum /= useCount;
00213     realSum /= useCount;
00214 
00215     Eigen::Matrix3d W;
00216     for (std::vector<MarkerEval>::const_iterator it = points.begin();
00217         it != points.end(); it++) {
00218       W = W + (it->real-realSum) * (it->model-modelSum).transpose();
00219     }
00220 
00221     Eigen::JacobiSVD<Eigen::Matrix3d> svd(W, Eigen::ComputeFullU | Eigen::ComputeFullV);
00222     Eigen::Matrix3d U = svd.matrixU();
00223     Eigen::Matrix3d V = svd.matrixV();
00224     Eigen::Vector3d d = svd.singularValues();
00225 
00226     Eigen::Matrix3d S;
00227     S.setIdentity();
00228 
00229     if (U.determinant() * V.determinant() < 0)
00230       S(2,2) = -1;
00231     Eigen::Matrix3d rotM = (U*S)*V.transpose();
00232     Eigen::Vector3d t = realSum - rotM*modelSum;
00233     p.setIdentity();
00234     p.translate(t);
00235     p.rotate(rotM);
00236 
00237     // calculate inliers and squared error
00238     double sqrErrSum = 0;
00239     numInliers = 0;
00240     for (std::vector<MarkerEval>::iterator it = points.begin();
00241         it != points.end(); it++) {
00242 //      it->sqrErr = p.transform(it->model).sqrDist(it->real); // less efficient
00243       Eigen::Vector3d tmp = it->real - rotM*it->model - t;
00244       it->sqrErr = tmp.dot(tmp);
00245       if (it->sqrErr < sqrErrThreshold) {
00246         numInliers++;
00247         sqrErrSum += it->sqrErr;
00248         it->use = true;
00249       }
00250     }
00251     return sqrErrSum;
00252   }
00253 
00254 
00255   void PoseTracker::parsePropFile(const std::string &logfile, double scale){
00256     std::ifstream is(logfile.c_str());
00257     if (!is.is_open()) {
00258       std::cerr << "Error while opening prop-file '" << logfile << "'.\n";
00259       return;
00260     }
00261 
00262     std::string line;
00263     getline(is, line);
00264     if (line.find("[RigidBody]") == std::string::npos) {
00265       std::cerr << "Object of prop file has to be a rigid body\n";
00266       return;
00267     }
00268     getline(is, line);
00269     if (line.find("Name=") == std::string::npos) {
00270       std::cerr << "Expected name in second line\n";
00271       return;
00272     }
00273     bodyName = line.substr(5);
00274     if (bodyName[bodyName.length()-1] == '\r')
00275       bodyName = bodyName.substr(0, bodyName.length()-1);
00276     while (!is.eof() && line.find("NumberOfMarkers=") == std::string::npos) {
00277       getline(is, line);
00278     }
00279     if (is.eof()) {
00280       std::cerr << "Error while parsing prop-file\n";
00281       return;
00282     }
00283     int numMarkers = atoi(line.substr(16).c_str());
00284     std::cerr << "Reading object '" << bodyName << "' with " << numMarkers << " markers\n";
00285     for (int i=0; i<numMarkers; i++) {
00286       getline(is, line);
00287       size_t pos;
00288       while ((pos = line.find(',')) != std::string::npos)
00289         line[pos] = ' ';
00290 
00291       Eigen::Vector3d markerpos;
00292       std::istringstream ss(line);
00293       ss >> markerpos(0);
00294       ss >> markerpos(1);
00295       ss >> markerpos(2);
00296       markerpos *= scale;
00297       double dummy;
00298       ss >> dummy;
00299       std::string markerName;
00300       ss >> markerName;
00301       if (ss.fail()) {
00302         std::cerr << "Failed to read marker " << i << "\n";
00303         return;
00304       }
00305       bodyMarkerPositions.push_back(markerpos);
00306       bodyMarkerNames.push_back(markerName);
00307     }
00308   }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


cortex_stream
Author(s): Daniel Maier
autogenerated on Wed Oct 31 2012 08:22:56