leg_detector.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 * Software License Agreement (BSD License)
00003 * 
00004 *  Copyright (c) 2008, Willow Garage, Inc.
00005 *  All rights reserved.
00006 * 
00007 *  Redistribution and use in source and binary forms, with or without
00008 *  modification, are permitted provided that the following conditions
00009 *  are met:
00010 * 
00011 *   * Redistributions of source code must retain the above copyright
00012 *     notice, this list of conditions and the following disclaimer.
00013 *   * Redistributions in binary form must reproduce the above
00014 *     copyright notice, this list of conditions and the following
00015 *     disclaimer in the documentation and/or other materials provided
00016 *     with the distribution.
00017 *   * Neither the name of the Willow Garage nor the names of its
00018 *     contributors may be used to endorse or promote products derived
00019 *     from this software without specific prior written permission.
00020 * 
00021 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 *  POSSIBILITY OF SUCH DAMAGE.
00033 *********************************************************************/
00034 #include <ros/ros.h>
00035 
00036 #include <leg_detector/LegDetectorConfig.h>
00037 #include <leg_detector/laser_processor.h>
00038 #include <leg_detector/calc_leg_features.h>
00039 
00040 #include <opencv/cxcore.h>
00041 #include <opencv/cv.h>
00042 #include <opencv/ml.h>
00043 
00044 #include <people_msgs/PositionMeasurement.h>
00045 #include <people_msgs/PositionMeasurementArray.h>
00046 #include <sensor_msgs/LaserScan.h>
00047 
00048 #include <tf/transform_listener.h>
00049 #include <tf/message_filter.h>
00050 #include <message_filters/subscriber.h>
00051 
00052 #include <people_tracking_filter/tracker_kalman.h>
00053 #include <people_tracking_filter/state_pos_vel.h>
00054 #include <people_tracking_filter/rgb.h>
00055 #include <visualization_msgs/Marker.h>
00056 #include <dynamic_reconfigure/server.h>
00057 
00058 #include <algorithm>
00059 
00060 using namespace std;
00061 using namespace laser_processor;
00062 using namespace ros;
00063 using namespace tf;
00064 using namespace estimation;
00065 using namespace BFL;
00066 using namespace MatrixWrapper;
00067 
00068 
00069 static double no_observation_timeout_s = 0.5;
00070 static double max_second_leg_age_s     = 2.0;
00071 static double max_track_jump_m         = 1.0; 
00072 static double max_meas_jump_m          = 0.75; // 1.0
00073 static double leg_pair_separation_m    = 1.0;
00074 static string fixed_frame              = "odom_combined";
00075 
00076 static double kal_p = 4, kal_q = .002, kal_r = 10;
00077 static bool use_filter = true;
00078 
00079 
00080 class SavedFeature
00081 {
00082 public:
00083   static int nextid;
00084   TransformListener& tfl_;
00085 
00086   BFL::StatePosVel sys_sigma_;
00087   TrackerKalman filter_;
00088 
00089   string id_;
00090   string object_id;
00091   ros::Time time_;
00092   ros::Time meas_time_;
00093 
00094   double reliability, p;
00095 
00096   Stamped<Point> position_;
00097   SavedFeature* other;
00098   float dist_to_person_;
00099 
00100   // one leg tracker
00101   SavedFeature(Stamped<Point> loc, TransformListener& tfl)
00102     : tfl_(tfl),
00103       sys_sigma_(Vector3(0.05, 0.05, 0.05), Vector3(1.0, 1.0, 1.0)),
00104       filter_("tracker_name",sys_sigma_),
00105       reliability(-1.), p(4)
00106   {
00107     char id[100];
00108     snprintf(id,100,"legtrack%d", nextid++);
00109     id_ = std::string(id);
00110 
00111     object_id = "";
00112     time_ = loc.stamp_;
00113     meas_time_ = loc.stamp_;
00114     other = NULL;
00115 
00116     try {
00117     tfl_.transformPoint(fixed_frame, loc, loc);
00118     } catch(...) {
00119       ROS_WARN("TF exception spot 6.");
00120     }
00121     StampedTransform pose( Pose(Quaternion(0.0, 0.0, 0.0, 1.0), loc), loc.stamp_, id_, loc.frame_id_);
00122     tfl_.setTransform(pose);
00123 
00124     StatePosVel prior_sigma(Vector3(0.1,0.1,0.1), Vector3(0.0000001, 0.0000001, 0.0000001));
00125     filter_.initialize(loc, prior_sigma, time_.toSec());    
00126 
00127     StatePosVel est;
00128     filter_.getEstimate(est);
00129 
00130     updatePosition();
00131   }
00132 
00133   void propagate(ros::Time time)
00134   {
00135     time_ = time;
00136 
00137     filter_.updatePrediction(time.toSec());
00138 
00139     updatePosition();
00140   }
00141 
00142   void update(Stamped<Point> loc, double probability)
00143   {
00144     StampedTransform pose( Pose(Quaternion(0.0, 0.0, 0.0, 1.0), loc), loc.stamp_, id_, loc.frame_id_);
00145     tfl_.setTransform(pose);
00146 
00147     meas_time_ = loc.stamp_;
00148     time_ = meas_time_;
00149 
00150     SymmetricMatrix cov(3);
00151     cov = 0.0;
00152     cov(1,1) = 0.0025;
00153     cov(2,2) = 0.0025;
00154     cov(3,3) = 0.0025;
00155 
00156     filter_.updateCorrection(loc, cov);
00157 
00158     updatePosition();
00159 
00160     if(reliability<0 || !use_filter){
00161         reliability = probability;
00162         p = kal_p;
00163     }
00164     else{
00165         p += kal_q;
00166         double k = p / (p+kal_r);
00167         reliability += k * (probability - reliability);
00168         p *= (1 - k);
00169     }
00170   }
00171 
00172   double getLifetime()
00173   {
00174     return filter_.getLifetime();
00175   }
00176 
00177   double getReliability()
00178   {
00179     return reliability;
00180   }
00181 
00182 private:
00183   void updatePosition()
00184   {
00185     StatePosVel est;
00186     filter_.getEstimate(est);
00187 
00188     position_[0] = est.pos_[0];
00189     position_[1] = est.pos_[1];
00190     position_[2] = est.pos_[2];
00191     position_.stamp_ = time_;
00192     position_.frame_id_ = fixed_frame;
00193     double nreliability = fmin(1.0, fmax(0.1, est.vel_.length() / 0.5));
00194     //reliability = fmax(reliability, nreliability);
00195   }
00196 };
00197 
00198 int SavedFeature::nextid = 0;
00199 
00200 
00201 
00202 
00203 class MatchedFeature
00204 {
00205 public:
00206   SampleSet* candidate_;
00207   SavedFeature* closest_;
00208   float distance_;
00209   double probability_;
00210 
00211   MatchedFeature(SampleSet* candidate, SavedFeature* closest, float distance, double probability)
00212   : candidate_(candidate)
00213   , closest_(closest)
00214   , distance_(distance)
00215   , probability_(probability)
00216   {}
00217 
00218   inline bool operator< (const MatchedFeature& b) const
00219   {
00220     return (distance_ <  b.distance_);
00221   }
00222 };
00223 
00224 int g_argc;
00225 char** g_argv;
00226 
00227 
00228 
00229 
00230 // actual legdetector node
00231 class LegDetector
00232 {
00233 public:
00234   NodeHandle nh_;
00235 
00236   TransformListener tfl_;
00237 
00238   ScanMask mask_;
00239 
00240   int mask_count_;
00241 
00242   CvRTrees forest;
00243 
00244   float connected_thresh_;
00245 
00246   int feat_count_;
00247 
00248   char save_[100];
00249 
00250   list<SavedFeature*> saved_features_;
00251   boost::mutex saved_mutex_;
00252 
00253   int feature_id_;
00254 
00255   bool use_seeds_;
00256   bool publish_legs_, publish_people_, publish_leg_markers_, publish_people_markers_;
00257   int next_p_id_;
00258   double leg_reliability_limit_;
00259   int min_points_per_group;
00260 
00261   ros::Publisher people_measurements_pub_;
00262   ros::Publisher leg_measurements_pub_;
00263   ros::Publisher markers_pub_;
00264 
00265   dynamic_reconfigure::Server<leg_detector::LegDetectorConfig> server_;
00266 
00267   message_filters::Subscriber<people_msgs::PositionMeasurement> people_sub_;
00268   message_filters::Subscriber<sensor_msgs::LaserScan> laser_sub_;
00269   tf::MessageFilter<people_msgs::PositionMeasurement> people_notifier_;
00270   tf::MessageFilter<sensor_msgs::LaserScan> laser_notifier_;
00271 
00272   LegDetector(ros::NodeHandle nh) :
00273     nh_(nh), 
00274     mask_count_(0), 
00275     feat_count_(0),
00276     next_p_id_(0),
00277     people_sub_(nh_,"people_tracker_filter",10),
00278     laser_sub_(nh_,"scan",10),
00279     people_notifier_(people_sub_,tfl_,fixed_frame,10),
00280     laser_notifier_(laser_sub_,tfl_,fixed_frame,10)
00281   {
00282     if (g_argc > 1) {
00283       forest.load(g_argv[1]);
00284       feat_count_ = forest.get_active_var_mask()->cols;
00285       printf("Loaded forest with %d features: %s\n", feat_count_, g_argv[1]);
00286     } else {
00287       printf("Please provide a trained random forests classifier as an input.\n");
00288       shutdown();
00289     }
00290 
00291     nh_.param<bool>("use_seeds", use_seeds_, !true);
00292 
00293     // advertise topics
00294     leg_measurements_pub_ = nh_.advertise<people_msgs::PositionMeasurementArray>("leg_tracker_measurements",0);
00295     people_measurements_pub_ = nh_.advertise<people_msgs::PositionMeasurementArray>("people_tracker_measurements", 0);
00296     markers_pub_ = nh_.advertise<visualization_msgs::Marker>("visualization_marker", 20);
00297 
00298     if(use_seeds_){
00299       people_notifier_.registerCallback(boost::bind(&LegDetector::peopleCallback, this, _1));
00300       people_notifier_.setTolerance(ros::Duration(0.01));
00301     }
00302     laser_notifier_.registerCallback(boost::bind(&LegDetector::laserCallback, this, _1));
00303     laser_notifier_.setTolerance(ros::Duration(0.01));
00304 
00305     dynamic_reconfigure::Server<leg_detector::LegDetectorConfig>::CallbackType f;
00306     f = boost::bind(&LegDetector::configure, this, _1, _2);
00307     server_.setCallback(f);
00308 
00309     feature_id_ = 0;
00310   }
00311 
00312 
00313   ~LegDetector()
00314   {
00315   }
00316 
00317   void configure(leg_detector::LegDetectorConfig &config, uint32_t level) {
00318     connected_thresh_       = config.connection_threshold;
00319     min_points_per_group    = config.min_points_per_group;
00320     leg_reliability_limit_  = config.leg_reliability_limit;
00321     publish_legs_           = config.publish_legs;
00322     publish_people_         = config.publish_people;
00323     publish_leg_markers_    = config.publish_leg_markers;
00324     publish_people_markers_ = config.publish_people_markers;
00325 
00326     no_observation_timeout_s = config.no_observation_timeout;
00327     max_second_leg_age_s     = config.max_second_leg_age;
00328     max_track_jump_m         = config.max_track_jump;
00329     max_meas_jump_m          = config.max_meas_jump;
00330     leg_pair_separation_m    = config.leg_pair_separation;
00331     if(fixed_frame.compare(config.fixed_frame) != 0)
00332     {
00333       fixed_frame              = config.fixed_frame;
00334       laser_notifier_.setTargetFrame(fixed_frame);
00335       people_notifier_.setTargetFrame(fixed_frame);
00336     }
00337 
00338     kal_p                    = config.kalman_p;
00339     kal_q                    = config.kalman_q;
00340     kal_r                    = config.kalman_r;
00341     use_filter               = config.kalman_on == 1;
00342   }
00343 
00344   double distance( list<SavedFeature*>::iterator it1,  list<SavedFeature*>::iterator it2){
00345     Stamped<Point> one = (*it1)->position_, two = (*it2)->position_;
00346     double dx = one[0]-two[0], dy = one[1]-two[1], dz = one[2]-two[2];
00347     return sqrt(dx*dx+dy*dy+dz*dz);
00348   }
00349 
00350   // Find the tracker that is closest to this person message
00351   // If a tracker was already assigned to a person, keep this assignment when the distance between them is not too large.
00352   void peopleCallback(const people_msgs::PositionMeasurement::ConstPtr& people_meas)
00353   {
00354     // If there are no legs, return.
00355     if (saved_features_.empty()) 
00356       return;
00357 
00358     Point pt;
00359     pointMsgToTF(people_meas->pos, pt);
00360     Stamped<Point> person_loc(pt, people_meas->header.stamp, people_meas->header.frame_id);
00361     person_loc[2] = 0.0; // Ignore the height of the person measurement.
00362     Stamped<Point> dest_loc(pt, people_meas->header.stamp, people_meas->header.frame_id); // Holder for all transformed pts.
00363 
00364     boost::mutex::scoped_lock lock(saved_mutex_);
00365 
00366     list<SavedFeature*>::iterator closest = saved_features_.end();
00367     list<SavedFeature*>::iterator closest1 = saved_features_.end();
00368     list<SavedFeature*>::iterator closest2 = saved_features_.end();
00369     float closest_dist = max_meas_jump_m;
00370     float closest_pair_dist = 2*max_meas_jump_m;
00371 
00372     list<SavedFeature*>::iterator begin = saved_features_.begin();
00373     list<SavedFeature*>::iterator end = saved_features_.end();
00374     list<SavedFeature*>::iterator it1, it2;
00375 
00376     // If there's a pair of legs with the right label and within the max dist, return
00377     // If there's one leg with the right label and within the max dist, 
00378     //   find a partner for it from the unlabeled legs whose tracks are reasonably new.
00379     //   If no partners exist, label just the one leg.
00380     // If there are no legs with the right label and within the max dist,
00381     //   find a pair of unlabeled legs and assign them the label.
00382     // If all of the above cases fail, 
00383     //   find a new unlabeled leg and assign the label.
00384     
00385     // For each tracker, get the distance to this person.
00386     for (it1 = begin; it1 != end; ++it1) 
00387     {
00388       try {
00389       tfl_.transformPoint((*it1)->id_, people_meas->header.stamp,
00390         person_loc, fixed_frame, dest_loc);
00391       //ROS_INFO("Succesful leg transformation at spot 7"); 
00392       } catch(...) {
00393         ROS_WARN("TF exception spot 7.");
00394       }
00395       (*it1)->dist_to_person_ = dest_loc.length();
00396     }
00397 
00398     // Try to find one or two trackers with the same label and within the max distance of the person.
00399     cout << "Looking for two legs" << endl;
00400     it2 = end;
00401     for (it1 = begin; it1 != end; ++it1)
00402     {
00403       // If this leg belongs to the person...
00404       if ((*it1)->object_id == people_meas->object_id) 
00405       {
00406         // and their distance is close enough... 
00407         if ((*it1)->dist_to_person_ < max_meas_jump_m)
00408         {
00409           // if this is the first leg we've found, assign it to it2. Otherwise, leave it assigned to it1 and break.
00410           if (it2 == end) 
00411             it2 = it1;
00412           else
00413             break;
00414         }
00415         // Otherwise, remove the tracker's label, it doesn't belong to this person.
00416         else{
00417           // the two trackers moved apart. This should not happen.
00418           (*it1)->object_id = "";
00419         }
00420       }
00421     }
00422     // If we found two legs with the right label and within the max distance, all is good, return.
00423     if (it1 != end && it2 != end) 
00424     {
00425       cout << "Found matching pair. The second distance was " << (*it1)->dist_to_person_ << endl;
00426       return;
00427     }
00428 
00429 
00430 
00431     // If we only found one close leg with the right label, let's try to find a second leg that 
00432     //   * doesn't yet have a label  (=valid precondition),
00433     //   * is within the max distance,
00434     //   * is less than max_second_leg_age_s old.
00435     cout << "Looking for one leg plus one new leg" << endl;
00436     float dist_between_legs, closest_dist_between_legs;
00437     if (it2 != end) 
00438     {
00439       closest_dist = max_meas_jump_m;
00440       closest = saved_features_.end();
00441 
00442       for (it1 = begin; it1 != end; ++it1) 
00443       {
00444         // Skip this leg track if:
00445         // - you're already using it.
00446         // - it already has an id.
00447         // - it's too old. Old unassigned trackers are unlikely to be the second leg in a pair.
00448         // - it's too far away from the person.
00449         if ((it1 == it2) || ((*it1)->object_id != "") ||  ((*it1)->getLifetime() > max_second_leg_age_s) || ((*it1)->dist_to_person_ >= closest_dist) )
00450           continue;
00451 
00452         // Get the distance between the two legs
00453         try {
00454           tfl_.transformPoint((*it1)->id_, (*it2)->position_.stamp_, (*it2)->position_, fixed_frame, dest_loc);
00455         } catch(...) {
00456           ROS_WARN("TF exception getting distance between legs.");
00457         }
00458         dist_between_legs = dest_loc.length();
00459 
00460         // If this is the closest dist (and within range), and the legs are close together and unlabeled, mark it.
00461         if ( dist_between_legs < leg_pair_separation_m )
00462         {
00463           closest = it1;
00464           closest_dist = (*it1)->dist_to_person_;
00465           closest_dist_between_legs = dist_between_legs;
00466         }
00467       }
00468       // If we found a close, unlabeled leg, set it's label.
00469       if (closest != end) 
00470       {
00471         cout << "Replaced one leg with a distance of " << closest_dist << " and a distance between the legs of " << closest_dist_between_legs << endl;
00472         (*closest)->object_id = people_meas->object_id;
00473       }
00474       else 
00475       {
00476         cout << "Returned one matched leg only" << endl;
00477       }
00478       
00479       // Regardless of whether we found a second leg, return.
00480       return;
00481     }
00482 
00483     cout << "Looking for a pair of new legs" << endl;
00484     // If we didn't find any legs with this person's label, try to find two unlabeled legs that are close together and close to the tracker.
00485     it1 = saved_features_.begin();
00486     it2 = saved_features_.begin();
00487     closest = saved_features_.end();
00488     closest1 = saved_features_.end();
00489     closest2 = saved_features_.end();
00490     closest_dist = max_meas_jump_m;
00491     closest_pair_dist = 2*max_meas_jump_m;
00492     for (; it1 != end; ++it1) 
00493     {
00494       // Only look at trackers without ids and that are not too far away.
00495       if ((*it1)->object_id != "" || (*it1)->dist_to_person_ >= max_meas_jump_m )
00496         continue;
00497 
00498       // Keep the single closest leg around in case none of the pairs work out.
00499       if ( (*it1)->dist_to_person_ < closest_dist ) 
00500       {
00501         closest_dist = (*it1)->dist_to_person_;
00502         closest = it1;
00503       }
00504 
00505       // Find a second leg.
00506       it2 = it1;
00507       it2++;
00508       for (; it2 != end; ++it2) 
00509       {
00510         // Only look at trackers without ids and that are not too far away.
00511         if ((*it2)->object_id != "" || (*it2)->dist_to_person_ >= max_meas_jump_m ) 
00512           continue;
00513    
00514         // Get the distance between the two legs
00515         try {
00516           tfl_.transformPoint((*it1)->id_, (*it2)->position_.stamp_, (*it2)->position_, fixed_frame, dest_loc);
00517         } catch(...) {
00518           ROS_WARN("TF exception getting distance between legs in spot 2.");
00519         }
00520         dist_between_legs = dest_loc.length();
00521 
00522         // Ensure that this pair of legs is the closest pair to the tracker, and that the distance between the legs isn't too large.
00523         if ( (*it1)->dist_to_person_+(*it2)->dist_to_person_ < closest_pair_dist && dist_between_legs < leg_pair_separation_m ) 
00524         {
00525           closest_pair_dist = (*it1)->dist_to_person_+(*it2)->dist_to_person_;
00526           closest1 = it1;
00527           closest2 = it2;
00528           closest_dist_between_legs = dist_between_legs;
00529         }
00530       }
00531     }
00532     // Found a pair of legs.
00533     if (closest1 != end && closest2 != end) 
00534     {
00535       (*closest1)->object_id = people_meas->object_id;
00536       (*closest2)->object_id = people_meas->object_id;
00537       cout << "Found a completely new pair with total distance " << closest_pair_dist << " and a distance between the legs of " << closest_dist_between_legs << endl;
00538       return;
00539     }
00540 
00541     cout << "Looking for just one leg" << endl;
00542     // No pair worked, try for just one leg.
00543     if (closest != end)
00544     {
00545       (*closest)->object_id = people_meas->object_id;
00546       cout << "Returned one new leg only" << endl;
00547       return;
00548     }
00549 
00550     cout << "Nothing matched" << endl;
00551   }
00552 
00553   void pairLegs()
00554   {
00555     // Deal With legs that already have ids
00556     list<SavedFeature*>::iterator begin = saved_features_.begin();
00557     list<SavedFeature*>::iterator end = saved_features_.end();
00558     list<SavedFeature*>::iterator leg1, leg2, best, it;
00559 
00560     for (leg1 = begin; leg1 != end; ++leg1)
00561     {
00562       // If this leg has no id, skip
00563       if ((*leg1)->object_id == "") 
00564         continue;
00565 
00566       leg2 = end;
00567       best = end;
00568       double closest_dist = leg_pair_separation_m;
00569       for ( it = begin; it != end; ++it)
00570       {
00571         if(it==leg1) continue;
00572 
00573         if ( (*it)->object_id == (*leg1)->object_id ) {
00574           leg2 = it;
00575           break;
00576         }
00577         
00578         if ((*it)->object_id != "")
00579           continue;
00580 
00581         double d = distance(it, leg1);
00582         if (((*it)->getLifetime() <= max_second_leg_age_s) 
00583              && (d < closest_dist)){
00584           closest_dist = d;
00585           best = it;
00586         }
00587         
00588       }
00589 
00590       if(leg2 != end){
00591         double dist_between_legs = distance(leg1, leg2);
00592         if (dist_between_legs > leg_pair_separation_m){
00593           (*leg1)->object_id = "";
00594           (*leg1)->other = NULL;
00595           (*leg2)->object_id = "";
00596           (*leg2)->other = NULL;
00597         }else{
00598           (*leg1)->other = *leg2;
00599           (*leg2)->other = *leg1;
00600         }
00601       }else if(best != end){
00602         (*best)->object_id = (*leg1)->object_id;
00603         (*leg1)->other = *best;
00604         (*best)->other = *leg1;
00605       }
00606     }
00607 
00608     // Attempt to pair up legs with no id
00609     for(;;){
00610       list<SavedFeature*>::iterator best1 = end, best2 = end;
00611       double closest_dist = leg_pair_separation_m;
00612 
00613       for (leg1 = begin; leg1 != end; ++leg1)
00614       {
00615         // If this leg has an id or low reliability, skip
00616         if ((*leg1)->object_id != "" 
00617             || (*leg1)->getReliability() < leg_reliability_limit_) 
00618           continue;
00619 
00620         for ( leg2 = begin; leg2 != end; ++leg2)
00621         {
00622           if(    ((*leg2)->object_id != "") 
00623               || ((*leg2)->getReliability() < leg_reliability_limit_)
00624               || (leg1==leg2) ) continue;
00625           double d = distance(leg1, leg2);
00626           if(d<closest_dist){
00627             best1 = leg1;
00628             best2 = leg2;
00629           }
00630         }
00631       }
00632 
00633       if(best1 != end){
00634         char id[100];
00635         snprintf(id,100,"Person%d", next_p_id_++);
00636         (*best1)->object_id = std::string(id);
00637         (*best2)->object_id = std::string(id);
00638         (*best1)->other = *best2;
00639         (*best2)->other = *best1;
00640       }else{
00641         break;
00642       }
00643     }
00644   }
00645 
00646   void laserCallback(const sensor_msgs::LaserScan::ConstPtr& scan)
00647   {
00648     ScanProcessor processor(*scan, mask_);
00649 
00650     processor.splitConnected(connected_thresh_);
00651     processor.removeLessThan(5);
00652 
00653     CvMat* tmp_mat = cvCreateMat(1,feat_count_,CV_32FC1);
00654 
00655     // if no measurement matches to a tracker in the last <no_observation_timeout>  seconds: erase tracker
00656     ros::Time purge = scan->header.stamp + ros::Duration().fromSec(-no_observation_timeout_s);
00657     list<SavedFeature*>::iterator sf_iter = saved_features_.begin();
00658     while (sf_iter != saved_features_.end())
00659     {
00660       if ((*sf_iter)->meas_time_ < purge)
00661       {
00662         if( (*sf_iter)->other )
00663           (*sf_iter)->other->other = NULL;
00664         delete (*sf_iter);
00665         saved_features_.erase(sf_iter++);
00666       }
00667       else
00668         ++sf_iter;
00669     }
00670 
00671 
00672     // System update of trackers, and copy updated ones in propagate list
00673     list<SavedFeature*> propagated;
00674     for (list<SavedFeature*>::iterator sf_iter = saved_features_.begin();
00675          sf_iter != saved_features_.end();
00676          sf_iter++)
00677     {
00678       (*sf_iter)->propagate(scan->header.stamp);
00679       propagated.push_back(*sf_iter);
00680     }
00681 
00682 
00683     // Detection step: build up the set of "candidate" clusters
00684     // For each candidate, find the closest tracker (within threshold) and add to the match list
00685     // If no tracker is found, start a new one
00686     multiset<MatchedFeature> matches;
00687     for (list<SampleSet*>::iterator i = processor.getClusters().begin();
00688          i != processor.getClusters().end();
00689          i++)
00690     {
00691       vector<float> f = calcLegFeatures(*i, *scan);
00692 
00693       for (int k = 0; k < feat_count_; k++)
00694         tmp_mat->data.fl[k] = (float)(f[k]);
00695 
00696       float probability = forest.predict_prob( tmp_mat );
00697       Stamped<Point> loc((*i)->center(), scan->header.stamp, scan->header.frame_id);
00698       try {
00699         tfl_.transformPoint(fixed_frame, loc, loc);
00700       } catch(...) {
00701         ROS_WARN("TF exception spot 3.");
00702       }
00703 
00704       list<SavedFeature*>::iterator closest = propagated.end();
00705       float closest_dist = max_track_jump_m;
00706       
00707       for (list<SavedFeature*>::iterator pf_iter = propagated.begin();
00708            pf_iter != propagated.end();
00709            pf_iter++)
00710       {
00711         // find the closest distance between candidate and trackers
00712         float dist = loc.distance((*pf_iter)->position_);
00713         if ( dist < closest_dist )
00714         {
00715           closest = pf_iter;
00716           closest_dist = dist;
00717         }
00718       }
00719       // Nothing close to it, start a new track
00720       if (closest == propagated.end()) 
00721       {
00722         list<SavedFeature*>::iterator new_saved = saved_features_.insert(saved_features_.end(), new SavedFeature(loc, tfl_));
00723       }
00724       // Add the candidate, the tracker and the distance to a match list
00725       else
00726         matches.insert(MatchedFeature(*i,*closest,closest_dist,probability));
00727     }
00728     
00729     // loop through _sorted_ matches list
00730     // find the match with the shortest distance for each tracker
00731     while (matches.size() > 0)
00732     {
00733       multiset<MatchedFeature>::iterator matched_iter = matches.begin();
00734       bool found = false;
00735       list<SavedFeature*>::iterator pf_iter = propagated.begin();
00736       while (pf_iter != propagated.end())
00737       {
00738         // update the tracker with this candidate
00739         if (matched_iter->closest_ == *pf_iter)
00740         {
00741           // Transform candidate to fixed frame
00742           Stamped<Point> loc(matched_iter->candidate_->center(), scan->header.stamp, scan->header.frame_id);
00743           try {
00744             tfl_.transformPoint(fixed_frame, loc, loc);
00745           } catch(...) {
00746             ROS_WARN("TF exception spot 4.");
00747           }
00748 
00749           // Update the tracker with the candidate location
00750           matched_iter->closest_->update(loc, matched_iter->probability_);
00751           
00752           // remove this match and 
00753           matches.erase(matched_iter);
00754           propagated.erase(pf_iter++);
00755           found = true;
00756           break;
00757         }
00758         // still looking for the tracker to update
00759         else
00760         {
00761           pf_iter++;
00762         }
00763       }
00764 
00765       // didn't find tracker to update, because it was deleted above
00766       // try to assign the candidate to another tracker
00767       if (!found)
00768       {
00769         Stamped<Point> loc(matched_iter->candidate_->center(), scan->header.stamp, scan->header.frame_id);
00770         try {
00771           tfl_.transformPoint(fixed_frame, loc, loc);
00772         } catch(...) {
00773           ROS_WARN("TF exception spot 5.");
00774         }
00775 
00776         list<SavedFeature*>::iterator closest = propagated.end();
00777         float closest_dist = max_track_jump_m;
00778       
00779         for (list<SavedFeature*>::iterator remain_iter = propagated.begin();
00780              remain_iter != propagated.end();
00781              remain_iter++)
00782         {
00783           float dist = loc.distance((*remain_iter)->position_);
00784           if ( dist < closest_dist )
00785           {
00786             closest = remain_iter;
00787             closest_dist = dist;
00788           }
00789         }
00790 
00791         // no tracker is within a threshold of this candidate
00792         // so create a new tracker for this candidate
00793         if (closest == propagated.end())
00794           list<SavedFeature*>::iterator new_saved = saved_features_.insert(saved_features_.end(), new SavedFeature(loc, tfl_));
00795         else
00796           matches.insert(MatchedFeature(matched_iter->candidate_,*closest,closest_dist, matched_iter->probability_));
00797         matches.erase(matched_iter);
00798       }
00799     }
00800 
00801     cvReleaseMat(&tmp_mat); tmp_mat = 0;
00802     if(!use_seeds_)
00803       pairLegs();
00804 
00805     // Publish Data!
00806     int i = 0;
00807     vector<people_msgs::PositionMeasurement> people;
00808     vector<people_msgs::PositionMeasurement> legs;
00809 
00810     for (list<SavedFeature*>::iterator sf_iter = saved_features_.begin();
00811          sf_iter != saved_features_.end();
00812          sf_iter++,i++)
00813     {
00814       // reliability
00815       double reliability = (*sf_iter)->getReliability();
00816 
00817       if ((*sf_iter)->getReliability() > leg_reliability_limit_
00818           && publish_legs_){
00819         people_msgs::PositionMeasurement pos;
00820         pos.header.stamp = scan->header.stamp;
00821         pos.header.frame_id = fixed_frame;
00822         pos.name = "leg_detector";
00823         pos.object_id = (*sf_iter)->id_;
00824         pos.pos.x = (*sf_iter)->position_[0];
00825         pos.pos.y = (*sf_iter)->position_[1];
00826         pos.pos.z = (*sf_iter)->position_[2];
00827         pos.reliability = reliability;
00828         pos.covariance[0] = pow(0.3 / reliability,2.0);
00829         pos.covariance[1] = 0.0;
00830         pos.covariance[2] = 0.0;
00831         pos.covariance[3] = 0.0;
00832         pos.covariance[4] = pow(0.3 / reliability,2.0);
00833         pos.covariance[5] = 0.0;
00834         pos.covariance[6] = 0.0;
00835         pos.covariance[7] = 0.0;
00836         pos.covariance[8] = 10000.0;
00837         pos.initialization = 0;
00838         legs.push_back(pos);
00839 
00840       }
00841 
00842       if (publish_leg_markers_){
00843         visualization_msgs::Marker m;
00844         m.header.stamp = (*sf_iter)->time_;
00845         m.header.frame_id = fixed_frame;
00846         m.ns = "LEGS";
00847         m.id = i;
00848         m.type = m.SPHERE;
00849         m.pose.position.x = (*sf_iter)->position_[0];
00850         m.pose.position.y = (*sf_iter)->position_[1];
00851         m.pose.position.z = (*sf_iter)->position_[2];
00852 
00853         m.scale.x = .1;
00854         m.scale.y = .1;
00855         m.scale.z = .1;
00856         m.color.a = 1;
00857         m.lifetime = ros::Duration(0.5);
00858         if((*sf_iter)->object_id != ""){
00859           m.color.r = 1;
00860         }else{
00861           m.color.b = (*sf_iter)->getReliability();
00862         }
00863 
00864         markers_pub_.publish(m);
00865       }
00866 
00867       if (publish_people_ || publish_people_markers_){
00868         SavedFeature* other = (*sf_iter)->other;
00869         if(other!=NULL && other<(*sf_iter)){
00870           double dx = ((*sf_iter)->position_[0] + other->position_[0])/2,
00871                  dy = ((*sf_iter)->position_[1] + other->position_[1])/2,
00872                  dz = ((*sf_iter)->position_[2] + other->position_[2])/2;
00873 
00874           if (publish_people_){
00875             reliability = reliability * other->reliability;
00876             people_msgs::PositionMeasurement pos;
00877             pos.header.stamp = (*sf_iter)->time_;
00878             pos.header.frame_id = fixed_frame;
00879             pos.name = (*sf_iter)->object_id;;
00880             pos.object_id = (*sf_iter)->id_ + "|" + other->id_;
00881             pos.pos.x = dx;
00882             pos.pos.y = dy;
00883             pos.pos.z = dz;
00884             pos.reliability = reliability;
00885             pos.covariance[0] = pow(0.3 / reliability,2.0);
00886             pos.covariance[1] = 0.0;
00887             pos.covariance[2] = 0.0;
00888             pos.covariance[3] = 0.0;
00889             pos.covariance[4] = pow(0.3 / reliability,2.0);
00890             pos.covariance[5] = 0.0;
00891             pos.covariance[6] = 0.0;
00892             pos.covariance[7] = 0.0;
00893             pos.covariance[8] = 10000.0;
00894             pos.initialization = 0;
00895             people.push_back(pos);  
00896           }
00897    
00898           if (publish_people_markers_){
00899             visualization_msgs::Marker m;
00900             m.header.stamp = (*sf_iter)->time_;
00901             m.header.frame_id = fixed_frame;
00902             m.ns = "PEOPLE";
00903             m.id = i;
00904             m.type = m.SPHERE;
00905             m.pose.position.x = dx;
00906             m.pose.position.y = dy;
00907             m.pose.position.z = dz;
00908             m.scale.x = .2;
00909             m.scale.y = .2;
00910             m.scale.z = .2;
00911             m.color.a = 1;
00912             m.color.g = 1;
00913             m.lifetime = ros::Duration(0.5);
00914 
00915             markers_pub_.publish(m);
00916           }
00917         }
00918       }
00919     }
00920 
00921     people_msgs::PositionMeasurementArray array;
00922     array.header.stamp = ros::Time::now();
00923     if(publish_legs_){
00924       array.people = legs;
00925       leg_measurements_pub_.publish(array);
00926     }
00927     if(publish_people_){
00928       array.people = people;
00929       people_measurements_pub_.publish(array);
00930     }
00931   }
00932 };
00933 
00934 int main(int argc, char **argv)
00935 {
00936   ros::init(argc, argv,"leg_detector");
00937   g_argc = argc;
00938   g_argv = argv;
00939   ros::NodeHandle nh;
00940   LegDetector ld(nh);
00941   ros::spin();
00942   
00943   return 0;
00944 }
00945 


leg_detector
Author(s): Caroline Pantofaru
autogenerated on Thu Aug 27 2015 14:18:07