Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
00079
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
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
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
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
00238 double sqrErrSum = 0;
00239 numInliers = 0;
00240 for (std::vector<MarkerEval>::iterator it = points.begin();
00241 it != points.end(); it++) {
00242
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 }