dynamic_trails.cpp
Go to the documentation of this file.
00001 #include <fstream>
00002 
00003 #include <boost/version.hpp>
00004 #include <deque>
00005 
00006 
00007 #include "ros/ros.h"
00008 #include "ros/console.h"
00009 #include "pointmatcher/PointMatcher.h"
00010 #include "pointmatcher/Timer.h"
00011 
00012 #include "nabo/nabo.h"
00013 
00014 #include "pointmatcher_ros/point_cloud.h"
00015 #include "pointmatcher_ros/transform.h"
00016 #include "pointmatcher_ros/get_params_from_server.h"
00017 #include "pointmatcher_ros/ros_logger.h"
00018 
00019 #include "nav_msgs/Odometry.h"
00020 #include "tf/transform_broadcaster.h"
00021 #include "tf_conversions/tf_eigen.h"
00022 #include "tf/transform_listener.h"
00023 
00024 #include <message_filters/subscriber.h>
00025 #include <message_filters/synchronizer.h>
00026 #include <message_filters/sync_policies/exact_time.h>
00027 
00028 #include <visualization_msgs/Marker.h>
00029 
00030 #include "std_msgs/String.h"
00031 #include "std_srvs/Empty.h"
00032 
00033 using namespace std;
00034 using namespace PointMatcherSupport;
00035 using namespace visualization_msgs;
00036 
00037 typedef PointMatcher<float> PM;
00038 typedef PM::DataPoints DP;
00039 
00040 class DynamicTrails
00041 {
00042         typedef PM::TransformationParameters TP;
00043         typedef PM::Matches Matches;
00044         
00045         typedef typename Nabo::NearestNeighbourSearch<float> NNS;
00046         typedef typename NNS::SearchType NNSearchType;
00047 
00048         ros::NodeHandle& n;
00049         ros::NodeHandle& pn;
00050 
00051         //message_filters::Subscriber<sensor_msgs::PointCloud2> cloud_sub;
00052         //message_filters::Subscriber<nav_msgs::Odometry> odom_sub;
00053 
00054         //typedef message_filters::sync_policies::ExactTime<sensor_msgs::PointCloud2, nav_msgs::Odometry> MySyncPolicy;
00055         //message_filters::Synchronizer<MySyncPolicy> sync;
00056 
00057         ros::Subscriber scanSub;
00058         ros::Subscriber cloudSub;
00059         ros::Subscriber mapSub;
00060         ros::Publisher lastPub;
00061         ros::Publisher dynPub;
00062         ros::Publisher lastProjectedPub;
00063         ros::Publisher dynProjectedPub;
00064         ros::Publisher markerPub;
00065 
00066         PM::DataPointsFilters inputFilters;
00067         unique_ptr<PM::Transformation> transformation;
00068         shared_ptr<DP> lastPointCloud;
00069         shared_ptr<DP> trailPointCloud;
00070         PM::DataPoints globalMap;
00071         
00072         std::shared_ptr<NNS> globalNNS;
00073         std::shared_ptr<NNS> lastNNS;
00074 
00075         boost::mutex usingGlobalMap;
00076         
00077         std::deque<shared_ptr<DP>> priors;
00078 
00079         // tf
00080         tf::TransformListener tfListener;
00081 
00082         boost::mutex publishLock;
00083         
00084         const float eps;
00085         ros::Time lastInputTime;
00086 
00087         // Parameters
00088         const string p_mapFrame;
00089         const float p_minDynamicRatio;
00090         const float p_normalSpaceFactor;
00091         const float p_maxVelocity;
00092         const float p_inputRate;
00093         const int p_windowSize;
00094         const string p_trailFilepName;
00095   const bool p_accumulateMarkers;
00096         const float p_maxGlobalMapDist;
00097         const float p_maxClusterDistance;
00098         
00099   int trailCount;
00100         
00101 public:
00102         DynamicTrails(ros::NodeHandle& n, ros::NodeHandle& pn);
00103         ~DynamicTrails();
00104         
00105 protected:
00106         //void gotCloud(const sensor_msgs::PointCloud2ConstPtr& cloudMsgIn, const nav_msgs::OdometryConstPtr& odom);
00107         void gotCloud(const sensor_msgs::PointCloud2ConstPtr& cloudMsgIn);
00108         void gotMap(const sensor_msgs::PointCloud2& cloudMsgIn);
00109         void processCloud(DP cloud, const TP TScannerToMap);
00110         PM::DataPoints extractDynamicPoints(const PM::DataPoints input, const float minDynamicRatio);
00111         void computeVelocity(shared_ptr<DP> reference, shared_ptr<NNS> ref_tree, shared_ptr<DP> reading, shared_ptr<NNS> read_tree, const float maxRadius, const int knn, ros::Publisher debugPub);
00112         float angleWeight(const Eigen::Vector3f &normal, const Eigen::Vector3f &velocity);
00113         
00114         void averageWithReference(shared_ptr<DP> reference, shared_ptr<DP> reading, const float dir);
00115 
00116 };
00117 
00118 DynamicTrails::DynamicTrails(ros::NodeHandle& n, ros::NodeHandle& pn):
00119         n(n),
00120         pn(pn),
00121         //cloud_sub(n, "cloud_in", 1),
00122         //odom_sub(n, "icp_odom", 1),
00123         //sync(MySyncPolicy(10), cloud_sub, odom_sub),
00124         transformation(PM::get().REG(Transformation).create("RigidTransformation")),
00125         lastPointCloud(0),
00126         trailPointCloud(0),
00127   tfListener(ros::Duration(30)),
00128         eps(0.0001),
00129         p_mapFrame(getParam<string>("map_frame", "map")),
00130         p_minDynamicRatio(getParam<double>("min_dynamic_ratio", 0.75)),
00131         p_normalSpaceFactor(getParam<double>("normal_space_factor", 1.0)),
00132         p_maxVelocity(getParam<double>("max_velocity", 12.0)),
00133         p_inputRate(getParam<double>("input_rate", 1.5)),
00134         p_windowSize(getParam<int>("window_size", 3)),
00135         p_trailFilepName(getParam<string>("trail_filename", "trailMap.vtk")),
00136         p_accumulateMarkers(getParam<bool>("accumulate_markers", false)),
00137         p_maxGlobalMapDist(getParam<double>("max_global_map_dist", 0.5)),
00138         p_maxClusterDistance(getParam<double>("max_cluster_distance", 0.75)),
00139         trailCount(0)
00140 {
00141         
00142         // memory for last velocities
00143         priors.resize(p_windowSize+1);
00144 
00145 
00146         // load configs
00147         string configFileName;
00148 
00149         if (ros::param::get("~inputFiltersConfig", configFileName))
00150         {
00151                 ifstream ifs(configFileName.c_str());
00152                 if (ifs.good())
00153                 {
00154                         inputFilters = PM::DataPointsFilters(ifs);
00155                 }
00156                 else
00157                 {
00158                         ROS_ERROR_STREAM("Cannot load input filters config from YAML file " << configFileName);
00159                 }
00160         }
00161         else
00162         {
00163                 ROS_INFO_STREAM("No input filters config file given, not using these filters");
00164         }
00165 
00166         
00167         // topics and services initialization
00168         //sync.registerCallback(boost::bind(&DynamicTrails::gotCloud, this, _1, _2));
00169         
00170         cloudSub = n.subscribe("cloud_in", 10, &DynamicTrails::gotCloud, this);
00171         mapSub = n.subscribe("point_map", 1, &DynamicTrails::gotMap, this);
00172         lastPub = n.advertise<sensor_msgs::PointCloud2>("last_dynamic_points", 2, true);
00173         dynPub = n.advertise<sensor_msgs::PointCloud2>("current_dynamic_points", 2, true);
00174         lastProjectedPub= n.advertise<sensor_msgs::PointCloud2>("last_projected_points", 2, true);
00175         dynProjectedPub= n.advertise<sensor_msgs::PointCloud2>("dyn_projected_points", 2, true);
00176         markerPub = n.advertise<visualization_msgs::Marker>("dynamic_trail", 1);
00177                 
00178 }
00179 
00180 DynamicTrails::~DynamicTrails()
00181 {
00182         // save point cloud
00183         
00184         if (trailPointCloud)
00185         {
00186                 trailPointCloud->save(p_trailFilepName);
00187         }
00188 
00189 }
00190 
00191 // Callback
00192 void DynamicTrails::gotMap(const sensor_msgs::PointCloud2& cloudMsgIn)
00193 {
00194         cout << "Map received" << endl;
00195         usingGlobalMap.lock();
00196         // Convert pointcloud2 to DataPoint
00197         globalMap = PointMatcher_ros::rosMsgToPointMatcherCloud<float>(cloudMsgIn);
00198         
00199         // Build a kd-tree
00200         globalNNS.reset( NNS::create(globalMap.features, globalMap.features.rows() - 1, NNS::KDTREE_LINEAR_HEAP, NNS::TOUCH_STATISTICS));
00201         usingGlobalMap.unlock();
00202 }
00203 
00204 
00205 
00206 void DynamicTrails::gotCloud(const sensor_msgs::PointCloud2ConstPtr& cloudMsgIn)
00207 {
00208         // IMPORTANT:  We need to receive the point clouds in local coordinates (scanner or robot)
00209 
00210         const ros::Time currentTime = ros::Time::now();
00211         const float currentRate = 1.0/(currentTime - lastInputTime).toSec();
00212         
00213         if(currentRate < p_inputRate || p_inputRate == -1)
00214         {
00215                 lastInputTime = currentTime;
00216 
00217                 // Convert pointcloud2 to DataPoint
00218                 DP cloud(PointMatcher_ros::rosMsgToPointMatcherCloud<float>(*cloudMsgIn));
00219                 
00220                 // Convert odometry msg to TransformationParameters
00221                 //TP TScannerToMap =    PointMatcher_ros::odomMsgToEigenMatrix<float>(*odom);
00222                 TP TScannerToMap;
00223 
00224                 try
00225                 {
00226                         tfListener.waitForTransform(p_mapFrame, cloudMsgIn->header.frame_id, cloudMsgIn->header.stamp, ros::Duration(0.5));
00227                         TScannerToMap = PointMatcher_ros::transformListenerToEigenMatrix<float>(
00228                                         tfListener,
00229                                         p_mapFrame,
00230                                         cloudMsgIn->header.frame_id,
00231                                         cloudMsgIn->header.stamp
00232                                 );
00233                         processCloud(cloud, TScannerToMap);
00234                 }
00235                 catch(tf::ExtrapolationException e)
00236                 {
00237                         ROS_ERROR_STREAM("Extrapolation Exception. stamp = "<< cloudMsgIn->header.stamp << " now = " << ros::Time::now() << " delta = " << ros::Time::now() - cloudMsgIn->header.stamp);
00238                         return;
00239                 }
00240         
00241         }
00242   else
00243   {
00244     ROS_WARN_STREAM("Skipping point cloud"); 
00245   }
00246 
00247 }
00248 
00249 // Point cloud processing
00250 void DynamicTrails::processCloud(DP inputPointCloud, const TP TScannerToMap)
00251 {
00252 
00253         ROS_INFO("Processing new point cloud");
00254         
00255         timer t; // Print how long take the algo
00256                 
00257 
00258                 
00259         ROS_INFO_STREAM("Input filters took " << t.elapsed() << " [s]");
00260         
00261         // Correct new points using ICP result and move them in their own frame
00262         inputPointCloud = transformation->compute(inputPointCloud, TScannerToMap); 
00263 
00264         cerr << "inputPointCloud.features.cols() " << inputPointCloud.features.cols() << endl;
00265         // filter to keep only dynamic points
00266         shared_ptr<DP> dynamicPointCloud( new DP(extractDynamicPoints(inputPointCloud, p_minDynamicRatio)));
00267 
00268         
00269         
00270         // Apply filters to incoming cloud, in global coordinates!
00271         inputFilters.apply(*dynamicPointCloud);
00272         
00273         const int dynamicPtsCount = dynamicPointCloud->features.cols();
00274 
00275         cerr << "dynamicPointCloud->features.cols() " << dynamicPtsCount << endl;
00276         
00277         // Error verification
00278         if(dynamicPtsCount == 0)
00279         {
00280                 ROS_WARN_STREAM("No dynamic points could be found");
00281                 return;
00282         }
00283                 
00284         //PM::Matrix unitVec(3,dynamicPtsCount);
00285         //unitVec.row(0) = PM::Matrix::Ones(1,dynamicPtsCount);
00286         //unitVec.bottomRows(2) = PM::Matrix::Zero(2,dynamicPtsCount);
00287 
00288 
00289         dynamicPointCloud->addDescriptor("velocity_dir", PM::Matrix::Zero(3,dynamicPtsCount));
00290         dynamicPointCloud->addDescriptor("velocity_mag", PM::Matrix::Zero(1,dynamicPtsCount));
00291         dynamicPointCloud->addDescriptor("velocity_dt", PM::Matrix::Zero(1,dynamicPtsCount));
00292 
00293 
00294         // fill the lastPointCloud for the firs time
00295         if(!lastPointCloud)
00296         {
00297                 lastPointCloud = dynamicPointCloud;
00298                 cerr << lastPointCloud->features.cols() << endl;
00299 
00300 
00301                 DP::View viewOn_normals_last = lastPointCloud->getDescriptorViewByName("normals");
00302 
00303                 // Build the kd-tree of the last points
00304                 PM::Matrix lastEuclNormal(6, dynamicPtsCount);
00305                 lastEuclNormal.topRows(3) = lastPointCloud->features.topRows(3);
00306                 lastEuclNormal.bottomRows(3) = viewOn_normals_last*p_normalSpaceFactor;
00307 
00308                 //lastNNS.reset( NNS::create(lastEuclNormal, 6, NNS::KDTREE_LINEAR_HEAP, NNS::TOUCH_STATISTICS));
00309                 lastNNS.reset( NNS::create(lastPointCloud->features, lastPointCloud->features.rows() - 1, NNS::KDTREE_LINEAR_HEAP, NNS::TOUCH_STATISTICS));
00310 
00311                 ROS_INFO_STREAM("Initializing last point cloud");
00312 
00313                 return;
00314         }
00315 
00316         const int lastPtsCount = lastPointCloud->features.cols();
00317         ROS_INFO_STREAM("lastPtsCount: " << lastPtsCount);
00318 
00319         // Error check on dimensions
00320         if (dynamicPointCloud->features.rows() != lastPointCloud->features.rows())
00321         {
00322                 ROS_ERROR_STREAM("Dimensionality missmatch: incoming cloud is " << dynamicPointCloud->features.rows()-1 << " while lastPointCloud is " << lastPointCloud->features.rows()-1);
00323                 return;
00324         }
00325 
00326         
00327 
00328         // Copy the last speed direction for temporal smoothing
00329         PM::Matrix priorOn_velocityDir = lastPointCloud->getDescriptorViewByName("velocity_dir");
00330         PM::Matrix priorOn_velocityDt = lastPointCloud->getDescriptorViewByName("velocity_dt");
00331         
00332         DP::View v_normals_input = dynamicPointCloud->getDescriptorViewByName("normals");
00333         PM::Matrix inputEuclNormal(6, dynamicPtsCount);
00334         inputEuclNormal.topRows(3) = dynamicPointCloud->features.topRows(3);
00335         inputEuclNormal.bottomRows(3) = v_normals_input*p_normalSpaceFactor;
00336         
00337 
00338         // Build kd-tree of the input points
00339         std::shared_ptr<NNS> inputNNS;
00340         //inputNNS.reset( NNS::create(inputEuclNormal, 6, NNS::KDTREE_LINEAR_HEAP, NNS::TOUCH_STATISTICS));
00341         inputNNS.reset( NNS::create(dynamicPointCloud->features, 3, NNS::KDTREE_LINEAR_HEAP, NNS::TOUCH_STATISTICS));
00342 
00343 
00344         // FIXME: those are parameters
00345         const int nbIter = 5;
00346         for(int i=0; i<nbIter; i++)
00347         {
00348                 computeVelocity(lastPointCloud, lastNNS, dynamicPointCloud, inputNNS, p_maxClusterDistance, nbIter-i, dynProjectedPub);
00349                 computeVelocity(dynamicPointCloud, inputNNS, lastPointCloud, lastNNS, p_maxClusterDistance, nbIter-i, lastProjectedPub);
00350 
00351                 averageWithReference(lastPointCloud, dynamicPointCloud, 1);
00352                 averageWithReference(dynamicPointCloud, lastPointCloud, 1);
00353         }
00354         
00355 
00356         DP::View v_matchId_dyn = dynamicPointCloud->getDescriptorViewByName("match_id");
00357         //DP::View v_velocityMag_dyn = dynamicPointCloud->getDescriptorViewByName("velocity_mag");
00358         DP::View v_velocityDir_dyn = dynamicPointCloud->getDescriptorViewByName("velocity_dir");
00359         DP::View v_velocityDt_dyn = dynamicPointCloud->getDescriptorViewByName("velocity_dt");
00360         DP::View v_normal_dyn = dynamicPointCloud->getDescriptorViewByName("normals");
00361 
00362         //DP::View v_velocityMag_last = lastPointCloud->getDescriptorViewByName("velocity_mag");
00363         DP::View v_velocityDir_last = lastPointCloud->getDescriptorViewByName("velocity_dir");
00364         DP::View v_velocityDt_last = lastPointCloud->getDescriptorViewByName("velocity_dt");
00365         
00366         // Project into the future
00367         v_velocityDir_dyn *= -1;
00368         
00369         // Markers
00370         visualization_msgs::Marker marker;
00371 
00372         marker.header.frame_id = p_mapFrame;
00373         marker.header.stamp = ros::Time::now();
00374         marker.ns = "basic_shapes";
00375         marker.type = visualization_msgs::Marker::LINE_LIST;
00376         
00377         marker.scale.x = 0.3;
00378         marker.scale.y = 0.3; //not use by line
00379         marker.scale.z = 0.3; //not use by line 
00380 
00381         marker.color.r = 1.0f;
00382         marker.color.g = 1.0f;
00383         marker.color.b = 0.0f;
00384         
00385   if(p_accumulateMarkers)
00386   {
00387     marker.color.a = 0.2;
00388     marker.id = trailCount; 
00389   }
00390   else
00391   {
00392     marker.color.a = 1.0;
00393     marker.id = 0;
00394         }
00395 
00396   trailCount++;
00397 
00398         marker.lifetime = ros::Duration(2);
00399 
00400         DP currenttTrails = dynamicPointCloud->createSimilarEmpty();
00401         int currentTrailPtCount = 0;
00402 
00403         // Filter outliers and build markers
00404         for(int i=0; i<dynamicPtsCount; i++)
00405         {
00406                 const int id = v_matchId_dyn(0,i);
00407 
00408                 const Eigen::Vector3f pt = dynamicPointCloud->features.col(i).head(3);
00409                 const Eigen::Vector3f pt_last = lastPointCloud->features.col(id).head(3);
00410                 
00411                 const Eigen::Vector3f normal = v_normal_dyn.col(i);
00412                 const float w_ang = angleWeight(normal, v_velocityDir_dyn.col(i));
00413                 
00414                 const Eigen::Vector3f lastVelDir = priorOn_velocityDir.col(id);
00415                 const Eigen::Vector3f currentVelDir = v_velocityDir_dyn.col(i);
00416                 const float w_diffAngle =  1 - acos(lastVelDir.normalized().dot(currentVelDir.normalized()))/M_PI;
00417                 
00418                 
00419                 int lastID = id;
00420 
00421     // TODO: evaluate multiple scans
00422                 // FIXME: finish here
00423                 //for(int i = 0; i < priors.size(); i++)
00424                 //{
00425                 //      const shared_ptr<DP> lastPrior = priors[i];
00426                 //      cerr << lastPrior << endl;
00427                 //      cerr << "lastID " << lastID << endl;
00428                 //      cerr << "last size " << lastPrior->features.cols() << endl;
00429                 //      DP::View match_id = priors[i]->getDescriptorViewByName("match_id");
00430 
00431                 //      lastID = match_id(0, lastID);
00432                 //      
00433                 //}
00434 
00435                 //cerr << "----------" << endl;
00436                 
00437                 const float lastDt = priorOn_velocityDt(0,id);
00438                 const float delta = (pt_last - pt).norm();
00439                 const float delta_projected = (pt_last + lastVelDir*lastDt - pt).norm();
00440                 const float w_proj = delta_projected/delta;
00441 
00442 
00443                 const float mag = currentVelDir.norm();
00444                 //if(w_ang > 0.75  && mag > eps && mag < p_maxVelocity)
00445                 if(mag > eps && mag < p_maxVelocity)
00446                 {
00447                         if(w_diffAngle > 0.25 && w_proj < 0.25)
00448                         {
00449                                 // Temporal smoothing
00450 
00451                                 v_velocityDir_dyn.col(i) = (lastVelDir + currentVelDir)/2;
00452 
00453                                 geometry_msgs::Point p;
00454                                 p.x = dynamicPointCloud->features(0,i);
00455                                 p.y = dynamicPointCloud->features(1,i);
00456                                 p.z = dynamicPointCloud->features(2,i);
00457                                 marker.points.push_back(p);
00458                                 
00459                                 p.x += v_velocityDir_dyn(0,i);
00460                                 p.y += v_velocityDir_dyn(1,i);
00461                                 p.z += v_velocityDir_dyn(2,i);
00462 
00463                                 marker.points.push_back(p);
00464 
00465                                 currenttTrails.setColFrom(currentTrailPtCount, *dynamicPointCloud, i);
00466                                 currentTrailPtCount++;
00467                         }
00468                 }
00469                 else
00470                 {
00471                         v_velocityDir_dyn.col(i) = Eigen::Vector3f::Zero();
00472                         v_velocityDt_dyn(0,i) = 0;
00473                 }
00474                 
00475         }
00476 
00477         currenttTrails.conservativeResize(currentTrailPtCount);
00478 
00479         if(currentTrailPtCount > 0)
00480         {
00481                 //if(trailPointCloud == false)
00482                 //{
00483                 //      trailPointCloud.reset(new DP(currenttTrails));
00484                 //}
00485                 //else
00486                 //{
00487                 //      trailPointCloud->concatenate(currenttTrails);
00488                 //}
00489         }
00490 
00491         markerPub.publish(marker);
00492 
00493         dynPub.publish(PointMatcher_ros::pointMatcherCloudToRosMsg<float>(*dynamicPointCloud.get(), p_mapFrame, ros::Time::now()));
00494         lastPub.publish(PointMatcher_ros::pointMatcherCloudToRosMsg<float>(*lastPointCloud.get(), p_mapFrame, ros::Time::now()));
00495 
00496 
00497         lastPointCloud = dynamicPointCloud;
00498         lastNNS = inputNNS;
00499 
00500 
00501         if(priors.size() >= p_windowSize)
00502         {
00503                 priors.pop_back();
00504         }
00505 
00506         priors.push_front(dynamicPointCloud);
00507 
00508 
00509         ROS_INFO_STREAM("Total trail computation: " << t.elapsed() << " [s]");
00510 
00511         //ros::Rate r(2);
00512         //r.sleep();
00513 }
00514 
00515 
00516 PM::DataPoints DynamicTrails::extractDynamicPoints (const PM::DataPoints input, const float minDynamicRatio)
00517 {
00518         const int inputPtsCount(input.features.cols());
00519 
00520         DP output(input.createSimilarEmpty());
00521 
00522         const int knn = 1;
00523         Matches::Dists dists_input(knn, inputPtsCount);
00524         Matches::Ids ids_input(knn, inputPtsCount);
00525         
00526         usingGlobalMap.lock();
00527         globalNNS->knn(input.features, ids_input, dists_input, knn, 0, 0, p_maxGlobalMapDist);
00528 
00529         if(globalMap.descriptorExists("probabilityStatic") == false ||
00530                         globalMap.descriptorExists("probabilityDynamic") == false ||
00531                         globalMap.descriptorExists("debug") == false
00532                 )
00533         {
00534                 ROS_WARN_STREAM("Map descriptors not found");
00535                 usingGlobalMap.unlock();
00536                 return output;
00537         }
00538 
00539         //DP::View viewOnDebug = globalMap.getDescriptorViewByName("debug");
00540         DP::View viewOnProbabilityStatic = globalMap.getDescriptorViewByName("probabilityStatic");
00541         DP::View viewOnProbabilityDynamic = globalMap.getDescriptorViewByName("probabilityDynamic");
00542 
00543         int dynamicPtsCount=0;
00544         for(int i=0; i<inputPtsCount; i++)
00545         {
00546                 float sumObs = 0;
00547                 float dist = numeric_limits<float>::infinity();
00548                 float dynRatio = 0;
00549 
00550                 for(int k=0; k<knn; k++)
00551                 {
00552                         const int mapId = ids_input(k,i);
00553                         sumObs = max(sumObs, viewOnProbabilityDynamic(0,mapId) + viewOnProbabilityStatic(0,mapId));
00554                         dist = min(dist, dists_input(k,i));
00555                         dynRatio = max(dynRatio, viewOnProbabilityDynamic(0, mapId));
00556                 }
00557 
00558                 {
00559                         //if(sumObs == 0 || dynRatio > minDynamicRatio || dist == numeric_limits<float>::infinity())
00560                         if(dynRatio > minDynamicRatio || dist == numeric_limits<float>::infinity())
00561                         {
00562                                 output.setColFrom(dynamicPtsCount, input, i);
00563                                 dynamicPtsCount++;
00564                         }
00565                 }
00566         }
00567 
00568         usingGlobalMap.unlock();
00569 
00570         output.conservativeResize(dynamicPtsCount);
00571         return output;
00572 
00573 }
00574 
00575 void DynamicTrails::computeVelocity(shared_ptr<DP> reference, shared_ptr<NNS> ref_tree, shared_ptr<DP> reading, shared_ptr<NNS> read_tree, const float maxRadius, const int knn, ros::Publisher debugPub)
00576 {
00577 
00578         const int readPtsCount = reading->features.cols();
00579         const int refPtsCount = reference->features.cols();
00580 
00581         // Prepare useful views on descriptors
00582         DP::View v_velocityDir_read = reading->getDescriptorViewByName("velocity_dir");
00583         DP::View v_velocityDt_read = reading->getDescriptorViewByName("velocity_dt");
00584         DP::View v_normal_read = reading->getDescriptorViewByName("normals");
00585 
00586         DP::View v_Msec_read = reading->getDescriptorViewByName("stamps_Msec");
00587         DP::View v_sec_read = reading->getDescriptorViewByName("stamps_sec");
00588         DP::View v_nsec_read = reading->getDescriptorViewByName("stamps_nsec");
00589         
00590         // Ensure that we don't modify the reference
00591         PM::Matrix velocityDir_ref = PM::Matrix::Zero(3,refPtsCount);
00592         PM::Matrix velocityDt_ref = PM::Matrix::Zero(1,refPtsCount);
00593 
00594         DP::View v_Msec_ref = reference->getDescriptorViewByName("stamps_Msec");
00595         DP::View v_sec_ref = reference->getDescriptorViewByName("stamps_sec");
00596         DP::View v_nsec_ref = reference->getDescriptorViewByName("stamps_nsec");
00597         
00598 
00599         // Move points based on velocity
00600         PM::Matrix moved_read(3, readPtsCount);
00601         //PM::Matrix moved_read(6, readPtsCount);
00602 
00603         const PM::Matrix static_read = reading->features.topRows(3);
00604         //PM::Matrix static_read(6, readPtsCount);
00605         //static_read.topRows(3) = reading->features.topRows(3);
00606         //static_read.bottomRows(3) = v_normal_read;
00607         
00608         //if (knn == 1)
00609         //      abort();
00610 
00611         for(int i=0; i<readPtsCount; i++)
00612         {
00613                 moved_read.col(i)= reading->features.col(i).head(3) + v_velocityDir_read.col(i)*v_velocityDt_read(0,i);
00614                 //moved_read.col(i)= reading->features.col(i).head(3) + v_velocityDir_read.col(i);
00615                 
00616                 //moved_read.topRows(3).col(i)= reading->features.col(i).head(3) + v_velocityDir_read.col(i)*v_velocityMag_read(0,i);
00617                 //moved_read.bottomRows(3).col(i) = v_normal_read.col(i);
00618                 
00619                 
00620                 assert(!isnan(moved_read(0,i)));
00621                 assert(!isnan(moved_read(1,i)));
00622                 assert(!isnan(moved_read(2,i)));
00623                 assert(!isinf(moved_read(0,i)));
00624                 assert(!isinf(moved_read(1,i)));
00625                 assert(!isinf(moved_read(2,i)));
00626         }
00627 
00628         //------------------
00629         // Search for nearest points
00630         Matches::Dists dists(knn, readPtsCount);
00631         Matches::Ids ids(knn, readPtsCount);
00632 
00633         ref_tree->knn(moved_read, ids, dists, knn, 0, 2.0);
00634 
00635         
00636         PM::Matrix sumVec_ref = PM::Matrix::Zero(3,refPtsCount);
00637         //PM::Matrix sumVec_ref(3,refPtsCount);
00638         //sumVec_ref.row(0) = PM::Matrix::Ones(1,refPtsCount);
00639         //sumVec_ref.bottomRows(2) = PM::Matrix::Zero(2,refPtsCount);
00640 
00641         PM::Matrix closeId_read = PM::Matrix::Constant(1,readPtsCount, -1);
00642         PM::Matrix weight_ref = PM::Matrix::Zero(1,refPtsCount);
00643         PM::Matrix sumDt_ref = PM::Matrix::Zero(1,refPtsCount);
00644 
00645         for(int i=0; i<readPtsCount; i++)
00646         {
00647                 const Eigen::Vector3f pt = reading->features.col(i).head(3);
00648                 const double timeRead = v_Msec_read(0,i)*1e6 + v_sec_read(0,i) + v_nsec_read(0,i)*1e-9;
00649 
00650                 // Counters for reading
00651                 float sumWeight = 0;
00652                 float sumDt = 0;
00653                 Eigen::Vector3f sumVec = Eigen::Vector3f::Zero(3,1);
00654 
00655     int nbMatch = 0;
00656                 for(int k=0; k<knn; k++)
00657                 {
00658                         if(dists(k,i) != numeric_limits<float>::infinity())
00659                         {
00660                                 const int id = ids(k,i);
00661                                 const Eigen::Vector3f pt_nn = reference->features.col(id).head(3);
00662                                 const double timeRef = v_Msec_ref(0,id)*1e6 + v_sec_ref(0,id) + v_nsec_ref(0,id)*1e-9;
00663                                 
00664                                 const Eigen::Vector3f delta = pt_nn - pt;
00665                                 const Eigen::Vector3f normal_read = v_normal_read.col(i);
00666                                 const double dt = abs(timeRead - timeRef);
00667 
00668                                 const float distRatio = sqrt(dists(k,i))/delta.norm();
00669                                 const float w_dist = 1 + eps - std::min(1.0f, distRatio);
00670                                 const float w_ang = angleWeight(normal_read, delta);
00671                                 //const float w = w_ang*w_dist;
00672                                 const float w = w_dist;
00673                                 //const float w = 1;
00674 
00675                                 assert(!isnan(w_dist));
00676                                 assert(!isnan(w_ang));
00677                                 assert(dt != 0);
00678 
00679                         
00680                                 weight_ref(id)     += w;
00681                                 sumDt_ref(id)      += w*dt;
00682                                 sumVec_ref.col(id) += w*delta/dt;
00683                                 //sumVec_ref.col(id) += w*delta;
00684 
00685                                 sumWeight += w;
00686                                 sumDt     += w*dt;
00687                                 sumVec    += w*delta/dt;
00688                                 //sumVec    += w*delta;
00689                                 
00690                                 closeId_read(i) = id;
00691         nbMatch++;
00692                         }
00693                 }
00694 
00695                 // Weighted mean
00696     //FIXME: this is a parameter
00697                 if(sumWeight > eps && nbMatch > 4)
00698                 {
00699                         sumDt /= sumWeight;
00700                         sumVec /= sumWeight;
00701 
00702                         const float mag = sumVec.norm();
00703                         if( mag < p_maxVelocity)
00704                         {
00705                                 // Store in the descriptors
00706                                 v_velocityDir_read.col(i) = sumVec;
00707                                 v_velocityDt_read(0,i) = sumDt;
00708                         }
00709                 }
00710 
00711 
00712 
00713         }
00714 
00715         //------------------
00716         // Average points that received multiple matches on the reference
00717         for(int i=0; i<refPtsCount; i++)
00718         {
00719                 // Avoid division per zero
00720                 const float mag = sumVec_ref.col(i).norm();
00721                 if(mag > eps)
00722                 {
00723                         // Weighted mean
00724                         sumDt_ref(i) /= weight_ref(i);
00725                         sumVec_ref.col(i) /= weight_ref(i);
00726                         
00727                         if(mag < p_maxVelocity)
00728                         {
00729                                 // Store in the descriptors
00730                                 velocityDir_ref.col(i) = sumVec_ref.col(i);
00731                                 velocityDt_ref(0,i) = sumDt_ref(i);
00732                         }       
00733                 }
00734         }
00735 
00736 
00737         //------------------
00738         // Average all points with dual match
00739         for(int i=0; i<readPtsCount; i++)
00740         {
00741                 assert(!isnan(v_velocityDir_read(0,i)));
00742                 const int id = closeId_read(i);
00743 
00744                 if(id != -1)
00745                 {
00746                         const float mag = velocityDir_ref.col(id).norm();
00747                         if(mag > eps)
00748                         {
00749                                 // We only keep the reference velocity, if only one match it will be the same
00750                                 v_velocityDir_read.col(i) = velocityDir_ref.col(id);
00751                                 v_velocityDt_read(0,i) = velocityDt_ref(0,id);
00752                         }
00753                 }
00754                 
00755         }
00756 
00757         //------------------
00758         // Apply local constrains on velocity
00759         const int maxNN = 100;
00760         Matches::Dists dists_local(maxNN, readPtsCount);
00761         Matches::Ids ids_local(maxNN, readPtsCount);
00762 
00763         // Search
00764         read_tree->knn(static_read, ids_local, dists_local, maxNN, 0, 0, maxRadius);
00765         //PM::Matrix dists_nosqrt = dists_local.cwiseSqrt();
00766         //dists_local = dists_local.cwiseSqrt();
00767         
00768         // Initialize counters
00769         
00770         PM::Matrix sumVec_read = PM::Matrix::Zero(3,readPtsCount);
00771 
00772         PM::Matrix weight_read = PM::Matrix::Zero(1,readPtsCount);
00773         PM::Matrix sumMag_read = PM::Matrix::Zero(1,readPtsCount);
00774         PM::Matrix sumDt_read = PM::Matrix::Zero(1,readPtsCount);
00775         
00776         for(int i=0; i<readPtsCount; i++)
00777         {
00778                 const Eigen::Vector3f normal_read = v_normal_read.col(i);
00779                 
00780                 for(int k=0; k<maxNN; k++)
00781                 {
00782                         if(dists_local(k,i) != numeric_limits<float>::infinity())
00783                         {
00784                                 const int id = ids_local(k,i);
00785                                 const Eigen::Vector3f velocityDir = v_velocityDir_read.col(id);
00786 
00787                                 const float w_dist = eps + (1 - eps)*(1 - sqrt(dists_local(k,i))/maxRadius);
00788                                 assert(!isnan(w_dist));
00789 
00790                                 //const float w_ang = angleWeight(normal_read, velocityDir);
00791                                 //assert(!isnan(w_ang));
00792 
00793                                 const float w = w_dist;
00794                                 //const float w = 1;
00795 
00796                                 weight_read(i)     += w;
00797                                 sumVec_read.col(i) += w*velocityDir;
00798                                 sumDt_read(i)      += w*v_velocityDt_read(0,id);
00799                         }
00800                 }
00801 
00802         }
00803         
00804         //------------------
00805         // Average points given their neighborgs
00806         for(int i=0; i<readPtsCount; i++)
00807         {
00808                 assert(!isnan(v_velocityDir_read(0,i)));
00809                 // Avoid division per zero
00810                 if(weight_read(i) > eps)
00811                 {
00812                         // Weighted mean
00813                         sumDt_read(i) /= weight_read(i);
00814                         sumVec_read.col(i) /= weight_read(i);
00815 
00816                         const float mag = sumVec_read.col(i).norm();
00817                         if(mag > eps && mag < p_maxVelocity)
00818                         {
00819                                 // Store in the descriptors
00820                                 v_velocityDir_read.col(i) = sumVec_read.col(i);
00821                                 v_velocityDt_read(0,i) = sumDt_read(i);
00822                         }
00823                 }
00824                 
00825                 assert(isnan(v_velocityDir_read(0,i)) == false);
00826 
00827         }
00828         reading->addDescriptor("match_id", closeId_read);
00829 
00830 
00831         // Extra for debug
00832         DP projectedPointCloud = *reading;
00833         projectedPointCloud.features.topRows(3) = moved_read.topRows(3);
00834         debugPub.publish(PointMatcher_ros::pointMatcherCloudToRosMsg<float>(projectedPointCloud, p_mapFrame, ros::Time::now()));
00835 
00836         //usleep(100000);
00837 }
00838 
00839 float DynamicTrails::angleWeight(const Eigen::Vector3f &normal, const Eigen::Vector3f &velocity)
00840 {
00841         const float projDist = min(1.0f, fabs(normal.dot(velocity.normalized())));
00842         assert(projDist <= 1);
00843 
00844         return (eps + (1 - eps)*(1 - 2.0*acos(projDist)/M_PI));
00845 
00846         //if(projDist > 0)
00847         //{
00848         //      return (1 + eps - 2.0*fabs(acos(min(1.0f, projDist)))/M_PI);
00849         //}
00850         //else
00851         //{
00852         //      const float projDistFlip = normal.dot(-velocity.normalized());
00853         //      return (1 + eps - 2.0*fabs(acos(min(1.0f, projDistFlip)))/M_PI);
00854         //}
00855 }
00856 
00857 void DynamicTrails::averageWithReference(shared_ptr<DP> reference, shared_ptr<DP> reading, const float dir)
00858 {
00859         //const int readPtsCount = reading->features.cols();
00860         const int refPtsCount = reference->features.cols();
00861         
00862         //DP::View v_matchId_read = reading->getDescriptorViewByName("match_id");
00863         DP::View v_velocityDir_read = reading->getDescriptorViewByName("velocity_dir");
00864         DP::View v_velocityDt_read = reading->getDescriptorViewByName("velocity_dt");
00865         DP::View v_normal_read = reading->getDescriptorViewByName("normals");
00866         
00867         DP::View v_matchId_ref = reference->getDescriptorViewByName("match_id");
00868         DP::View v_velocityDir_ref = reference->getDescriptorViewByName("velocity_dir");
00869         DP::View v_velocityDt_ref = reference->getDescriptorViewByName("velocity_dt");
00870         
00871         for(int i=0; i<refPtsCount; i++)
00872         {
00873                 const int id = v_matchId_ref(0,i);
00874                 const float w_read = angleWeight(v_normal_read.col(id), v_velocityDir_read.col(id));
00875                 const float w_ref = angleWeight(v_normal_read.col(id), v_velocityDir_ref.col(i));
00876                 const float w_sum = w_read + w_ref;
00877                 
00878                 const float mag_ref = v_velocityDir_ref.col(i).norm();
00879                 if(w_sum > eps && mag_ref > eps)
00880                 {
00881                         v_velocityDir_read.col(id) = (w_read*dir*v_velocityDir_read.col(id) - w_ref*dir*v_velocityDir_ref.col(i))/(w_sum);
00882                         
00883                         v_velocityDt_read(0,id) = (w_read*v_velocityDt_read(0,id) + w_ref*v_velocityDt_ref(0,i))/(w_sum);
00884                 }
00885         }
00886 
00887         //for(int i=0; i<readPtsCount; i++)
00888         //{
00889         //      assert(!isnan(v_velocityDir_read(0,i)));
00890         //      const int id = v_matchId_read(0,i);
00891         //      const float w_read = angleWeight(v_normal_read.col(i), v_velocityDir_read.col(i));
00892         //      const float w_ref = angleWeight(v_normal_read.col(i), v_velocityDir_ref.col(id));
00893         //      const float w_sum = w_read + w_ref;
00894         //      
00895         //      const float mag_ref = v_velocityDir_ref.col(id).norm();
00896         //      if(w_sum > eps && mag_ref > eps)
00897         //      {
00898         //              assert((dir*v_velocityDir_read.col(i) - dir*v_velocityDir_ref.col(id)).norm() != 0);
00899 
00900         //              v_velocityDir_read.col(i) = (w_read*dir*v_velocityDir_read.col(i) - w_ref*dir*v_velocityDir_ref.col(id))/(w_sum);
00901         //              
00902         //              v_velocityDt_read(0,i) = (w_read*v_velocityDt_read(0,i) + w_ref*v_velocityDt_ref(0,id))/(w_sum);
00903         //      }
00904         //      assert(isnan(v_velocityDir_read(0,i)) == false);
00905         //}
00906 }
00907 
00908 
00909 // Main function supporting the DynamicTrails class
00910 int main(int argc, char **argv)
00911 {
00912         ros::init(argc, argv, "map_maintainer");
00913         ros::NodeHandle n;
00914         ros::NodeHandle pn("~");
00915         DynamicTrails trails(n, pn);
00916 
00917         ros::Rate r(50);
00918         while(ros::ok())
00919         {
00920                 ros::spinOnce();
00921                 r.sleep();
00922         }
00923         
00924         return 0;
00925 }


ethzasl_icp_mapper
Author(s): François Pomerleau and Stéphane Magnenat
autogenerated on Mon Oct 6 2014 10:28:23