00001
00060
00061
00062
00063 #include <cob_people_detection/detection_tracker_node.h>
00064 #include <munkres/munkres.h>
00065
00066
00067
00068
00069
00070 #include <ros/ros.h>
00071 #include <ros/package.h>
00072
00073
00074 #include <sensor_msgs/Image.h>
00075 #include <cob_perception_msgs/DetectionArray.h>
00076
00077
00078
00079
00080
00081 #include <message_filters/subscriber.h>
00082 #include <message_filters/synchronizer.h>
00083 #include <message_filters/sync_policies/approximate_time.h>
00084 #include <image_transport/image_transport.h>
00085 #include <image_transport/subscriber_filter.h>
00086
00087
00088 #include <opencv/cv.h>
00089 #include <opencv/highgui.h>
00090 #include <cv_bridge/cv_bridge.h>
00091 #include <sensor_msgs/image_encodings.h>
00092
00093
00094 #include <boost/bind.hpp>
00095 #include <boost/thread/mutex.hpp>
00096
00097
00098 #include "cob_vision_utils/GlobalDefines.h"
00099
00100
00101 #include "cob_people_detection/timer.h"
00102
00103 #include <sstream>
00104 #include <string>
00105 #include <vector>
00106
00107 using namespace ipa_PeopleDetector;
00108
00109 DetectionTrackerNode::DetectionTrackerNode(ros::NodeHandle nh) :
00110 node_handle_(nh)
00111 {
00112 it_ = 0;
00113 sync_input_2_ = 0;
00114
00115
00116 std::cout << "\n---------------------------\nPeople Detection Parameters:\n---------------------------\n";
00117 node_handle_.param("debug", debug_, false);
00118 std::cout << "debug = " << debug_ << "\n";
00119 node_handle_.param("rosbag_mode", rosbag_mode_, false);
00120 std::cout << "use rosbag mode: " << rosbag_mode_ << "\n";
00121 node_handle_.param("use_people_segmentation", use_people_segmentation_, true);
00122 std::cout << "use_people_segmentation = " << use_people_segmentation_ << "\n";
00123 node_handle_.param("face_redetection_time", face_redetection_time_, 2.0);
00124 std::cout << "face_redetection_time = " << face_redetection_time_ << "\n";
00125 double publish_currently_not_visible_detections_timespan = face_redetection_time_;
00126 node_handle_.param("publish_currently_not_visible_detections_timespan", publish_currently_not_visible_detections_timespan, face_redetection_time_);
00127 std::cout << "publish_currently_not_visible_detections_timespan = " << publish_currently_not_visible_detections_timespan << "\n";
00128 publish_currently_not_visible_detections_timespan_ = ros::Duration(publish_currently_not_visible_detections_timespan);
00129 node_handle_.param("min_segmented_people_ratio_face", min_segmented_people_ratio_face_, 0.7);
00130 std::cout << "min_segmented_people_ratio_face = " << min_segmented_people_ratio_face_ << "\n";
00131 node_handle_.param("min_segmented_people_ratio_head", min_segmented_people_ratio_head_, 0.2);
00132 std::cout << "min_segmented_people_ratio_head = " << min_segmented_people_ratio_head_ << "\n";
00133 node_handle_.param("tracking_range_m", tracking_range_m_, 0.3);
00134 std::cout << "tracking_range_m = " << tracking_range_m_ << "\n";
00135 node_handle_.param("face_identification_score_decay_rate", face_identification_score_decay_rate_, 0.9);
00136 std::cout << "face_identification_score_decay_rate = " << face_identification_score_decay_rate_ << "\n";
00137 node_handle_.param("min_face_identification_score_to_publish", min_face_identification_score_to_publish_, 0.9);
00138 std::cout << "min_face_identification_score_to_publish = " << min_face_identification_score_to_publish_ << "\n";
00139 node_handle_.param("fall_back_to_unknown_identification", fall_back_to_unknown_identification_, true);
00140 std::cout << "fall_back_to_unknown_identification = " << fall_back_to_unknown_identification_ << "\n";
00141 node_handle_.param("display_timing", display_timing_, false);
00142 std::cout << "display_timing = " << display_timing_ << "\n";
00143
00144
00145 it_ = new image_transport::ImageTransport(node_handle_);
00146 people_segmentation_image_sub_.subscribe(*it_, "people_segmentation_image", 1);
00147 face_position_subscriber_.subscribe(node_handle_, "face_position_array_in", 1);
00148
00149
00150 sensor_msgs::Image::ConstPtr nullPtr;
00151 if (use_people_segmentation_ == true)
00152 {
00153 sync_input_2_ = new message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_perception_msgs::DetectionArray, sensor_msgs::Image> >(2);
00154 sync_input_2_->connectInput(face_position_subscriber_, people_segmentation_image_sub_);
00155 sync_input_2_->registerCallback(boost::bind(&DetectionTrackerNode::inputCallback, this, _1, _2));
00156 }
00157 else
00158 {
00159 face_position_subscriber_.registerCallback(boost::bind(&DetectionTrackerNode::inputCallback, this, _1, nullPtr));
00160 }
00161
00162
00163 face_position_publisher_ = node_handle_.advertise<cob_perception_msgs::DetectionArray>("face_position_array", 1);
00164
00165 std::cout << "DetectionTrackerNode initialized." << std::endl;
00166 }
00167
00168 DetectionTrackerNode::~DetectionTrackerNode()
00169 {
00170 if (it_ != 0)
00171 delete it_;
00172 if (sync_input_2_ != 0)
00173 delete sync_input_2_;
00174 }
00175
00177 unsigned long DetectionTrackerNode::convertColorImageMessageToMat(const sensor_msgs::Image::ConstPtr& image_msg, cv_bridge::CvImageConstPtr& image_ptr, cv::Mat& image)
00178 {
00179 try
00180 {
00181 image_ptr = cv_bridge::toCvShare(image_msg, sensor_msgs::image_encodings::BGR8);
00182 } catch (cv_bridge::Exception& e)
00183 {
00184 ROS_ERROR("PeopleDetection: cv_bridge exception: %s", e.what());
00185 return ipa_Utils::RET_FAILED;
00186 }
00187 image = image_ptr->image;
00188
00189 return ipa_Utils::RET_OK;
00190 }
00191
00198 unsigned long DetectionTrackerNode::copyDetection(const cob_perception_msgs::Detection& src, cob_perception_msgs::Detection& dest, bool update,
00199 unsigned int updateIndex)
00200 {
00201
00202 dest.mask.roi.x = src.mask.roi.x;
00203 dest.mask.roi.y = src.mask.roi.y;
00204 dest.mask.roi.width = src.mask.roi.width;
00205 dest.mask.roi.height = src.mask.roi.height;
00206
00207
00208
00209
00210
00211 dest.pose.pose = src.pose.pose;
00212
00213
00214 if (update == true)
00215 {
00216
00217
00218
00219 if (face_identification_votes_[updateIndex].find(src.label) == face_identification_votes_[updateIndex].end())
00220 face_identification_votes_[updateIndex][src.label] = 1.0;
00221 else
00222 face_identification_votes_[updateIndex][src.label] += 1.0;
00223
00224
00225
00226 double max_score = 0;
00227 dest.label = src.label;
00228 for (std::map<std::string, double>::iterator face_identification_votes_it = face_identification_votes_[updateIndex].begin(); face_identification_votes_it
00229 != face_identification_votes_[updateIndex].end(); face_identification_votes_it++)
00230 {
00231
00232 face_identification_votes_it->second *= face_identification_score_decay_rate_;
00233 std::string label = face_identification_votes_it->first;
00234 if (face_identification_votes_it->second > max_score && (fall_back_to_unknown_identification_ == true || (label != "Unknown" && fall_back_to_unknown_identification_
00235 == false)) && label != "UnknownHead" )
00236 {
00237 max_score = face_identification_votes_it->second;
00238 dest.label = label;
00239 }
00240 }
00241
00242
00243 if (face_identification_votes_[updateIndex][dest.label] > face_identification_votes_[updateIndex]["UnknownHead"])
00244 face_identification_votes_[updateIndex]["UnknownHead"] = face_identification_votes_[updateIndex][dest.label];
00245 if (fall_back_to_unknown_identification_ == false)
00246 {
00247 if (face_identification_votes_[updateIndex]["Unknown"] > face_identification_votes_[updateIndex]["UnknownHead"])
00248 face_identification_votes_[updateIndex]["UnknownHead"] = face_identification_votes_[updateIndex]["Unknown"];
00249 }
00250 }
00251 else
00252 dest.label = src.label;
00253
00254 if (dest.label == "UnknownHead")
00255 dest.label = "Unknown";
00256
00257
00258
00259
00260
00261
00262
00263 dest.detector = src.detector;
00264
00265 dest.header.stamp = src.header.stamp;
00266
00267 return ipa_Utils::RET_OK;
00268 }
00269
00270 inline double abs(double x)
00271 {
00272 return ((x < 0) ? -x : x);
00273 }
00274
00278 double DetectionTrackerNode::computeFacePositionDistanceTrackingRange(const cob_perception_msgs::Detection& previous_detection,
00279 const cob_perception_msgs::Detection& current_detection)
00280 {
00281 const geometry_msgs::Point* point_1 = &(previous_detection.pose.pose.position);
00282 const geometry_msgs::Point* point_2 = &(current_detection.pose.pose.position);
00283
00284 double dx = abs(point_1->x - point_2->x);
00285 double dy = abs(point_1->y - point_2->y);
00286 double dz = abs(point_1->z - point_2->z);
00287
00288
00289 if (dx > tracking_range_m_ || dy > tracking_range_m_ || dz > tracking_range_m_)
00290 {
00291
00292 return DBL_MAX;
00293 }
00294
00295
00296 double dist = dx * dx + dy * dy + dz * dz;
00297 return dist;
00298 }
00299
00300 double DetectionTrackerNode::computeFacePositionDistance(const cob_perception_msgs::Detection& previous_detection,
00301 const cob_perception_msgs::Detection& current_detection)
00302 {
00303 const geometry_msgs::Point* point_1 = &(previous_detection.pose.pose.position);
00304 const geometry_msgs::Point* point_2 = &(current_detection.pose.pose.position);
00305
00306 double dx = point_1->x - point_2->x;
00307 double dy = point_1->y - point_2->y;
00308 double dz = point_1->z - point_2->z;
00309
00310 return sqrt(dx * dx + dy * dy + dz * dz);
00311 }
00312
00315 unsigned long DetectionTrackerNode::removeMultipleInstancesOfLabel()
00316 {
00317
00318 for (int i = 0; i < (int)face_position_accumulator_.size(); i++)
00319 {
00320
00321 std::string label = face_position_accumulator_[i].label;
00322
00323
00324 if (label != "Unknown" && label != "No face")
00325 {
00326 for (int j = 0; j < (int)face_position_accumulator_.size(); j++)
00327 {
00328 if (j == i)
00329 continue;
00330
00331 if (face_position_accumulator_[j].label == label)
00332 {
00333 if (debug_)
00334 std::cout << "face_identification_votes_[i][" << label << "] = " << face_identification_votes_[i][label] << " face_identification_votes_[j][" << label
00335 << "] = " << face_identification_votes_[j][label] << "\n";
00336
00337
00338 if (face_identification_votes_[i][label] < face_identification_votes_[j][label])
00339 {
00340 face_position_accumulator_[i].label = "Unknown";
00341
00342 if (face_identification_votes_[i][label] > face_identification_votes_[i]["Unknown"])
00343 face_identification_votes_[i]["Unknown"] = face_identification_votes_[i][label];
00344 }
00345 }
00346 }
00347 }
00348 }
00349
00350 return ipa_Utils::RET_OK;
00351 }
00352
00353 unsigned long DetectionTrackerNode::prepareFacePositionMessage(cob_perception_msgs::DetectionArray& face_position_msg_out, ros::Time image_recording_time)
00354 {
00355
00356 std::vector < cob_perception_msgs::Detection > faces_to_publish;
00357 for (int i = 0; i < (int)face_position_accumulator_.size(); i++)
00358 {
00359 if (debug_)
00360 std::cout << "'UnknownHead' score: " << face_identification_votes_[i]["UnknownHead"] << " label '" << face_position_accumulator_[i].label << "' score: "
00361 << face_identification_votes_[i][face_position_accumulator_[i].label] << " - ";
00362 if ((face_identification_votes_[i][face_position_accumulator_[i].label] > min_face_identification_score_to_publish_ || face_identification_votes_[i]["UnknownHead"]
00363 > min_face_identification_score_to_publish_) && ((image_recording_time - face_position_accumulator_[i].header.stamp)
00364 < publish_currently_not_visible_detections_timespan_))
00365 {
00366 faces_to_publish.push_back(face_position_accumulator_[i]);
00367 if (debug_)
00368 std::cout << "published\n";
00369 }
00370 else if (debug_)
00371 std::cout << "not published\n";
00372 }
00373 face_position_msg_out.detections = faces_to_publish;
00374
00375
00376
00377
00378
00379
00380 face_position_msg_out.header.stamp = ros::Time::now();
00381
00382 return ipa_Utils::RET_OK;
00383 }
00384
00386 void DetectionTrackerNode::inputCallback(const cob_perception_msgs::DetectionArray::ConstPtr& face_position_msg_in,
00387 const sensor_msgs::Image::ConstPtr& people_segmentation_image_msg)
00388 {
00389
00390
00391
00392
00393
00394
00395
00396 cv_bridge::CvImageConstPtr people_segmentation_image_ptr;
00397 cv::Mat people_segmentation_image;
00398 if (use_people_segmentation_ == true)
00399 convertColorImageMessageToMat(people_segmentation_image_msg, people_segmentation_image_ptr, people_segmentation_image);
00400
00401 if (debug_)
00402 std::cout << "incoming detections: " << face_position_msg_in->detections.size() << "\n";
00403
00404
00405 ros::Duration timeSpan(face_redetection_time_);
00406
00407 if (!rosbag_mode_)
00408 {
00409 for (int i = (int)face_position_accumulator_.size() - 1; i >= 0; i--)
00410 {
00411 if ((ros::Time::now() - face_position_accumulator_[i].header.stamp) > timeSpan)
00412 {
00413 face_position_accumulator_.erase(face_position_accumulator_.begin() + i);
00414 face_identification_votes_.erase(face_identification_votes_.begin() + i);
00415 }
00416 }
00417 if (debug_)
00418 std::cout << "Old face positions deleted.\n";
00419 }
00420
00421
00422 std::vector<int> face_detection_indices;
00423 if (use_people_segmentation_ == true)
00424 {
00425 for (int i = 0; i < (int)face_position_msg_in->detections.size(); i++)
00426 {
00427 const cob_perception_msgs::Detection& det_in = face_position_msg_in->detections[i];
00428 cv::Rect face;
00429 face.x = det_in.mask.roi.x;
00430 face.y = det_in.mask.roi.y;
00431 face.width = det_in.mask.roi.width;
00432 face.height = det_in.mask.roi.height;
00433
00434
00435 int numberBlackPixels = 0;
00436 for (int v = face.y; v < face.y + face.height; v++)
00437 {
00438 uchar* data = people_segmentation_image.ptr(v);
00439 for (int u = face.x; u < face.x + face.width; u++)
00440 {
00441 int index = 3 * u;
00442 if (data[index] == 0 && data[index + 1] == 0 && data[index + 2] == 0)
00443 numberBlackPixels++;
00444 }
00445 }
00446 int faceArea = face.height * face.width;
00447 double segmentedPeopleRatio = (double)(faceArea - numberBlackPixels) / (double)faceArea;
00448
00449
00450 if ((det_in.detector == "face" && segmentedPeopleRatio < min_segmented_people_ratio_face_) || (det_in.detector == "head" && segmentedPeopleRatio
00451 < min_segmented_people_ratio_head_))
00452 {
00453
00454 if (debug_)
00455 std::cout << "False detection\n";
00456 }
00457 else
00458 {
00459
00460 face_detection_indices.push_back(i);
00461 }
00462 }
00463 if (debug_)
00464 std::cout << "Verification with people segmentation done.\n";
00465 }
00466 else
00467 {
00468 for (unsigned int i = 0; i < face_position_msg_in->detections.size(); i++)
00469 face_detection_indices.push_back(i);
00470 }
00471
00472
00473 std::vector<bool> current_detection_has_matching(face_detection_indices.size(), false);
00474
00475 if (false)
00476 {
00477
00478 std::map<int, std::map<int, double> > distance_matrix;
00479 std::map<int, std::map<int, double> >::iterator distance_matrix_it;
00480 for (unsigned int previous_det = 0; previous_det < face_position_accumulator_.size(); previous_det++)
00481 {
00482 std::map<int, double> distance_row;
00483 for (unsigned int i = 0; i < face_detection_indices.size(); i++)
00484 distance_row[face_detection_indices[i]] = computeFacePositionDistanceTrackingRange(face_position_accumulator_[previous_det],
00485 face_position_msg_in->detections[face_detection_indices[i]]);
00486 distance_matrix[previous_det] = distance_row;
00487 }
00488 if (debug_)
00489 std::cout << "Distance matrix.\n";
00490
00491
00492 unsigned int number_matchings = (face_position_accumulator_.size() < face_detection_indices.size()) ? face_position_accumulator_.size() : face_detection_indices.size();
00493 for (unsigned int m = 0; m < number_matchings; m++)
00494 {
00495
00496 double min_dist = DBL_MAX;
00497 int previous_min_index, current_min_index;
00498 for (distance_matrix_it = distance_matrix.begin(); distance_matrix_it != distance_matrix.end(); distance_matrix_it++)
00499 {
00500 for (std::map<int, double>::iterator distance_row_it = distance_matrix_it->second.begin(); distance_row_it != distance_matrix_it->second.end(); distance_row_it++)
00501 {
00502 if (distance_row_it->second < min_dist)
00503 {
00504 min_dist = distance_row_it->second;
00505 previous_min_index = distance_matrix_it->first;
00506 current_min_index = distance_row_it->first;
00507 }
00508 }
00509 }
00510
00511
00512
00513
00514
00515 if (min_dist == DBL_MAX)
00516 break;
00517
00518
00519 copyDetection(face_position_msg_in->detections[current_min_index], face_position_accumulator_[previous_min_index], true, previous_min_index);
00520
00521 for (unsigned int i = 0; i < face_detection_indices.size(); i++)
00522 if (face_detection_indices[i] == current_min_index)
00523 current_detection_has_matching[i] = true;
00524
00525
00526 distance_matrix.erase(previous_min_index);
00527 for (distance_matrix_it = distance_matrix.begin(); distance_matrix_it != distance_matrix.end(); distance_matrix_it++)
00528 distance_matrix_it->second.erase(current_min_index);
00529 }
00530 }
00531
00532 else
00533 {
00534
00535 std::vector < std::vector<int> > costs_matrix(face_position_accumulator_.size(), std::vector<int>(face_detection_indices.size(), 0));
00536 if (debug_)
00537 std::cout << "Costs matrix.\n";
00538 for (unsigned int previous_det = 0; previous_det < face_position_accumulator_.size(); previous_det++)
00539 {
00540 for (unsigned int i = 0; i < face_detection_indices.size(); i++)
00541 {
00542 costs_matrix[previous_det][i] = 100 * computeFacePositionDistance(face_position_accumulator_[previous_det],
00543 face_position_msg_in->detections[face_detection_indices[i]]) + 100 * tracking_range_m_
00544 * (face_position_msg_in->detections[face_detection_indices[i]].label.compare(face_position_accumulator_[previous_det].label) == 0 ? 0 : 1);
00545 if (debug_)
00546 std::cout << costs_matrix[previous_det][i] << "\t";
00547 }
00548 if (debug_)
00549 std::cout << std::endl;
00550 }
00551
00552 if (face_position_accumulator_.size() != 0 && face_detection_indices.size() != 0)
00553 {
00554
00555 munkres assignmentProblem;
00556 assignmentProblem.set_diag(false);
00557 assignmentProblem.load_weights(costs_matrix);
00558 int num_rows = std::min(costs_matrix.size(), costs_matrix[0].size());
00559
00560 ordered_pair *optimalAssignment = new ordered_pair[num_rows];
00561 assignmentProblem.assign(optimalAssignment);
00562 if (debug_)
00563 std::cout << "Assignment problem solved.\n";
00564
00565
00566 for (int i = 0; i < num_rows; i++)
00567 {
00568 int current_match_index = 0, previous_match_index = 0;
00569 if (face_position_accumulator_.size() < face_detection_indices.size())
00570 {
00571
00572 previous_match_index = optimalAssignment[i].row;
00573 current_match_index = optimalAssignment[i].col;
00574 }
00575 else
00576 {
00577
00578 previous_match_index = optimalAssignment[i].col;
00579 current_match_index = optimalAssignment[i].row;
00580 }
00581
00582
00583 copyDetection(face_position_msg_in->detections[current_match_index], face_position_accumulator_[previous_match_index], true, previous_match_index);
00584
00585 for (unsigned int i = 0; i < face_detection_indices.size(); i++)
00586 if (face_detection_indices[i] == current_match_index)
00587 current_detection_has_matching[i] = true;
00588 }
00589
00590 delete optimalAssignment;
00591 }
00592 }
00593 if (debug_)
00594 std::cout << "Matches found.\n";
00595
00596
00597 for (unsigned int i = 0; i < face_detection_indices.size(); i++)
00598 {
00599 if (current_detection_has_matching[i] == false)
00600 {
00601 const cob_perception_msgs::Detection& det_in = face_position_msg_in->detections[face_detection_indices[i]];
00602 if (det_in.detector == "face")
00603 {
00604
00605 if (debug_)
00606 std::cout << "\n***** New detection *****\n\n";
00607 cob_perception_msgs::Detection det_out;
00608 copyDetection(det_in, det_out, false);
00609 det_out.pose.header.frame_id = "head_cam3d_link";
00610 face_position_accumulator_.push_back(det_out);
00611
00612 std::map<std::string, double> new_identification_data;
00613
00614 new_identification_data["UnknownHead"] = 0.0;
00615 new_identification_data[det_in.label] = 1.0;
00616 face_identification_votes_.push_back(new_identification_data);
00617 }
00618 }
00619 }
00620 if (debug_)
00621 std::cout << "New detections.\n";
00622
00623
00624 removeMultipleInstancesOfLabel();
00625
00626
00627 ros::Time image_recording_time = (face_position_msg_in->detections.size() > 0 ? face_position_msg_in->detections[0].header.stamp : ros::Time::now());
00628 cob_perception_msgs::DetectionArray face_position_msg_out;
00629 prepareFacePositionMessage(face_position_msg_out, image_recording_time);
00630 face_position_msg_out.header.stamp = face_position_msg_in->header.stamp;
00631 face_position_publisher_.publish(face_position_msg_out);
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671 if (display_timing_ == true)
00672 ROS_INFO("%d DetectionTracker: Time stamp of pointcloud message: %f. Delay: %f.", face_position_msg_in->header.seq, face_position_msg_in->header.stamp.toSec(), ros::Time::now().toSec()-face_position_msg_in->header.stamp.toSec());
00673
00674 }
00675
00676
00677
00678 int main(int argc, char** argv)
00679 {
00680
00681 ros::init(argc, argv, "detection_tracker");
00682
00683
00684 ros::NodeHandle nh;
00685
00686
00687 DetectionTrackerNode detection_tracker_node(nh);
00688
00689
00690
00691
00692
00693
00694 ros::spin();
00695
00696 return 0;
00697 }