$search
00001 /**************************************************************** 00002 * 00003 * Copyright (c) 2010 00004 * 00005 * Fraunhofer Institute for Manufacturing Engineering 00006 * and Automation (IPA) 00007 * 00008 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 00009 * 00010 * Project name: care-o-bot 00011 * ROS stack name: cob_vision 00012 * ROS package name: cob_people_detection 00013 * Description: Takes the positions of detected or recognized faces and 00014 * a people segmentation of the environment as input and outputs people 00015 * positions. 00016 * 00017 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 00018 * 00019 * Author: Jan Fischer, email:jan.fischer@ipa.fhg.de 00020 * Author: Richard Bormann, email: richard.bormann@ipa.fhg.de 00021 * Supervised by: 00022 * 00023 * Date of creation: 03/2011 00024 * ToDo: 00025 * 00026 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 00027 * 00028 * Redistribution and use in source and binary forms, with or without 00029 * modification, are permitted provided that the following conditions are met: 00030 * 00031 * * Redistributions of source code must retain the above copyright 00032 * notice, this list of conditions and the following disclaimer. 00033 * * Redistributions in binary form must reproduce the above copyright 00034 * notice, this list of conditions and the following disclaimer in the 00035 * documentation and/or other materials provided with the distribution. 00036 * * Neither the name of the Fraunhofer Institute for Manufacturing 00037 * Engineering and Automation (IPA) nor the names of its 00038 * contributors may be used to endorse or promote products derived from 00039 * this software without specific prior written permission. 00040 * 00041 * This program is free software: you can redistribute it and/or modify 00042 * it under the terms of the GNU Lesser General Public License LGPL as 00043 * published by the Free Software Foundation, either version 3 of the 00044 * License, or (at your option) any later version. 00045 * 00046 * This program is distributed in the hope that it will be useful, 00047 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00048 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00049 * GNU Lesser General Public License LGPL for more details. 00050 * 00051 * You should have received a copy of the GNU Lesser General Public 00052 * License LGPL along with this program. 00053 * If not, see <http://www.gnu.org/licenses/>. 00054 * 00055 ****************************************************************/ 00056 00057 #ifndef _PEOPLE_DETECTION_ 00058 #define _PEOPLE_DETECTION_ 00059 00060 00061 //################## 00062 //#### includes #### 00063 00064 // standard includes 00065 //-- 00066 00067 // ROS includes 00068 #include <ros/ros.h> 00069 #include <nodelet/nodelet.h> 00070 #include <ros/package.h> 00071 00072 // ROS message includes 00073 #include <sensor_msgs/Image.h> 00074 #include <sensor_msgs/PointCloud2.h> 00075 #include <cob_people_detection_msgs/PeopleDetectionArray.h> 00076 00077 // services 00078 #include <cob_people_detection/DetectPeople.h> 00079 00080 // topics 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 // opencv 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 // point cloud 00094 #include <pcl/point_types.h> 00095 #include <pcl_ros/point_cloud.h> 00096 00097 // boost 00098 #include <boost/bind.hpp> 00099 #include <boost/thread/mutex.hpp> 00100 00101 // external includes 00102 #include "cob_vision_utils/GlobalDefines.h" 00103 00104 00105 #include <sstream> 00106 #include <string> 00107 #include <vector> 00108 00109 #include <pluginlib/class_list_macros.h> 00110 00111 namespace ipa_PeopleDetector { 00112 00113 00114 //#################### 00115 //#### node class #### 00116 class CobPeopleDetectionNodelet : public nodelet::Nodelet 00117 { 00118 protected: 00119 //message_filters::Subscriber<sensor_msgs::PointCloud2> shared_image_sub_; ///< Shared xyz image and color image topic 00120 image_transport::ImageTransport* it_; 00121 image_transport::SubscriberFilter people_segmentation_image_sub_; 00122 image_transport::SubscriberFilter color_image_sub_; 00123 message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_people_detection_msgs::PeopleDetectionArray, sensor_msgs::Image> >* sync_input_2_; 00124 message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_people_detection_msgs::PeopleDetectionArray, sensor_msgs::Image, sensor_msgs::Image> >* sync_input_3_; 00125 message_filters::Subscriber<cob_people_detection_msgs::PeopleDetectionArray> face_position_subscriber_; 00126 ros::Publisher face_position_publisher_; 00127 image_transport::Publisher people_detection_image_pub_; 00128 ros::ServiceServer service_server_detect_people_; 00129 00130 00131 ros::NodeHandle node_handle_; 00132 00133 std::vector<cob_people_detection_msgs::PeopleDetection> face_position_accumulator_; 00134 boost::timed_mutex face_position_accumulator_mutex_; 00135 std::vector<std::map<std::string, double> > face_identification_votes_; 00136 00137 // parameters 00138 bool display_; 00139 bool use_people_segmentation_; 00140 double face_redetection_time_; 00141 double min_segmented_people_ratio_color_; 00142 double min_segmented_people_ratio_range_; 00143 double tracking_range_m_; 00144 double face_identification_score_decay_rate_; 00145 double min_face_identification_score_to_publish_; 00146 bool fall_back_to_unknown_identification_; 00147 00148 public: 00149 00150 CobPeopleDetectionNodelet() 00151 { 00152 it_ = 0; 00153 sync_input_2_ = 0; 00154 sync_input_3_ = 0; 00155 } 00156 00157 ~CobPeopleDetectionNodelet() 00158 { 00159 if (it_ != 0) delete it_; 00160 if (sync_input_2_ != 0) delete sync_input_2_; 00161 if (sync_input_3_ != 0) delete sync_input_3_; 00162 } 00163 00165 void onInit() 00166 { 00167 node_handle_ = getNodeHandle(); 00168 00169 // parameters 00170 std::cout << "\n---------------------------\nPeople Detection Parameters:\n---------------------------\n"; 00171 node_handle_.param("display", display_, true); 00172 std::cout << "display = " << display_ << "\n"; 00173 node_handle_.param("face_redetection_time", face_redetection_time_, 2.0); 00174 std::cout << "face_redetection_time = " << face_redetection_time_ << "\n"; 00175 node_handle_.param("min_segmented_people_ratio_color", min_segmented_people_ratio_color_, 0.7); 00176 std::cout << "min_segmented_people_ratio_color = " << min_segmented_people_ratio_color_ << "\n"; 00177 node_handle_.param("min_segmented_people_ratio_range", min_segmented_people_ratio_range_, 0.2); 00178 std::cout << "min_segmented_people_ratio_range = " << min_segmented_people_ratio_range_ << "\n"; 00179 node_handle_.param("use_people_segmentation", use_people_segmentation_, true); 00180 std::cout << "use_people_segmentation = " << use_people_segmentation_ << "\n"; 00181 node_handle_.param("tracking_range_m", tracking_range_m_, 0.3); 00182 std::cout << "tracking_range_m = " << tracking_range_m_ << "\n"; 00183 node_handle_.param("face_identification_score_decay_rate", face_identification_score_decay_rate_, 0.9); 00184 std::cout << "face_identification_score_decay_rate = " << face_identification_score_decay_rate_ << "\n"; 00185 node_handle_.param("min_face_identification_score_to_publish", min_face_identification_score_to_publish_, 0.9); 00186 std::cout << "min_face_identification_score_to_publish = " << min_face_identification_score_to_publish_ << "\n"; 00187 node_handle_.param("fall_back_to_unknown_identification", fall_back_to_unknown_identification_, true); 00188 std::cout << "fall_back_to_unknown_identification = " << fall_back_to_unknown_identification_ << "\n"; 00189 00190 // subscribers 00191 it_ = new image_transport::ImageTransport(node_handle_); 00192 people_segmentation_image_sub_.subscribe(*it_, "people_segmentation_image", 1); 00193 if (display_==true) color_image_sub_.subscribe(*it_, "colorimage", 1); 00194 face_position_subscriber_.subscribe(node_handle_, "face_position_array_in", 1); 00195 00196 // input synchronization 00197 sensor_msgs::Image::ConstPtr nullPtr; 00198 if (use_people_segmentation_ == true) 00199 { 00200 if (display_ == false) 00201 { 00202 sync_input_2_ = new message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_people_detection_msgs::PeopleDetectionArray, sensor_msgs::Image> >(2); 00203 sync_input_2_->connectInput(face_position_subscriber_, people_segmentation_image_sub_); 00204 sync_input_2_->registerCallback(boost::bind(&CobPeopleDetectionNodelet::inputCallback, this, _1, _2, nullPtr)); 00205 } 00206 else 00207 { 00208 sync_input_3_ = new message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_people_detection_msgs::PeopleDetectionArray, sensor_msgs::Image, sensor_msgs::Image> >(3); 00209 sync_input_3_->connectInput(face_position_subscriber_, people_segmentation_image_sub_, color_image_sub_); 00210 sync_input_3_->registerCallback(boost::bind(&CobPeopleDetectionNodelet::inputCallback, this, _1, _2, _3)); 00211 } 00212 } 00213 else 00214 { 00215 if (display_ == true) 00216 { 00217 sync_input_2_ = new message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_people_detection_msgs::PeopleDetectionArray, sensor_msgs::Image> >(2); 00218 sync_input_2_->connectInput(face_position_subscriber_, color_image_sub_); 00219 sync_input_2_->registerCallback(boost::bind(&CobPeopleDetectionNodelet::inputCallback, this, _1, nullPtr, _2)); 00220 } 00221 else 00222 { 00223 face_position_subscriber_.registerCallback(boost::bind(&CobPeopleDetectionNodelet::inputCallback, this, _1, nullPtr, nullPtr)); 00224 } 00225 } 00226 00227 // services 00228 service_server_detect_people_ = node_handle_.advertiseService("detect_people", &CobPeopleDetectionNodelet::detectPeopleCallback, this); 00229 00230 // publishers 00231 face_position_publisher_ = node_handle_.advertise<cob_people_detection_msgs::PeopleDetectionArray>("face_position_array", 1); 00232 people_detection_image_pub_ = it_->advertise("people_detection_image", 1); 00233 00234 std::cout << "CobPeopleDetectionNodelet initialized.\n"; 00235 00236 //ros::spin(); not necessary with nodelets 00237 } 00238 00239 00241 unsigned long convertColorImageMessageToMat(const sensor_msgs::Image::ConstPtr& image_msg, cv_bridge::CvImageConstPtr& image_ptr, cv::Mat& image) 00242 { 00243 try 00244 { 00245 image_ptr = cv_bridge::toCvShare(image_msg, sensor_msgs::image_encodings::BGR8); 00246 } 00247 catch (cv_bridge::Exception& e) 00248 { 00249 ROS_ERROR("PeopleDetection: cv_bridge exception: %s", e.what()); 00250 return ipa_Utils::RET_FAILED; 00251 } 00252 image = image_ptr->image; 00253 00254 return ipa_Utils::RET_OK; 00255 } 00256 00257 00264 unsigned long copyDetection(const cob_people_detection_msgs::PeopleDetection& src, cob_people_detection_msgs::PeopleDetection& dest, bool update=false, unsigned int updateIndex=UINT_MAX) 00265 { 00266 // 2D image coordinates 00267 dest.mask.roi.x = src.mask.roi.x; dest.mask.roi.y = src.mask.roi.y; 00268 dest.mask.roi.width = src.mask.roi.width; dest.mask.roi.height = src.mask.roi.height; 00269 00270 // 3D world coordinates 00271 const geometry_msgs::Point* pointIn = &(src.pose.pose.position); 00272 geometry_msgs::Point* pointOut = &(dest.pose.pose.position); 00273 pointOut->x = pointIn->x; pointOut->y = pointIn->y; pointOut->z = pointIn->z; 00274 00275 // person ID 00276 if (update==true) 00277 { 00278 // update label history 00279 // if (src.label!="No face") 00280 // { 00281 if (face_identification_votes_[updateIndex].find(src.label) == face_identification_votes_[updateIndex].end()) 00282 face_identification_votes_[updateIndex][src.label] = 1.0; 00283 else 00284 face_identification_votes_[updateIndex][src.label] += 1.0; 00285 // } 00286 00287 // apply voting decay with time and find most voted label 00288 double max_score = 0; 00289 dest.label = src.label; 00290 for (std::map<std::string, double>::iterator face_identification_votes_it=face_identification_votes_[updateIndex].begin(); face_identification_votes_it!=face_identification_votes_[updateIndex].end(); face_identification_votes_it++) 00291 { 00292 face_identification_votes_it->second *= face_identification_score_decay_rate_; 00293 std::string label = face_identification_votes_it->first; 00294 if (((label!="Unknown" && fall_back_to_unknown_identification_==false) || fall_back_to_unknown_identification_==true) 00295 && label!="UnknownRange" /*&& label!="No face"*/ && face_identification_votes_it->second > max_score) 00296 { 00297 max_score = face_identification_votes_it->second; 00298 dest.label = label; 00299 } 00300 } 00301 00302 // if the score for the assigned label is higher than the score for UnknownRange increase the score for UnknownRange to the label's score (allows smooth transition if only the range detection is available after recognition) 00303 if (face_identification_votes_[updateIndex][dest.label] > face_identification_votes_[updateIndex]["UnknownRange"]) 00304 face_identification_votes_[updateIndex]["UnknownRange"] = face_identification_votes_[updateIndex][dest.label]; 00305 if (fall_back_to_unknown_identification_==false) 00306 { 00307 if (face_identification_votes_[updateIndex]["Unknown"] > face_identification_votes_[updateIndex]["UnknownRange"]) 00308 face_identification_votes_[updateIndex]["UnknownRange"] = face_identification_votes_[updateIndex]["Unknown"]; 00309 } 00310 } 00311 else dest.label = src.label; 00312 00313 if (dest.label=="UnknownRange") dest.label = "Unknown"; 00314 00315 // time stamp, detector (color or range) 00316 // if (update==true) 00317 // { 00318 // if (src.detector=="color") dest.detector = "color"; 00319 // } 00320 // else dest.detector = src.detector; 00321 dest.detector = src.detector; 00322 00323 dest.header.stamp = ros::Time::now(); 00324 00325 return ipa_Utils::RET_OK; 00326 } 00327 00328 inline double abs(double x) { return ((x<0) ? -x : x); } 00329 00330 00334 double computeFacePositionDistance(const cob_people_detection_msgs::PeopleDetection& previous_detection, const cob_people_detection_msgs::PeopleDetection& current_detection) 00335 { 00336 const geometry_msgs::Point* point_1 = &(previous_detection.pose.pose.position); 00337 const geometry_msgs::Point* point_2 = &(current_detection.pose.pose.position); 00338 00339 double dx = abs(point_1->x - point_2->x); 00340 double dy = abs(point_1->y - point_2->y); 00341 double dz = abs(point_1->z - point_2->z); 00342 00343 // return a huge distance if the current face position is too far away from the recent 00344 if (dx>tracking_range_m_ || dy>tracking_range_m_ || dz>tracking_range_m_) 00345 { 00346 // new face position is too distant to recent position 00347 return DBL_MAX; 00348 } 00349 00350 // return Euclidian distance if both faces are sufficiently close 00351 double dist = dx*dx+dy*dy+dz*dz; 00352 return dist; 00353 } 00354 00355 00358 unsigned long removeMultipleInstancesOfLabel() 00359 { 00360 // check this for each recognized face 00361 for (int i=0; i<(int)face_position_accumulator_.size(); i++) 00362 { 00363 // label of this detection 00364 std::string label = face_position_accumulator_[i].label; 00365 00366 // check whether this label has multiple occurrences if it is a real name 00367 if (label!="Unknown" && label!="No face") 00368 { 00369 for (int j=0; j<(int)face_position_accumulator_.size(); j++) 00370 { 00371 if (j==i) continue; // do not check yourself 00372 00373 if (face_position_accumulator_[j].label == label) 00374 { 00375 if (display_) std::cout << "face_identification_votes_[i][" << label << "] = " << face_identification_votes_[i][label] << " face_identification_votes_[j][" << label << "] = " << face_identification_votes_[j][label] << "\n"; 00376 00377 // correct this label to Unknown when some other instance has a higher score on this label 00378 if (face_identification_votes_[i][label] < face_identification_votes_[j][label]) 00379 { 00380 face_position_accumulator_[i].label = "Unknown"; 00381 // copy score to unknown if it is higher (this enables the display if either the unknown score or label's recognition score were high enough) 00382 if (face_identification_votes_[i][label] > face_identification_votes_[i]["Unknown"]) 00383 face_identification_votes_[i]["Unknown"] = face_identification_votes_[i][label]; 00384 } 00385 } 00386 } 00387 } 00388 } 00389 00390 return ipa_Utils::RET_OK; 00391 } 00392 00393 00394 unsigned long prepareFacePositionMessage(cob_people_detection_msgs::PeopleDetectionArray& face_position_msg_out) 00395 { 00396 // publish face positions 00397 std::vector<cob_people_detection_msgs::PeopleDetection> faces_to_publish; 00398 for (int i=0; i<(int)face_position_accumulator_.size(); i++) 00399 { 00400 if (display_) std::cout << "'UnknownRange' score: " << face_identification_votes_[i]["UnknownRange"] << " label '" << face_position_accumulator_[i].label << "' score: " << face_identification_votes_[i][face_position_accumulator_[i].label] << " - "; 00401 if (face_identification_votes_[i][face_position_accumulator_[i].label]>min_face_identification_score_to_publish_ || face_identification_votes_[i]["UnknownRange"]>min_face_identification_score_to_publish_) 00402 { 00403 faces_to_publish.push_back(face_position_accumulator_[i]); 00404 if (display_) std::cout << "published\n"; 00405 } 00406 else if (display_) std::cout << "not published\n"; 00407 } 00408 face_position_msg_out.detections = faces_to_publish; 00409 // hack: for WimiCare replace 'Unknown' by '0000' 00410 for (int i=0; i<(int)face_position_msg_out.detections.size(); i++) 00411 { 00412 if (face_position_msg_out.detections[i].label=="Unknown") 00413 face_position_msg_out.detections[i].label = "0000"; 00414 } 00415 face_position_msg_out.header.stamp = ros::Time::now(); 00416 00417 return ipa_Utils::RET_OK; 00418 } 00419 00420 00422 void inputCallback(const cob_people_detection_msgs::PeopleDetectionArray::ConstPtr& face_position_msg_in, const sensor_msgs::Image::ConstPtr& people_segmentation_image_msg, const sensor_msgs::Image::ConstPtr& color_image_msg) 00423 { 00424 // convert segmentation image to cv::Mat 00425 cv_bridge::CvImageConstPtr people_segmentation_image_ptr; 00426 cv::Mat people_segmentation_image; 00427 if (use_people_segmentation_ == true) convertColorImageMessageToMat(people_segmentation_image_msg, people_segmentation_image_ptr, people_segmentation_image); 00428 00429 if (display_) std::cout << "detections: " << face_position_msg_in->detections.size() << "\n"; 00430 00431 // source image size 00432 std::stringstream ss; 00433 ss << face_position_msg_in->header.frame_id; 00434 int width, height; 00435 ss >> width; 00436 ss >> height; 00437 00438 // delete old face positions in list 00439 ros::Duration timeSpan(face_redetection_time_); 00440 for (int i=0; i<(int)face_position_accumulator_.size(); i++) 00441 { 00442 if ((ros::Time::now()-face_position_accumulator_[i].header.stamp) > timeSpan) 00443 { 00444 face_position_accumulator_.erase(face_position_accumulator_.begin()+i); 00445 face_identification_votes_.erase(face_identification_votes_.begin()+i); 00446 } 00447 } 00448 if (display_) std::cout << "Old face positions deleted.\n"; 00449 00450 // secure this section with a mutex 00451 boost::timed_mutex::scoped_timed_lock lock(face_position_accumulator_mutex_, boost::posix_time::milliseconds(2000)); 00452 if (lock.owns_lock() == false) 00453 { 00454 ROS_ERROR("cob_people_detection::CobPeopleDetectionNodelet: Mutex was not freed during response time."); 00455 return; 00456 } 00457 if (display_) std::cout << "Got mutex.\n"; 00458 00459 // verify face detections with people segmentation if enabled -> only accept detected faces if a person is segmented at that position 00460 std::vector<int> face_detection_indices; // index set for face_position_msg_in: contains those indices of detected faces which are supported by a person segmentation at the same location 00461 if (use_people_segmentation_ == true) 00462 { 00463 for(int i=0; i<(int)face_position_msg_in->detections.size(); i++) 00464 { 00465 const cob_people_detection_msgs::PeopleDetection* const det_in = &(face_position_msg_in->detections[i]); 00466 cv::Rect face; 00467 face.x = det_in->mask.roi.x; 00468 face.y = det_in->mask.roi.y; 00469 face.width = det_in->mask.roi.width; 00470 face.height = det_in->mask.roi.height; 00471 00472 int numberBlackPixels = 0; 00473 //std::cout << "face: " << face.x << " " << face.y << " " << face.width << " " << face.height << "\n"; 00474 for (int v=face.y; v<face.y+face.height; v++) 00475 { 00476 uchar* data = people_segmentation_image.ptr(v); 00477 for (int u=face.x; u<face.x+face.width; u++) 00478 { 00479 int index = 3*u; 00480 if (data[index]==0 && data[index+1]==0 && data[index+2]==0) numberBlackPixels++; 00481 } 00482 } 00483 int faceArea = face.height * face.width; 00484 double segmentedPeopleRatio = (double)(faceArea-numberBlackPixels)/(double)faceArea; 00485 00486 // if (display_) std::cout << "ratio: " << segmentedPeopleRatio << "\n"; 00487 if ((det_in->detector=="color" && segmentedPeopleRatio < min_segmented_people_ratio_color_) || (det_in->detector=="range" && segmentedPeopleRatio < min_segmented_people_ratio_range_)) 00488 { 00489 // False detection 00490 if (display_) std::cout << "False detection\n"; 00491 } 00492 else 00493 { 00494 // Push index of this detection into the list 00495 face_detection_indices.push_back(i); 00496 } 00497 } 00498 if (display_) std::cout << "Verification with people segmentation done.\n"; 00499 } 00500 else 00501 { 00502 for (unsigned int i=0; i<face_position_msg_in->detections.size(); i++) 00503 face_detection_indices.push_back(i); 00504 } 00505 // match current detections with previous detections 00506 // build distance matrix 00507 std::map<int, std::map<int, double> > distance_matrix; // 1. index = face_position_accumulator_ index of previous detections, 2. index = index of current detections, content = spatial distance between the indexed faces 00508 std::map<int, std::map<int, double> >::iterator distance_matrix_it; 00509 for (unsigned int previous_det=0; previous_det<face_position_accumulator_.size(); previous_det++) 00510 { 00511 std::map<int, double> distance_row; 00512 for (unsigned int i=0; i<face_detection_indices.size(); i++) 00513 distance_row[face_detection_indices[i]] = computeFacePositionDistance(face_position_accumulator_[previous_det], face_position_msg_in->detections[face_detection_indices[i]]); 00514 distance_matrix[previous_det] = distance_row; 00515 } 00516 if (display_) std::cout << "Distance matrix.\n"; 00517 00518 // find matching faces between previous and current detections 00519 unsigned int number_matchings = (face_position_accumulator_.size() < face_detection_indices.size()) ? face_position_accumulator_.size() : face_detection_indices.size(); 00520 std::vector<bool> current_detection_has_matching(face_detection_indices.size(), false); // index set for face_detection_indices: contains the indices of face_detection_indices and whether these faces could be matched to previously found faces 00521 for (unsigned int m=0; m<number_matchings; m++) 00522 { 00523 // find minimum matching distance between any two elements of the distance_matrix 00524 double min_dist = DBL_MAX; 00525 int previous_min_index, current_min_index; 00526 for (distance_matrix_it=distance_matrix.begin(); distance_matrix_it!=distance_matrix.end(); distance_matrix_it++) 00527 { 00528 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++) 00529 { 00530 if (distance_row_it->second < min_dist) 00531 { 00532 min_dist = distance_row_it->second; 00533 previous_min_index = distance_matrix_it->first; 00534 current_min_index = distance_row_it->first; 00535 } 00536 } 00537 } 00538 00539 // if there is no matching pair of detections interrupt the search for matchings at this point 00540 if (min_dist == DBL_MAX) break; 00541 00542 // instantiate the matching 00543 copyDetection(face_position_msg_in->detections[current_min_index], face_position_accumulator_[previous_min_index], true, previous_min_index); 00544 // mark the respective entry in face_detection_indices as labeled 00545 for (unsigned int i=0; i<face_detection_indices.size(); i++) 00546 if (face_detection_indices[i] == current_min_index) 00547 current_detection_has_matching[i] = true; 00548 00549 // delete the row and column of the found matching so that both detections cannot be involved in any further matching again 00550 distance_matrix.erase(previous_min_index); 00551 for (distance_matrix_it=distance_matrix.begin(); distance_matrix_it!=distance_matrix.end(); distance_matrix_it++) 00552 distance_matrix_it->second.erase(current_min_index); 00553 } 00554 if (display_) std::cout << "Matches found.\n"; 00555 00556 // create new detections for the unmatched of the current detections if they originate from the color image 00557 for (unsigned int i=0; i<face_detection_indices.size(); i++) 00558 { 00559 if (current_detection_has_matching[i] == false) 00560 { 00561 const cob_people_detection_msgs::PeopleDetection* const det_in = &(face_position_msg_in->detections[face_detection_indices[i]]); 00562 if (det_in->detector=="color") 00563 { 00564 // save in accumulator 00565 if (display_) std::cout << "\n***** New detection *****\n\n"; 00566 cob_people_detection_msgs::PeopleDetection det_out; 00567 copyDetection(*det_in, det_out, false); 00568 det_out.pose.header.frame_id = "head_cam3d_link"; 00569 face_position_accumulator_.push_back(det_out); 00570 // remember label history 00571 std::map<std::string, double> new_identification_data; 00572 //new_identification_data["Unknown"] = 0.0; 00573 new_identification_data["UnknownRange"] = 0.0; 00574 new_identification_data[det_in->label] = 1.0; 00575 face_identification_votes_.push_back(new_identification_data); 00576 } 00577 } 00578 } 00579 if (display_) std::cout << "New detections.\n"; 00580 00581 // eliminate multiple instances of a label 00582 removeMultipleInstancesOfLabel(); 00583 00584 // publish face positions 00585 cob_people_detection_msgs::PeopleDetectionArray face_position_msg_out; 00586 /* std::vector<cob_people_detection_msgs::PeopleDetection> faces_to_publish; 00587 for (int i=0; i<(int)face_position_accumulator_.size(); i++) 00588 { 00589 if (display_) std::cout << "'UnknownRange' score: " << face_identification_votes_[i]["UnknownRange"] << " label '" << face_position_accumulator_[i].label << "' score: " << face_identification_votes_[i][face_position_accumulator_[i].label] << " - "; 00590 if (face_identification_votes_[i][face_position_accumulator_[i].label]>min_face_identification_score_to_publish_ || face_identification_votes_[i]["UnknownRange"]>min_face_identification_score_to_publish_) 00591 { 00592 faces_to_publish.push_back(face_position_accumulator_[i]); 00593 if (display_) std::cout << "published\n"; 00594 } 00595 else if (display_) std::cout << "not published\n"; 00596 } 00597 face_position_msg_out.detections = faces_to_publish; 00598 // hack: for WimiCare replace 'Unknown' by '0000' 00599 for (int i=0; i<(int)face_position_msg_out.detections.size(); i++) 00600 { 00601 if (face_position_msg_out.detections[i].label=="Unknown") 00602 face_position_msg_out.detections[i].label = "0000"; 00603 } 00604 face_position_msg_out.header.stamp = ros::Time::now(); 00605 */ 00606 prepareFacePositionMessage(face_position_msg_out); 00607 face_position_publisher_.publish(face_position_msg_out); 00608 00609 // display 00610 if (display_ == true) 00611 { 00612 // convert image message to cv::Mat 00613 cv_bridge::CvImageConstPtr colorImagePtr; 00614 cv::Mat colorImage; 00615 convertColorImageMessageToMat(color_image_msg, colorImagePtr, colorImage); 00616 00617 // display color image 00618 for(int i=0; i<(int)face_position_msg_out.detections.size(); i++) 00619 { 00620 cv::Rect face; 00621 cob_people_detection_msgs::Rect& faceRect = face_position_msg_out.detections[i].mask.roi; 00622 face.x = faceRect.x; face.width = faceRect.width; 00623 face.y = faceRect.y; face.height = faceRect.height; 00624 00625 if (face_position_msg_out.detections[i].detector == "range") 00626 cv::rectangle(colorImage, cv::Point(face.x, face.y), cv::Point(face.x + face.width, face.y + face.height), CV_RGB(0, 0, 255), 2, 8, 0); 00627 else 00628 cv::rectangle(colorImage, cv::Point(face.x, face.y), cv::Point(face.x + face.width, face.y + face.height), CV_RGB(0, 255, 0), 2, 8, 0); 00629 00630 if (face_position_msg_out.detections[i].label == "Unknown") 00631 // Distance to face class is too high 00632 cv::putText(colorImage, "Unknown", cv::Point(face.x,face.y+face.height+25), cv::FONT_HERSHEY_PLAIN, 2, CV_RGB( 255, 0, 0 ), 2); 00633 else if (face_position_msg_out.detections[i].label == "No face") 00634 // Distance to face space is too high 00635 cv::putText(colorImage, "No face", cv::Point(face.x,face.y+face.height+25), cv::FONT_HERSHEY_PLAIN, 2, CV_RGB( 255, 0, 0 ), 2); 00636 else 00637 // Face classified 00638 cv::putText(colorImage, face_position_msg_out.detections[i].label.c_str(), cv::Point(face.x,face.y+face.height+25), cv::FONT_HERSHEY_PLAIN, 2, CV_RGB( 0, 255, 0 ), 2); 00639 } 00640 // publish image 00641 cv_bridge::CvImage cv_ptr; 00642 cv_ptr.image = colorImage; 00643 cv_ptr.encoding = "bgr8"; 00644 people_detection_image_pub_.publish(cv_ptr.toImageMsg()); 00645 } 00646 } 00647 00648 bool detectPeopleCallback(cob_people_detection::DetectPeople::Request &req, cob_people_detection::DetectPeople::Response &res) 00649 { 00650 // secure this section with a mutex 00651 boost::timed_mutex::scoped_timed_lock lock(face_position_accumulator_mutex_, boost::posix_time::milliseconds(2000)); 00652 if (lock.owns_lock() == false) 00653 { 00654 ROS_ERROR("cob_people_detection::CobPeopleDetectionNodelet: Mutex was not freed during response time."); 00655 return false; 00656 } 00657 00658 prepareFacePositionMessage(res.people_list); 00659 //res.people_list.detections = face_position_accumulator_; 00660 //res.people_list.header.stamp = ros::Time::now(); 00661 return true; 00662 } 00663 }; 00664 00665 }; 00666 00667 PLUGINLIB_DECLARE_CLASS(ipa_PeopleDetector, CobPeopleDetectionNodelet, ipa_PeopleDetector::CobPeopleDetectionNodelet, nodelet::Nodelet); 00668 00669 #endif // _PEOPLE_DETECTION_ 00670