leg_detector.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2008, Willow Garage, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the Willow Garage nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34 #include <ros/ros.h>
35 
36 #include <leg_detector/LegDetectorConfig.h>
39 
40 #include <opencv/cxcore.h>
41 #include <opencv/cv.h>
42 #include <opencv/ml.h>
43 
44 #include <people_msgs/PositionMeasurement.h>
45 #include <people_msgs/PositionMeasurementArray.h>
46 #include <sensor_msgs/LaserScan.h>
47 
48 #include <tf/transform_listener.h>
49 #include <tf/message_filter.h>
51 
55 #include <visualization_msgs/Marker.h>
56 #include <dynamic_reconfigure/server.h>
57 
58 #include <algorithm>
59 
60 using namespace std;
61 using namespace laser_processor;
62 using namespace ros;
63 using namespace tf;
64 using namespace estimation;
65 using namespace BFL;
66 using namespace MatrixWrapper;
67 
68 
69 static double no_observation_timeout_s = 0.5;
70 static double max_second_leg_age_s = 2.0;
71 static double max_track_jump_m = 1.0;
72 static double max_meas_jump_m = 0.75; // 1.0
73 static double leg_pair_separation_m = 1.0;
74 static string fixed_frame = "odom_combined";
75 
76 static double kal_p = 4, kal_q = .002, kal_r = 10;
77 static bool use_filter = true;
78 
79 
81 {
82 public:
83  static int nextid;
85 
88 
89  string id_;
90  string object_id;
93 
94  double reliability, p;
95 
99 
100  // one leg tracker
102  : tfl_(tfl),
103  sys_sigma_(Vector3(0.05, 0.05, 0.05), Vector3(1.0, 1.0, 1.0)),
104  filter_("tracker_name", sys_sigma_),
105  reliability(-1.), p(4)
106  {
107  char id[100];
108  snprintf(id, 100, "legtrack%d", nextid++);
109  id_ = std::string(id);
110 
111  object_id = "";
112  time_ = loc.stamp_;
113  meas_time_ = loc.stamp_;
114  other = NULL;
115 
116  try
117  {
118  tfl_.transformPoint(fixed_frame, loc, loc);
119  }
120  catch (...)
121  {
122  ROS_WARN("TF exception spot 6.");
123  }
124  StampedTransform pose(Pose(Quaternion(0.0, 0.0, 0.0, 1.0), loc), loc.stamp_, id_, loc.frame_id_);
125  tfl_.setTransform(pose);
126 
127  StatePosVel prior_sigma(Vector3(0.1, 0.1, 0.1), Vector3(0.0000001, 0.0000001, 0.0000001));
128  filter_.initialize(loc, prior_sigma, time_.toSec());
129 
130  StatePosVel est;
131  filter_.getEstimate(est);
132 
133  updatePosition();
134  }
135 
136  void propagate(ros::Time time)
137  {
138  time_ = time;
139 
140  filter_.updatePrediction(time.toSec());
141 
142  updatePosition();
143  }
144 
145  void update(Stamped<Point> loc, double probability)
146  {
147  StampedTransform pose(Pose(Quaternion(0.0, 0.0, 0.0, 1.0), loc), loc.stamp_, id_, loc.frame_id_);
148  tfl_.setTransform(pose);
149 
150  meas_time_ = loc.stamp_;
151  time_ = meas_time_;
152 
153  SymmetricMatrix cov(3);
154  cov = 0.0;
155  cov(1, 1) = 0.0025;
156  cov(2, 2) = 0.0025;
157  cov(3, 3) = 0.0025;
158 
159  filter_.updateCorrection(loc, cov);
160 
161  updatePosition();
162 
163  if (reliability < 0 || !use_filter)
164  {
165  reliability = probability;
166  p = kal_p;
167  }
168  else
169  {
170  p += kal_q;
171  double k = p / (p + kal_r);
172  reliability += k * (probability - reliability);
173  p *= (1 - k);
174  }
175  }
176 
177  double getLifetime()
178  {
179  return filter_.getLifetime();
180  }
181 
182  double getReliability()
183  {
184  return reliability;
185  }
186 
187 private:
189  {
190  StatePosVel est;
191  filter_.getEstimate(est);
192 
193  position_[0] = est.pos_[0];
194  position_[1] = est.pos_[1];
195  position_[2] = est.pos_[2];
196  position_.stamp_ = time_;
197  position_.frame_id_ = fixed_frame;
198  double nreliability = fmin(1.0, fmax(0.1, est.vel_.length() / 0.5));
199  //reliability = fmax(reliability, nreliability);
200  }
201 };
202 
203 int SavedFeature::nextid = 0;
204 
205 
206 
207 
209 {
210 public:
213  float distance_;
214  double probability_;
215 
216  MatchedFeature(SampleSet* candidate, SavedFeature* closest, float distance, double probability)
217  : candidate_(candidate)
218  , closest_(closest)
219  , distance_(distance)
220  , probability_(probability)
221  {}
222 
223  inline bool operator< (const MatchedFeature& b) const
224  {
225  return (distance_ < b.distance_);
226  }
227 };
228 
229 int g_argc;
230 char** g_argv;
231 
232 
233 
234 
235 // actual legdetector node
237 {
238 public:
240 
242 
244 
246 
247  // cv::ml::RTrees forest;
248  cv::Ptr<cv::ml::RTrees> forest;
249 
251 
253 
254  char save_[100];
255 
256  list<SavedFeature*> saved_features_;
257  boost::mutex saved_mutex_;
258 
260 
262  bool publish_legs_, publish_people_, publish_leg_markers_, publish_people_markers_;
266 
270 
271  dynamic_reconfigure::Server<leg_detector::LegDetectorConfig> server_;
272 
277 
279  nh_(nh),
280  mask_count_(0),
281  feat_count_(0),
282  next_p_id_(0),
283  people_sub_(nh_, "people_tracker_filter", 10),
284  laser_sub_(nh_, "scan", 10),
285  people_notifier_(people_sub_, tfl_, fixed_frame, 10),
286  laser_notifier_(laser_sub_, tfl_, fixed_frame, 10)
287  {
288  if (g_argc > 1)
289  {
290  forest = cv::ml::RTrees::create();
291  cv::String feature_file = cv::String(g_argv[1]);
292  forest = cv::ml::StatModel::load<cv::ml::RTrees>(feature_file);
293  feat_count_ = forest->getVarCount();
294  printf("Loaded forest with %d features: %s\n", feat_count_, g_argv[1]);
295  }
296  else
297  {
298  printf("Please provide a trained random forests classifier as an input.\n");
299  shutdown();
300  }
301 
302  nh_.param<bool>("use_seeds", use_seeds_, !true);
303 
304  // advertise topics
305  leg_measurements_pub_ = nh_.advertise<people_msgs::PositionMeasurementArray>("leg_tracker_measurements", 0);
306  people_measurements_pub_ = nh_.advertise<people_msgs::PositionMeasurementArray>("people_tracker_measurements", 0);
307  markers_pub_ = nh_.advertise<visualization_msgs::Marker>("visualization_marker", 20);
308 
309  if (use_seeds_)
310  {
311  people_notifier_.registerCallback(boost::bind(&LegDetector::peopleCallback, this, _1));
312  people_notifier_.setTolerance(ros::Duration(0.01));
313  }
314  laser_notifier_.registerCallback(boost::bind(&LegDetector::laserCallback, this, _1));
315  laser_notifier_.setTolerance(ros::Duration(0.01));
316 
317  dynamic_reconfigure::Server<leg_detector::LegDetectorConfig>::CallbackType f;
318  f = boost::bind(&LegDetector::configure, this, _1, _2);
319  server_.setCallback(f);
320 
321  feature_id_ = 0;
322  }
323 
324 
326  {
327  }
328 
329  void configure(leg_detector::LegDetectorConfig &config, uint32_t level)
330  {
331  connected_thresh_ = config.connection_threshold;
332  min_points_per_group = config.min_points_per_group;
333  leg_reliability_limit_ = config.leg_reliability_limit;
334  publish_legs_ = config.publish_legs;
335  publish_people_ = config.publish_people;
336  publish_leg_markers_ = config.publish_leg_markers;
337  publish_people_markers_ = config.publish_people_markers;
338 
339  no_observation_timeout_s = config.no_observation_timeout;
340  max_second_leg_age_s = config.max_second_leg_age;
341  max_track_jump_m = config.max_track_jump;
342  max_meas_jump_m = config.max_meas_jump;
343  leg_pair_separation_m = config.leg_pair_separation;
344  if (fixed_frame.compare(config.fixed_frame) != 0)
345  {
346  fixed_frame = config.fixed_frame;
347  laser_notifier_.setTargetFrame(fixed_frame);
348  people_notifier_.setTargetFrame(fixed_frame);
349  }
350 
351  kal_p = config.kalman_p;
352  kal_q = config.kalman_q;
353  kal_r = config.kalman_r;
354  use_filter = config.kalman_on == 1;
355  }
356 
357  double distance(list<SavedFeature*>::iterator it1, list<SavedFeature*>::iterator it2)
358  {
359  Stamped<Point> one = (*it1)->position_, two = (*it2)->position_;
360  double dx = one[0] - two[0], dy = one[1] - two[1], dz = one[2] - two[2];
361  return sqrt(dx * dx + dy * dy + dz * dz);
362  }
363 
364  // Find the tracker that is closest to this person message
365  // If a tracker was already assigned to a person, keep this assignment when the distance between them is not too large.
366  void peopleCallback(const people_msgs::PositionMeasurement::ConstPtr& people_meas)
367  {
368  // If there are no legs, return.
369  if (saved_features_.empty())
370  return;
371 
372  Point pt;
373  pointMsgToTF(people_meas->pos, pt);
374  Stamped<Point> person_loc(pt, people_meas->header.stamp, people_meas->header.frame_id);
375  person_loc[2] = 0.0; // Ignore the height of the person measurement.
376  Stamped<Point> dest_loc(pt, people_meas->header.stamp, people_meas->header.frame_id); // Holder for all transformed pts.
377 
378  boost::mutex::scoped_lock lock(saved_mutex_);
379 
380  list<SavedFeature*>::iterator closest = saved_features_.end();
381  list<SavedFeature*>::iterator closest1 = saved_features_.end();
382  list<SavedFeature*>::iterator closest2 = saved_features_.end();
383  float closest_dist = max_meas_jump_m;
384  float closest_pair_dist = 2 * max_meas_jump_m;
385 
386  list<SavedFeature*>::iterator begin = saved_features_.begin();
387  list<SavedFeature*>::iterator end = saved_features_.end();
388  list<SavedFeature*>::iterator it1, it2;
389 
390  // If there's a pair of legs with the right label and within the max dist, return
391  // If there's one leg with the right label and within the max dist,
392  // find a partner for it from the unlabeled legs whose tracks are reasonably new.
393  // If no partners exist, label just the one leg.
394  // If there are no legs with the right label and within the max dist,
395  // find a pair of unlabeled legs and assign them the label.
396  // If all of the above cases fail,
397  // find a new unlabeled leg and assign the label.
398 
399  // For each tracker, get the distance to this person.
400  for (it1 = begin; it1 != end; ++it1)
401  {
402  try
403  {
404  tfl_.transformPoint((*it1)->id_, people_meas->header.stamp,
405  person_loc, fixed_frame, dest_loc);
406  //ROS_INFO("Succesful leg transformation at spot 7");
407  }
408  catch (...)
409  {
410  ROS_WARN("TF exception spot 7.");
411  }
412  (*it1)->dist_to_person_ = dest_loc.length();
413  }
414 
415  // Try to find one or two trackers with the same label and within the max distance of the person.
416  cout << "Looking for two legs" << endl;
417  it2 = end;
418  for (it1 = begin; it1 != end; ++it1)
419  {
420  // If this leg belongs to the person...
421  if ((*it1)->object_id == people_meas->object_id)
422  {
423  // and their distance is close enough...
424  if ((*it1)->dist_to_person_ < max_meas_jump_m)
425  {
426  // if this is the first leg we've found, assign it to it2. Otherwise, leave it assigned to it1 and break.
427  if (it2 == end)
428  it2 = it1;
429  else
430  break;
431  }
432  // Otherwise, remove the tracker's label, it doesn't belong to this person.
433  else
434  {
435  // the two trackers moved apart. This should not happen.
436  (*it1)->object_id = "";
437  }
438  }
439  }
440  // If we found two legs with the right label and within the max distance, all is good, return.
441  if (it1 != end && it2 != end)
442  {
443  cout << "Found matching pair. The second distance was " << (*it1)->dist_to_person_ << endl;
444  return;
445  }
446 
447 
448 
449  // If we only found one close leg with the right label, let's try to find a second leg that
450  // * doesn't yet have a label (=valid precondition),
451  // * is within the max distance,
452  // * is less than max_second_leg_age_s old.
453  cout << "Looking for one leg plus one new leg" << endl;
454  float dist_between_legs, closest_dist_between_legs;
455  if (it2 != end)
456  {
457  closest_dist = max_meas_jump_m;
458  closest = saved_features_.end();
459 
460  for (it1 = begin; it1 != end; ++it1)
461  {
462  // Skip this leg track if:
463  // - you're already using it.
464  // - it already has an id.
465  // - it's too old. Old unassigned trackers are unlikely to be the second leg in a pair.
466  // - it's too far away from the person.
467  if ((it1 == it2) || ((*it1)->object_id != "") || ((*it1)->getLifetime() > max_second_leg_age_s) || ((*it1)->dist_to_person_ >= closest_dist))
468  continue;
469 
470  // Get the distance between the two legs
471  try
472  {
473  tfl_.transformPoint((*it1)->id_, (*it2)->position_.stamp_, (*it2)->position_, fixed_frame, dest_loc);
474  }
475  catch (...)
476  {
477  ROS_WARN("TF exception getting distance between legs.");
478  }
479  dist_between_legs = dest_loc.length();
480 
481  // If this is the closest dist (and within range), and the legs are close together and unlabeled, mark it.
482  if (dist_between_legs < leg_pair_separation_m)
483  {
484  closest = it1;
485  closest_dist = (*it1)->dist_to_person_;
486  closest_dist_between_legs = dist_between_legs;
487  }
488  }
489  // If we found a close, unlabeled leg, set it's label.
490  if (closest != end)
491  {
492  cout << "Replaced one leg with a distance of " << closest_dist << " and a distance between the legs of " << closest_dist_between_legs << endl;
493  (*closest)->object_id = people_meas->object_id;
494  }
495  else
496  {
497  cout << "Returned one matched leg only" << endl;
498  }
499 
500  // Regardless of whether we found a second leg, return.
501  return;
502  }
503 
504  cout << "Looking for a pair of new legs" << endl;
505  // 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.
506  it1 = saved_features_.begin();
507  it2 = saved_features_.begin();
508  closest = saved_features_.end();
509  closest1 = saved_features_.end();
510  closest2 = saved_features_.end();
511  closest_dist = max_meas_jump_m;
512  closest_pair_dist = 2 * max_meas_jump_m;
513  for (; it1 != end; ++it1)
514  {
515  // Only look at trackers without ids and that are not too far away.
516  if ((*it1)->object_id != "" || (*it1)->dist_to_person_ >= max_meas_jump_m)
517  continue;
518 
519  // Keep the single closest leg around in case none of the pairs work out.
520  if ((*it1)->dist_to_person_ < closest_dist)
521  {
522  closest_dist = (*it1)->dist_to_person_;
523  closest = it1;
524  }
525 
526  // Find a second leg.
527  it2 = it1;
528  it2++;
529  for (; it2 != end; ++it2)
530  {
531  // Only look at trackers without ids and that are not too far away.
532  if ((*it2)->object_id != "" || (*it2)->dist_to_person_ >= max_meas_jump_m)
533  continue;
534 
535  // Get the distance between the two legs
536  try
537  {
538  tfl_.transformPoint((*it1)->id_, (*it2)->position_.stamp_, (*it2)->position_, fixed_frame, dest_loc);
539  }
540  catch (...)
541  {
542  ROS_WARN("TF exception getting distance between legs in spot 2.");
543  }
544  dist_between_legs = dest_loc.length();
545 
546  // Ensure that this pair of legs is the closest pair to the tracker, and that the distance between the legs isn't too large.
547  if ((*it1)->dist_to_person_ + (*it2)->dist_to_person_ < closest_pair_dist && dist_between_legs < leg_pair_separation_m)
548  {
549  closest_pair_dist = (*it1)->dist_to_person_ + (*it2)->dist_to_person_;
550  closest1 = it1;
551  closest2 = it2;
552  closest_dist_between_legs = dist_between_legs;
553  }
554  }
555  }
556  // Found a pair of legs.
557  if (closest1 != end && closest2 != end)
558  {
559  (*closest1)->object_id = people_meas->object_id;
560  (*closest2)->object_id = people_meas->object_id;
561  cout << "Found a completely new pair with total distance " << closest_pair_dist << " and a distance between the legs of " << closest_dist_between_legs << endl;
562  return;
563  }
564 
565  cout << "Looking for just one leg" << endl;
566  // No pair worked, try for just one leg.
567  if (closest != end)
568  {
569  (*closest)->object_id = people_meas->object_id;
570  cout << "Returned one new leg only" << endl;
571  return;
572  }
573 
574  cout << "Nothing matched" << endl;
575  }
576 
577  void pairLegs()
578  {
579  // Deal With legs that already have ids
580  list<SavedFeature*>::iterator begin = saved_features_.begin();
581  list<SavedFeature*>::iterator end = saved_features_.end();
582  list<SavedFeature*>::iterator leg1, leg2, best, it;
583 
584  for (leg1 = begin; leg1 != end; ++leg1)
585  {
586  // If this leg has no id, skip
587  if ((*leg1)->object_id == "")
588  continue;
589 
590  leg2 = end;
591  best = end;
592  double closest_dist = leg_pair_separation_m;
593  for (it = begin; it != end; ++it)
594  {
595  if (it == leg1) continue;
596 
597  if ((*it)->object_id == (*leg1)->object_id)
598  {
599  leg2 = it;
600  break;
601  }
602 
603  if ((*it)->object_id != "")
604  continue;
605 
606  double d = distance(it, leg1);
607  if (((*it)->getLifetime() <= max_second_leg_age_s)
608  && (d < closest_dist))
609  {
610  closest_dist = d;
611  best = it;
612  }
613 
614  }
615 
616  if (leg2 != end)
617  {
618  double dist_between_legs = distance(leg1, leg2);
619  if (dist_between_legs > leg_pair_separation_m)
620  {
621  (*leg1)->object_id = "";
622  (*leg1)->other = NULL;
623  (*leg2)->object_id = "";
624  (*leg2)->other = NULL;
625  }
626  else
627  {
628  (*leg1)->other = *leg2;
629  (*leg2)->other = *leg1;
630  }
631  }
632  else if (best != end)
633  {
634  (*best)->object_id = (*leg1)->object_id;
635  (*leg1)->other = *best;
636  (*best)->other = *leg1;
637  }
638  }
639 
640  // Attempt to pair up legs with no id
641  for (;;)
642  {
643  list<SavedFeature*>::iterator best1 = end, best2 = end;
644  double closest_dist = leg_pair_separation_m;
645 
646  for (leg1 = begin; leg1 != end; ++leg1)
647  {
648  // If this leg has an id or low reliability, skip
649  if ((*leg1)->object_id != ""
650  || (*leg1)->getReliability() < leg_reliability_limit_)
651  continue;
652 
653  for (leg2 = begin; leg2 != end; ++leg2)
654  {
655  if (((*leg2)->object_id != "")
656  || ((*leg2)->getReliability() < leg_reliability_limit_)
657  || (leg1 == leg2)) continue;
658  double d = distance(leg1, leg2);
659  if (d < closest_dist)
660  {
661  best1 = leg1;
662  best2 = leg2;
663  }
664  }
665  }
666 
667  if (best1 != end)
668  {
669  char id[100];
670  snprintf(id, 100, "Person%d", next_p_id_++);
671  (*best1)->object_id = std::string(id);
672  (*best2)->object_id = std::string(id);
673  (*best1)->other = *best2;
674  (*best2)->other = *best1;
675  }
676  else
677  {
678  break;
679  }
680  }
681  }
682 
683  void laserCallback(const sensor_msgs::LaserScan::ConstPtr& scan)
684  {
685  ScanProcessor processor(*scan, mask_);
686 
687  processor.splitConnected(connected_thresh_);
688  processor.removeLessThan(5);
689 
690  cv::Mat tmp_mat = cv::Mat(1, feat_count_, CV_32FC1);
691 
692  // if no measurement matches to a tracker in the last <no_observation_timeout> seconds: erase tracker
693  ros::Time purge = scan->header.stamp + ros::Duration().fromSec(-no_observation_timeout_s);
694  list<SavedFeature*>::iterator sf_iter = saved_features_.begin();
695  while (sf_iter != saved_features_.end())
696  {
697  if ((*sf_iter)->meas_time_ < purge)
698  {
699  if ((*sf_iter)->other)
700  (*sf_iter)->other->other = NULL;
701  delete(*sf_iter);
702  saved_features_.erase(sf_iter++);
703  }
704  else
705  ++sf_iter;
706  }
707 
708 
709  // System update of trackers, and copy updated ones in propagate list
710  list<SavedFeature*> propagated;
711  for (list<SavedFeature*>::iterator sf_iter = saved_features_.begin();
712  sf_iter != saved_features_.end();
713  sf_iter++)
714  {
715  (*sf_iter)->propagate(scan->header.stamp);
716  propagated.push_back(*sf_iter);
717  }
718 
719 
720  // Detection step: build up the set of "candidate" clusters
721  // For each candidate, find the closest tracker (within threshold) and add to the match list
722  // If no tracker is found, start a new one
723  multiset<MatchedFeature> matches;
724  for (list<SampleSet*>::iterator i = processor.getClusters().begin();
725  i != processor.getClusters().end();
726  i++)
727  {
728  vector<float> f = calcLegFeatures(*i, *scan);
729 
730  for (int k = 0; k < feat_count_; k++)
731  tmp_mat.data[k] = (float)(f[k]);
732 
733  // Probability is the fuzzy measure of the probability that the second element should be chosen,
734  // in opencv2 RTrees had a method predict_prob, but that disapeared in opencv3, this is the
735  // substitute.
736  float probability = 0.5 -
737  forest->predict(tmp_mat, cv::noArray(), cv::ml::RTrees::PREDICT_SUM) /
738  forest->getRoots().size();
739  Stamped<Point> loc((*i)->center(), scan->header.stamp, scan->header.frame_id);
740  try
741  {
742  tfl_.transformPoint(fixed_frame, loc, loc);
743  }
744  catch (...)
745  {
746  ROS_WARN("TF exception spot 3.");
747  }
748 
749  list<SavedFeature*>::iterator closest = propagated.end();
750  float closest_dist = max_track_jump_m;
751 
752  for (list<SavedFeature*>::iterator pf_iter = propagated.begin();
753  pf_iter != propagated.end();
754  pf_iter++)
755  {
756  // find the closest distance between candidate and trackers
757  float dist = loc.distance((*pf_iter)->position_);
758  if (dist < closest_dist)
759  {
760  closest = pf_iter;
761  closest_dist = dist;
762  }
763  }
764  // Nothing close to it, start a new track
765  if (closest == propagated.end())
766  {
767  list<SavedFeature*>::iterator new_saved = saved_features_.insert(saved_features_.end(), new SavedFeature(loc, tfl_));
768  }
769  // Add the candidate, the tracker and the distance to a match list
770  else
771  matches.insert(MatchedFeature(*i, *closest, closest_dist, probability));
772  }
773 
774  // loop through _sorted_ matches list
775  // find the match with the shortest distance for each tracker
776  while (matches.size() > 0)
777  {
778  multiset<MatchedFeature>::iterator matched_iter = matches.begin();
779  bool found = false;
780  list<SavedFeature*>::iterator pf_iter = propagated.begin();
781  while (pf_iter != propagated.end())
782  {
783  // update the tracker with this candidate
784  if (matched_iter->closest_ == *pf_iter)
785  {
786  // Transform candidate to fixed frame
787  Stamped<Point> loc(matched_iter->candidate_->center(), scan->header.stamp, scan->header.frame_id);
788  try
789  {
790  tfl_.transformPoint(fixed_frame, loc, loc);
791  }
792  catch (...)
793  {
794  ROS_WARN("TF exception spot 4.");
795  }
796 
797  // Update the tracker with the candidate location
798  matched_iter->closest_->update(loc, matched_iter->probability_);
799 
800  // remove this match and
801  matches.erase(matched_iter);
802  propagated.erase(pf_iter++);
803  found = true;
804  break;
805  }
806  // still looking for the tracker to update
807  else
808  {
809  pf_iter++;
810  }
811  }
812 
813  // didn't find tracker to update, because it was deleted above
814  // try to assign the candidate to another tracker
815  if (!found)
816  {
817  Stamped<Point> loc(matched_iter->candidate_->center(), scan->header.stamp, scan->header.frame_id);
818  try
819  {
820  tfl_.transformPoint(fixed_frame, loc, loc);
821  }
822  catch (...)
823  {
824  ROS_WARN("TF exception spot 5.");
825  }
826 
827  list<SavedFeature*>::iterator closest = propagated.end();
828  float closest_dist = max_track_jump_m;
829 
830  for (list<SavedFeature*>::iterator remain_iter = propagated.begin();
831  remain_iter != propagated.end();
832  remain_iter++)
833  {
834  float dist = loc.distance((*remain_iter)->position_);
835  if (dist < closest_dist)
836  {
837  closest = remain_iter;
838  closest_dist = dist;
839  }
840  }
841 
842  // no tracker is within a threshold of this candidate
843  // so create a new tracker for this candidate
844  if (closest == propagated.end())
845  list<SavedFeature*>::iterator new_saved = saved_features_.insert(saved_features_.end(), new SavedFeature(loc, tfl_));
846  else
847  matches.insert(MatchedFeature(matched_iter->candidate_, *closest, closest_dist, matched_iter->probability_));
848  matches.erase(matched_iter);
849  }
850  }
851 
852  if (!use_seeds_)
853  pairLegs();
854 
855  // Publish Data!
856  int i = 0;
857  vector<people_msgs::PositionMeasurement> people;
858  vector<people_msgs::PositionMeasurement> legs;
859 
860  for (list<SavedFeature*>::iterator sf_iter = saved_features_.begin();
861  sf_iter != saved_features_.end();
862  sf_iter++, i++)
863  {
864  // reliability
865  double reliability = (*sf_iter)->getReliability();
866 
867  if ((*sf_iter)->getReliability() > leg_reliability_limit_
868  && publish_legs_)
869  {
870  people_msgs::PositionMeasurement pos;
871  pos.header.stamp = scan->header.stamp;
872  pos.header.frame_id = fixed_frame;
873  pos.name = "leg_detector";
874  pos.object_id = (*sf_iter)->id_;
875  pos.pos.x = (*sf_iter)->position_[0];
876  pos.pos.y = (*sf_iter)->position_[1];
877  pos.pos.z = (*sf_iter)->position_[2];
878  pos.reliability = reliability;
879  pos.covariance[0] = pow(0.3 / reliability, 2.0);
880  pos.covariance[1] = 0.0;
881  pos.covariance[2] = 0.0;
882  pos.covariance[3] = 0.0;
883  pos.covariance[4] = pow(0.3 / reliability, 2.0);
884  pos.covariance[5] = 0.0;
885  pos.covariance[6] = 0.0;
886  pos.covariance[7] = 0.0;
887  pos.covariance[8] = 10000.0;
888  pos.initialization = 0;
889  legs.push_back(pos);
890 
891  }
892 
893  if (publish_leg_markers_)
894  {
895  visualization_msgs::Marker m;
896  m.header.stamp = (*sf_iter)->time_;
897  m.header.frame_id = fixed_frame;
898  m.ns = "LEGS";
899  m.id = i;
900  m.type = m.SPHERE;
901  m.pose.position.x = (*sf_iter)->position_[0];
902  m.pose.position.y = (*sf_iter)->position_[1];
903  m.pose.position.z = (*sf_iter)->position_[2];
904 
905  m.scale.x = .1;
906  m.scale.y = .1;
907  m.scale.z = .1;
908  m.color.a = 1;
909  m.lifetime = ros::Duration(0.5);
910  if ((*sf_iter)->object_id != "")
911  {
912  m.color.r = 1;
913  }
914  else
915  {
916  m.color.b = (*sf_iter)->getReliability();
917  }
918 
919  markers_pub_.publish(m);
920  }
921 
922  if (publish_people_ || publish_people_markers_)
923  {
924  SavedFeature* other = (*sf_iter)->other;
925  if (other != NULL && other < (*sf_iter))
926  {
927  double dx = ((*sf_iter)->position_[0] + other->position_[0]) / 2,
928  dy = ((*sf_iter)->position_[1] + other->position_[1]) / 2,
929  dz = ((*sf_iter)->position_[2] + other->position_[2]) / 2;
930 
931  if (publish_people_)
932  {
933  reliability = reliability * other->reliability;
934  people_msgs::PositionMeasurement pos;
935  pos.header.stamp = (*sf_iter)->time_;
936  pos.header.frame_id = fixed_frame;
937  pos.name = (*sf_iter)->object_id;;
938  pos.object_id = (*sf_iter)->id_ + "|" + other->id_;
939  pos.pos.x = dx;
940  pos.pos.y = dy;
941  pos.pos.z = dz;
942  pos.reliability = reliability;
943  pos.covariance[0] = pow(0.3 / reliability, 2.0);
944  pos.covariance[1] = 0.0;
945  pos.covariance[2] = 0.0;
946  pos.covariance[3] = 0.0;
947  pos.covariance[4] = pow(0.3 / reliability, 2.0);
948  pos.covariance[5] = 0.0;
949  pos.covariance[6] = 0.0;
950  pos.covariance[7] = 0.0;
951  pos.covariance[8] = 10000.0;
952  pos.initialization = 0;
953  people.push_back(pos);
954  }
955 
956  if (publish_people_markers_)
957  {
958  visualization_msgs::Marker m;
959  m.header.stamp = (*sf_iter)->time_;
960  m.header.frame_id = fixed_frame;
961  m.ns = "PEOPLE";
962  m.id = i;
963  m.type = m.SPHERE;
964  m.pose.position.x = dx;
965  m.pose.position.y = dy;
966  m.pose.position.z = dz;
967  m.scale.x = .2;
968  m.scale.y = .2;
969  m.scale.z = .2;
970  m.color.a = 1;
971  m.color.g = 1;
972  m.lifetime = ros::Duration(0.5);
973 
974  markers_pub_.publish(m);
975  }
976  }
977  }
978  }
979 
980  people_msgs::PositionMeasurementArray array;
981  array.header.stamp = ros::Time::now();
982  if (publish_legs_)
983  {
984  array.people = legs;
985  leg_measurements_pub_.publish(array);
986  }
987  if (publish_people_)
988  {
989  array.people = people;
990  people_measurements_pub_.publish(array);
991  }
992  }
993 };
994 
995 int main(int argc, char **argv)
996 {
997  ros::init(argc, argv, "leg_detector");
998  g_argc = argc;
999  g_argv = argv;
1000  ros::NodeHandle nh;
1001  LegDetector ld(nh);
1002  ros::spin();
1003 
1004  return 0;
1005 }
1006 
Stamped< Point > position_
virtual void getEstimate(BFL::StatePosVel &est) const
d
static double max_second_leg_age_s
int min_points_per_group
string object_id
TransformListener tfl_
double leg_reliability_limit_
void publish(const boost::shared_ptr< M > &message) const
void laserCallback(const sensor_msgs::LaserScan::ConstPtr &scan)
ros::Publisher leg_measurements_pub_
cv::Ptr< cv::ml::RTrees > forest
void configure(leg_detector::LegDetectorConfig &config, uint32_t level)
f
virtual double getLifetime() const
char ** g_argv
dynamic_reconfigure::Server< leg_detector::LegDetectorConfig > server_
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
bool publish_people_markers_
int g_argc
message_filters::Subscriber< sensor_msgs::LaserScan > laser_sub_
bool setTransform(const StampedTransform &transform, const std::string &authority="default_authority")
BFL::StatePosVel sys_sigma_
void transformPoint(const std::string &target_frame, const geometry_msgs::PointStamped &stamped_in, geometry_msgs::PointStamped &stamped_out) const
NodeHandle nh_
TFSIMD_FORCE_INLINE tfScalar distance(const Vector3 &v) const
static double kal_q
float connected_thresh_
#define ROS_WARN(...)
message_filters::Subscriber< people_msgs::PositionMeasurement > people_sub_
SampleSet * candidate_
std::vector< float > calcLegFeatures(laser_processor::SampleSet *cluster, const sensor_msgs::LaserScan &scan)
list< SavedFeature * > saved_features_
ROSCPP_DECL void spin(Spinner &spinner)
tf::MessageFilter< sensor_msgs::LaserScan > laser_notifier_
ros::Publisher people_measurements_pub_
static double max_track_jump_m
static double kal_p
A namespace containing the laser processor helper classes.
boost::mutex saved_mutex_
int main(int argc, char **argv)
Duration & fromSec(double t)
TransformListener & tfl_
SavedFeature * other
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void update(Stamped< Point > loc, double probability)
static double max_meas_jump_m
double getReliability()
An ordered set of Samples.
void propagate(ros::Time time)
double distance(list< SavedFeature * >::iterator it1, list< SavedFeature * >::iterator it2)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
double getLifetime()
virtual void initialize(const BFL::StatePosVel &mu, const BFL::StatePosVel &sigma, const double time)
static string fixed_frame
static double leg_pair_separation_m
ros::Time meas_time_
tf::MessageFilter< people_msgs::PositionMeasurement > people_notifier_
std::list< SampleSet * > & getClusters()
TrackerKalman filter_
double reliability
void peopleCallback(const people_msgs::PositionMeasurement::ConstPtr &people_meas)
ros::Time stamp_
std::string frame_id_
tf::Vector3 vel_
LegDetector(ros::NodeHandle nh)
void updatePosition()
ros::Time time_
ros::Publisher markers_pub_
static int nextid
ScanMask mask_
float dist_to_person_
static Time now()
tf::Vector3 pos_
ROSCPP_DECL void shutdown()
void setTargetFrame(const std::string &target_frame)
SavedFeature * closest_
virtual bool updateCorrection(const tf::Vector3 &meas, const MatrixWrapper::SymmetricMatrix &cov)
static double kal_r
static bool use_filter
A mask for filtering out Samples based on range.
SavedFeature(Stamped< Point > loc, TransformListener &tfl)
void setTolerance(const ros::Duration &tolerance)
MatchedFeature(SampleSet *candidate, SavedFeature *closest, float distance, double probability)
static double no_observation_timeout_s
virtual bool updatePrediction(const double time)
TFSIMD_FORCE_INLINE tfScalar length() const
Connection registerCallback(const C &callback)


leg_detector
Author(s): Caroline Pantofaru
autogenerated on Fri Jun 7 2019 22:07:52