structs.cpp
Go to the documentation of this file.
00001 /*
00002  * structs.cpp
00003  *
00004  *  Created on: Jul 25, 2010
00005  *      Author: sturm
00006  */
00007 
00008 #include "structs.h"
00009 #include "hogman_wrapper.h"
00010 #include "boost/tuple/tuple.hpp"
00011 
00012 using namespace std;
00013 using namespace articulation_models;
00014 using namespace geometry_msgs;
00015 using namespace articulation_msgs;
00016 using namespace std_msgs;
00017 using namespace sensor_msgs;
00018 using namespace articulation_structure;
00019 using namespace Eigen;
00020 
00021 KinematicParams::KinematicParams() {
00022         sigma_position = 0.005;
00023         sigma_orientation = 0.001;
00024         eval_every = 1;
00025         eval_every_power = 1.0;
00026         supress_similar = false;
00027         reuse_model = true;
00028         restricted_graphs = "";
00029         restrict_graphs = false;
00030         reduce_dofs = false;
00031         search_all_models = false;
00032         full_eval="tree";
00033 }
00034 
00035 void KinematicParams::LoadParams(ros::NodeHandle &nh_local,bool show) {
00036         string filter_models("rigid rotational prismatic");
00037         nh_local.getParam("filter_models", filter_models);
00038         nh_local.getParam("sigma_position", sigma_position);
00039         nh_local.getParam("sigma_orientation", sigma_orientation);
00040         nh_local.getParam("sigmax_position", sigmax_position);
00041         nh_local.getParam("sigmax_orientation", sigmax_orientation);
00042         nh_local.getParam("full_eval", full_eval);
00043         nh_local.getParam("eval_every", eval_every);
00044         nh_local.getParam("eval_every_power", eval_every_power);
00045         nh_local.getParam("restricted_graphs", restricted_graphs);
00046         restricted_graphs = " "+restricted_graphs+" ";
00047         nh_local.getParam("restrict_graphs", restrict_graphs);
00048 
00049         nh_local.getParam("reuse_model", reuse_model);
00050         nh_local.getParam("supress_similar", supress_similar);
00051         nh_local.getParam("reduce_dofs", reduce_dofs);
00052         nh_local.getParam("search_all_models", search_all_models);
00053 
00054         factory.setFilter(filter_models);
00055 
00056 }
00057 
00058 void KinematicData::addPose(PoseStamped pose1, PoseStamped pose2, size_t id1, size_t id2,KinematicParams &params) {
00059         TrackMsgPtr& track = trajectories[id1][id2];
00060         if (!track) {
00061                 track = boost::make_shared<TrackMsg>();
00062                 ChannelFloat32 ch;
00063                 ch.name = "stamp";
00064                 track->channels.push_back(ch);
00065         }
00066 
00067         tf::Transform transf1 = poseToTransform(pose1.pose);
00068         tf::Transform transf2 = poseToTransform(pose2.pose);
00069         tf::Transform diff = transf1.inverseTimes(transf2);
00070 
00071         for(size_t i=0;i<trajectories[id1][id2]->pose.size();i++) {
00072                 tf::Transform diff_to_known;
00073                 Pose p;
00074                 p = trajectories[id1][id2]->pose[i];
00075                 tf::Transform t;
00076                 t = poseToTransform( p );
00077                 diff_to_known = t.inverseTimes( diff );
00078                 double diff_position = diff_to_known.getOrigin().length();
00079                 double diff_orientation = fabs(diff_to_known.getRotation().getAngle());
00080                 if(params.supress_similar && diff_position < params.sigma_position/2 && diff_orientation < params.sigma_orientation/2) {
00081 //                      cout <<"skipping relative pose information, too close to known sample"<<endl;
00082                         return;
00083                 }
00084         }
00085 
00086         poseIndex[id1][id2][ pose1.header.stamp.toSec() ] = track->pose.size();
00087 
00088         track->pose.push_back(transformToPose( diff));
00089         track->channels[0].values.push_back( pose1.header.stamp.toSec() );
00090         track->header = pose1.header;
00091 
00092 //      updateModel(id1, id2);
00093 }
00094 
00095 void KinematicData::updateModel(size_t id1, size_t id2,KinematicParams &params) {
00096         TrackMsgPtr& track = trajectories[id1][id2];
00097         GenericModelPtr& model = models[id1][id2];
00098 
00099         articulation_msgs::ModelMsg model_track;
00100         model_track.track = *track;
00101         model_track.header = track->header;
00102         setParamIfNotDefined(model_track.params, "sigma_position",
00103                         params.sigma_position, ParamMsg::PRIOR);
00104         setParamIfNotDefined(model_track.params, "sigma_orientation",
00105                         params.sigma_orientation, ParamMsg::PRIOR);
00106 
00107         GenericModelVector models_new = params.factory.createModels(model_track);
00108     map<double,GenericModelPtr> models_sorted;
00109     models_all[id1][id2].clear();
00110         for (size_t i = 0; i < models_new.size(); i++) {
00111                 if (!models_new[i]->fitModel()) continue;
00112                 if (!models_new[i]->fitMinMaxConfigurations()) continue;
00113                 if (!models_new[i]->evaluateModel()) continue;
00114                 if(isnan( models_new[i]->getBIC() )) continue;
00115 
00116                 if(params.reuse_model && model && model->getModelName()==models_new[i]->getModelName()) {
00117                         model->setTrack(*track);
00118                         model->optimizeParameters();
00119                         model->evaluateModel();
00120                         if(!isnan( model->getBIC() ) &&
00121                                         (models_new[i]->getBIC() > model->getBIC())) {
00122                                 models_new[i] = model;
00123                         }
00124                 }
00125 
00126                 models_sorted[models_new[i]->getBIC()] = models_new[i];
00127                 models_all[id1][id2].push_back( models_new[i] );
00128         }
00129 
00130         if(models_sorted.size()==0) {
00131                 ROS_INFO_STREAM("no models!! model["<<id1<<","<<id2<<"]: poses="<<track->pose.size());
00132                 model.reset();
00133                 return;
00134         }
00135         map<double,GenericModelPtr>::iterator it = models_sorted.begin();
00136         model = it->second;
00137 
00138 //      model->evaluateModel();
00139 //      while(it!=models_sorted.end()) {
00140 //              ROS_INFO_STREAM(
00141 //                      "model["<<id1<<","<<id2<<"]: poses="<<it->second->getSamples()<<
00142 //                      ", type='"<<it->second->getModelName()<<
00143 //                      ", BIC="<<it->first<<", logDL="<<it->second->loglikelihood<<", k="<<it->second->complexity<<
00144 //                      " pos="<<it->second->getParam("avg_error_position")<<
00145 //                      " orient="<<it->second->getParam("avg_error_orientation")
00146 //              );
00147 //              it++;
00148 //      }
00149 }
00150 
00151 std::vector<double> KinematicData::intersectionOfStamps() {
00152         // timestamps where all markers were detected
00153         std::vector<double> intersection;
00154 
00155         size_t num_markers = markerStamped.size();
00156         for(map<double, map<int, PoseStampedIdMsgConstPtr> >::iterator it = stampedMarker.begin();
00157                         it != stampedMarker.end();
00158                         it++) {
00159                 if(it->second.size() == num_markers) {
00160                         intersection.push_back( it->first );
00161                 }
00162 
00163 //              cout <<"timestamp "<<(it->first - stampedMarker.begin()->first )<<" markers "<<it->second.size()<<" total "<<num_markers<<" ";
00164 //              for(map<int, PoseStampedIdMsgConstPtr>::iterator j = it->second.begin();j!=it->second.end();j++) {
00165 //                      cout << " "<<j->first;
00166 //              }
00167 //              cout << endl;
00168         }
00169 
00170 //      ROS_INFO_STREAM("full visibility rate: "<< intersection.size() / (double) stampedMarker.size() );
00171         return(intersection);
00172 }
00173 
00174 PoseMap KinematicData::getObservation(double timestamp) {
00175         PoseMap observedMarkers;
00176         for(std::map<int, articulation_structure::PoseStampedIdMsgConstPtr>::iterator it = stampedMarker[timestamp].begin();
00177                         it != stampedMarker[timestamp].end();it++) {
00178                 observedMarkers[it->first] = it->second->pose.pose;
00179         }
00180         return observedMarkers;
00181 }
00182 
00183 KinematicGraph::KinematicGraph() {
00184         BIC = DBL_MAX;
00185         DOF = -1;
00186         avg_pos_err = -1;
00187         avg_orient_err = -1;
00188         loglh = DBL_MAX;
00189 }
00190 
00191 KinematicGraph::KinematicGraph(const KinematicGraph &other):
00192         KinematicGraphType( other ), BIC(other.BIC),DOF(other.DOF),avg_pos_err(other.avg_pos_err),avg_orient_err(other.avg_orient_err),loglh(other.loglh)
00193 {
00194 }
00195 
00196 KinematicGraph::KinematicGraph(const KinematicGraph &other,bool deepcopy):
00197                         KinematicGraphType( other ), BIC(other.BIC),DOF(other.DOF),avg_pos_err(other.avg_pos_err),avg_orient_err(other.avg_orient_err),loglh(other.loglh)
00198 {
00199         if(deepcopy) {
00200                 CopyFrom(other);
00201         }
00202 }
00203 
00204 void KinematicGraph::CopyFrom(const KinematicGraph &other) {
00205         *this = other;
00206         static MultiModelFactory factory;
00207         for(KinematicGraph::iterator it=begin();it!=end();it++) {
00208                 it->second = factory.restoreModel(it->second->getModel());
00209         }
00210 }
00211 
00212 
00213 size_t KinematicGraph::getNumberOfParameters() {
00214         size_t k = 0;
00215         for(KinematicGraph::iterator it=begin(); it != end();it++) {
00216                 k += (size_t) it->second->complexity;
00217         }
00218         return k;
00219 }
00220 
00221 
00222 
00223 int KinematicGraph::getNominalDOFs() {
00224         int DOFs = 0;
00225         for(KinematicGraph::iterator it=begin(); it != end();it++) {
00226                 DOFs += it->second->getDOFs();
00227         }
00228         return(DOFs);
00229 }
00230 
00231 PoseMap KinematicGraph::getPrediction(double timestamp, PoseMap &observedMarkers, PoseMap &predictedMarkersEmpty, KinematicParams &params,KinematicData &data) {
00232         return hogman_solver(*this, data.poseIndex, observedMarkers, predictedMarkersEmpty, params.sigma_position,params.sigma_orientation, timestamp);
00233 }
00234 
00235 string KinematicGraph::getTreeName(bool show_name,bool show_samples,bool show_dof) {
00236         stringstream s;
00237         if(show_dof) {
00238                 s << DOF<<"-DOF ";
00239         }
00240         for(KinematicGraph::iterator it=begin(); it != end();it++) {
00241                 if(it != begin()) s<<",";
00242                 s << "(";
00243                 if(show_name) {
00244                         s <<it->second->getModelName().substr(0,2)<<":";
00245                 }
00246                 s <<it->first.first<<","<<it->first.second;
00247                 if(show_samples)
00248                         s << "/"<<it->second->getSamples();
00249                 s<<")";
00250         }
00251         return s.str();
00252 }
00253 
00254 void KinematicGraph::evaluateSingleStamp(double timestamp,
00255                                 double &avgPositionError,
00256                                 double &avgOrientationError,
00257                                 double &loglikelihood,KinematicParams &params,KinematicData &data) {
00258 
00259         if (size()==0) return;
00260         // compare observation versus prediction
00261         PoseMap observationMarkers = data.getObservation(timestamp);
00262         PoseMap predictedMarkers = getPrediction(timestamp,observationMarkers,observationMarkers,params,data);
00263 
00264         // store predicted poses
00265         for(PoseMap::iterator i=predictedMarkers.begin();i!=predictedMarkers.end();i++) {
00266                 PoseStampedIdMsg p = *data.stampedMarker[timestamp][i->first];
00267                 p.pose.pose = i->second;
00268                 PoseStampedIdMsgConstPtr pptr = boost::make_shared<PoseStampedIdMsg>(p);
00269                 data.stampedMarkerProjected[timestamp][i->first] = pptr;
00270         }
00271 
00272         // output data loglikelihood
00273         double sum_loglh = 0;
00274         double sum_pos2_err = 0;
00275         double sum_orient2_err = 0;
00276 
00277         double sigma2_position = SQR(params.sigmax_position);
00278         double sigma2_orientation = SQR(params.sigmax_orientation);
00279 
00280         for(PoseMap::iterator it = observationMarkers.begin();
00281                         it != observationMarkers.end(); it++ ) {
00282                 tf::Transform p1 = poseToTransform(observationMarkers[it->first]);
00283                 tf::Transform p2 = poseToTransform(predictedMarkers[it->first]);
00284 
00285                 tf::Transform diff = p1.inverseTimes(p2);
00286                 double err_position2 = diff.getOrigin().length2();
00287                 if(isnan(err_position2 )) err_position2 =0;
00288                 double err_orientation2 = SQR(diff.getRotation().getAngle());
00289                 if(isnan(err_orientation2 )) err_orientation2 =0;
00290 
00291                 sum_pos2_err += err_position2;
00292                 sum_orient2_err += err_orientation2;
00293 
00294                 double loglikelihood =
00295                                 - log(2*M_PI * params.sigma_position*params.sigma_orientation)
00296                                 - 0.5*(
00297                                                 ( err_position2 / (sigma2_position) ) +
00298                                                 ( err_orientation2 / (sigma2_orientation) ) );  // 2-dim multivariate normal distribution
00299                 sum_loglh += loglikelihood;
00300         }
00301 
00302         size_t n = observationMarkers.size();
00303         avgPositionError = sqrt(sum_pos2_err/n);
00304         avgOrientationError = sqrt(sum_orient2_err/n);
00305         loglikelihood = sum_loglh;
00306 }
00307 
00308 void KinematicGraph::evaluate(
00309                 std::vector<double> stamps,
00310                 KinematicParams &params,KinematicData &data) {
00311         // first, copy our data
00312         static MultiModelFactory factory;
00313         for(KinematicGraph::iterator it=begin();it!=end();it++) {
00314                 it->second = factory.restoreModel(it->second->getModel());
00315         }
00316 
00317         BIC = DBL_MAX;
00318         avg_pos_err = DBL_MAX;
00319         avg_orient_err = DBL_MAX;
00320         loglh = DBL_MIN;
00321 
00322         if (size()==0) return;
00323 
00324         if(DOF != getNominalDOFs())
00325                 projectConfigurationSpace(DOF,stamps,params,data);
00326 
00327 //      cout << getTreeName(true,true,true);
00328 
00329         double sum_pos2_err = 0;
00330         double sum_orient2_err = 0;
00331         double sum_loglh = 0;
00332 
00333         double pos_err,orient_err;
00334 
00335         data.stampedMarkerProjected.clear();
00336         for(size_t i=0;i<stamps.size();i++) {
00337                 evaluateSingleStamp(stamps[i],pos_err, orient_err, loglh,params,data );
00338                 sum_loglh += loglh;
00339                 sum_pos2_err += SQR(pos_err);
00340                 sum_orient2_err += SQR(orient_err);
00341         }
00342 
00343         avg_pos_err = sqrt(sum_pos2_err/stamps.size());
00344         avg_orient_err = sqrt(orient_err/stamps.size());
00345         loglh = sum_loglh;
00346 
00347         k = getNumberOfParameters();
00348         int k_pca = 0;
00349         double loglh_pca;
00350         if(DOF != getNominalDOFs()) {
00351                 k_pca = getNominalDOFs() * DOF; // extra parameters needed to store projection matrix
00352                 loglh_pca = stamps.size() * (getNominalDOFs() - DOF) * log(stamps.size());      // correct likelihood for reduced dimensionality of configuration space
00353         }
00354         BIC = getBIC( loglh + loglh_pca, k + k_pca,stamps.size() );     // BIC with penalty for size of configuratino space
00355 //      cout << ": loglh="<<loglh<<" pos="<<avg_pos_err<<" orient="<<avg_orient_err<<" k="<<k<<" BIC="<<BIC << endl;
00356         return;
00357 }
00358 
00359 void KinematicGraph::projectConfigurationSpace(int reducedDOFs,std::vector<double> stamps, KinematicParams &params,KinematicData &data) {
00360         if(reducedDOFs == 0) return;
00361         if(stamps.size() == 0) return;
00362 
00363         map< GenericModelPtr, int> DOFoffsets;
00364         int DOFs = 0;
00365         for(KinematicGraph::iterator it=begin(); it != end();it++) {
00366                 DOFoffsets[it->second] = DOFs;
00367                 DOFs += it->second->getDOFs();
00368         }
00369         if(DOFs==0) return;
00370 
00371         MatrixXf X_trans(stamps.size(), DOFs);
00372 
00373         for(KinematicGraph::iterator it=begin(); it != end();it++) {
00374                 GenericModelPtr model = it->second;
00375                 int DOFoffset = DOFoffsets[model];
00376 
00377                 if(model->getDOFs()==0) continue;
00378 
00379                 for(size_t timestamp_idx = 0;timestamp_idx < stamps.size();timestamp_idx++) {
00380                         int idx = data.poseIndex[ it->first.first ][it->first.second][ stamps[timestamp_idx]];
00381 
00382                         VectorXd c = model->getConfiguration(idx);
00383                         for(size_t d=0;d< model->getDOFs();d++) {
00384                                 X_trans( timestamp_idx,DOFoffset + d ) = c(d);
00385                         }
00386                 }
00387         }
00388 
00389         VectorXf X_mean = VectorXf::Zero(DOFs,1);
00390         for( size_t i=0;i< stamps.size();i++) {
00391                 for( int j=0;j< DOFs;j++) {
00392                         X_mean(j) += X_trans(i,j);
00393                 }
00394         }
00395         X_mean /= stamps.size();
00396 
00397 
00398         // check for nans or large numbers (crash eigen while svd'ing)
00399         for( int j=0;j< DOFs;j++) {
00400                 if(isnan((double)X_mean(j))) {
00401                         cout << X_trans << endl<<endl;
00402                         cout << X_mean << endl;
00403                         cout <<"reducing DOFs failed, NaN value"<<endl;
00404                         return;
00405                 }
00406                 if(fabs((double)X_mean(j))>100) {
00407                         cout << X_trans << endl<<endl;
00408                         cout << X_mean << endl;
00409                         cout <<"reducing DOFs failed, large value"<<endl;
00410                         return;
00411                 }
00412         }
00413 
00414         MatrixXf X_center(stamps.size(), DOFs);
00415         for( size_t i=0;i< stamps.size();i++) {
00416                 for( int j=0;j< DOFs;j++) {
00417                         X_center(i,j) = X_trans(i,j) - X_mean(j);
00418                 }
00419         }
00420 
00421         if(stamps.size() < (size_t)DOFs) return;
00422 
00423         JacobiSVD<MatrixXf> svdOfA(X_center);
00424 
00425         const Eigen::MatrixXf U = svdOfA.matrixU();
00426         const Eigen::MatrixXf V = svdOfA.matrixV();
00427         const Eigen::VectorXf S = svdOfA.singularValues();
00428 
00429         //DiagonalMatrix<Eigen::VectorXf> S2(S);
00430         Eigen::MatrixXf V_projection = V.block(0,0,DOFs,reducedDOFs);
00431         MatrixXf X_reduced(stamps.size(),reducedDOFs);
00432 
00433         for( size_t i=0;i< stamps.size();i++) {
00434                 for( int k=0;k< reducedDOFs;k++) {
00435                         X_reduced(i,k) = 0.0;
00436                         for( int j=0;j< DOFs;j++) {
00437                                 X_reduced(i,k) += V(j,k) * X_center(i,j);
00438                         }
00439                 }
00440         }
00441 
00442         MatrixXf X_projected(stamps.size(),DOFs);
00443         for( size_t i=0;i< stamps.size();i++) {
00444                 for( int j=0;j< DOFs;j++) {
00445                         X_projected(i,j) = X_mean(j);
00446                         for( int k=0;k< reducedDOFs;k++) {
00447                                 X_projected(i,j) += V(j,k) * X_reduced(i,k);
00448                         }
00449                 }
00450         }
00451 
00452         for(KinematicGraph::iterator it=begin(); it != end();it++) {
00453                 GenericModelPtr model = it->second;
00454                 if(model->getDOFs()==0) continue;
00455                 int DOFoffset = DOFoffsets[model];
00456 
00457                 for(size_t timestamp_idx = 0;timestamp_idx < stamps.size();timestamp_idx++) {
00458                         int idx = data.poseIndex[ it->first.first ][it->first.second][ stamps[timestamp_idx]];
00459 
00460                         VectorXd c(model->getDOFs());
00461                         for(size_t d=0;d< model->getDOFs();d++) {
00462                                 c(d) =X_projected( timestamp_idx,DOFoffset + d );
00463                         }
00464 
00465                         model->setConfiguration(idx,c);
00466                         model->model.track.pose_projected[idx] = model->predictPose( c );
00467                 }
00468         }
00469         DOF = reducedDOFs;
00470 }
00471 
00472 #include "boost/tuple/tuple.hpp"
00473 
00474 int KinematicGraph::distanceTo(KinematicGraph &other) {
00475         int distance = 0;
00476         distance +=fabs((getNominalDOFs()-DOF) - (other.getNominalDOFs()-other.DOF));
00477 
00478         // first only consider edge differences
00479         set< pair<int,int> > my_edges,other_edges,diff_edges;
00480         for(KinematicGraph::iterator it=begin();it!=end();it++) my_edges.insert( pair<int,int>(it->first.first,it->first.second) );
00481         for(KinematicGraph::iterator it = other.begin();it!=other.end();it++) other_edges.insert(pair<int,int>(it->first.first,it->first.second) );
00482         set_symmetric_difference(my_edges.begin(),my_edges.end(),other_edges.begin(),other_edges.end(),insert_iterator<set< pair<int,int> > >(diff_edges,diff_edges.begin()) );
00483         distance += diff_edges.size();  // new/deleted edges
00484 
00485         // now only consider common edges and count model changes
00486         set< pair<pair<int,int>,string> > my_models,other_models,intersec_models,diff_models;
00487         for(KinematicGraph::iterator it=begin();it!=end();it++)
00488                 if(diff_edges.find(it->first)==diff_edges.end())
00489                         my_models.insert( pair<pair<int,int>,string>(pair<int,int>(it->first.first,it->first.second),it->second->getModelName()) );
00490         for(KinematicGraph::iterator it = other.begin();it!=other.end();it++)
00491                 if(diff_edges.find(it->first)==diff_edges.end())
00492                         other_models.insert(pair<pair<int,int>,string>(pair<int,int>(it->first.first,it->first.second),it->second->getModelName()) );
00493         set_symmetric_difference(my_models.begin(),my_models.end(),other_models.begin(),other_models.end(),insert_iterator<set< pair<pair<int,int>,string> > >(diff_models,diff_models.begin()) );
00494         distance += diff_models.size()/2;       // changed models
00495 
00496         return distance;
00497 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


articulation_structure
Author(s): sturm
autogenerated on Wed Dec 26 2012 15:37:59