people_detection.cpp
Go to the documentation of this file.
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 //#### includes ####
00062 
00063 // standard includes
00064 //--
00065 
00066 // ROS includes
00067 #include <ros/ros.h>
00068 #include <nodelet/nodelet.h>
00069 #include <ros/package.h>
00070 
00071 // ROS message includes
00072 #include <sensor_msgs/Image.h>
00073 #include <sensor_msgs/PointCloud2.h>
00074 #include <cob_perception_msgs/DetectionArray.h>
00075 
00076 // services
00077 #include <cob_people_detection/DetectPeople.h>
00078 
00079 // topics
00080 #include <message_filters/subscriber.h>
00081 #include <message_filters/synchronizer.h>
00082 #include <message_filters/sync_policies/approximate_time.h>
00083 #include <image_transport/image_transport.h>
00084 #include <image_transport/subscriber_filter.h>
00085 
00086 // opencv
00087 #include <opencv2/opencv.hpp>
00088 #include <cv_bridge/cv_bridge.h>
00089 #include <sensor_msgs/image_encodings.h>
00090 
00091 // point cloud
00092 #include <pcl/point_types.h>
00093 #include <pcl_ros/point_cloud.h>
00094 
00095 // boost
00096 #include <boost/bind.hpp>
00097 #include <boost/thread/mutex.hpp>
00098 
00099 // external includes
00100 #include "cob_vision_utils/GlobalDefines.h"
00101 
00102 #include <sstream>
00103 #include <string>
00104 #include <vector>
00105 
00106 #include <pluginlib/class_list_macros.h>
00107 
00108 namespace ipa_PeopleDetector
00109 {
00110 
00111 //####################
00112 //#### node class ####
00113 class CobPeopleDetectionNodelet: public nodelet::Nodelet
00114 {
00115 protected:
00116         //message_filters::Subscriber<sensor_msgs::PointCloud2> shared_image_sub_; ///< Shared xyz image and color image topic
00117         image_transport::ImageTransport* it_;
00118         image_transport::SubscriberFilter people_segmentation_image_sub_; 
00119         image_transport::SubscriberFilter color_image_sub_; 
00120         message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_perception_msgs::DetectionArray, sensor_msgs::Image> >* sync_input_2_;
00121         message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_perception_msgs::DetectionArray, sensor_msgs::Image, sensor_msgs::Image> >
00122                         * sync_input_3_;
00123         message_filters::Subscriber<cob_perception_msgs::DetectionArray> face_position_subscriber_; 
00124         ros::Publisher face_position_publisher_; 
00125         image_transport::Publisher people_detection_image_pub_; 
00126         ros::ServiceServer service_server_detect_people_; 
00127 
00128 
00129         ros::NodeHandle node_handle_; 
00130 
00131         std::vector<cob_perception_msgs::Detection> face_position_accumulator_; 
00132         boost::timed_mutex face_position_accumulator_mutex_; 
00133         std::vector<std::map<std::string, double> > face_identification_votes_; 
00134 
00135         // parameters
00136         bool display_; 
00137         bool use_people_segmentation_; 
00138         double face_redetection_time_; 
00139         double min_segmented_people_ratio_color_; 
00140         double min_segmented_people_ratio_range_; 
00141         double tracking_range_m_; 
00142         double face_identification_score_decay_rate_; 
00143         double min_face_identification_score_to_publish_; 
00144         bool fall_back_to_unknown_identification_; 
00145 
00146 public:
00147 
00148         CobPeopleDetectionNodelet()
00149         {
00150                 it_ = 0;
00151                 sync_input_2_ = 0;
00152                 sync_input_3_ = 0;
00153         }
00154 
00155         ~CobPeopleDetectionNodelet()
00156         {
00157                 if (it_ != 0)
00158                         delete it_;
00159                 if (sync_input_2_ != 0)
00160                         delete sync_input_2_;
00161                 if (sync_input_3_ != 0)
00162                         delete sync_input_3_;
00163         }
00164 
00166         void onInit()
00167         {
00168                 node_handle_ = getNodeHandle();
00169 
00170                 // parameters
00171                 std::cout << "\n---------------------------\nPeople Detection Parameters:\n---------------------------\n";
00172                 node_handle_.param("display", display_, true);
00173                 std::cout << "display = " << display_ << "\n";
00174                 node_handle_.param("face_redetection_time", face_redetection_time_, 2.0);
00175                 std::cout << "face_redetection_time = " << face_redetection_time_ << "\n";
00176                 node_handle_.param("min_segmented_people_ratio_color", min_segmented_people_ratio_color_, 0.7);
00177                 std::cout << "min_segmented_people_ratio_color = " << min_segmented_people_ratio_color_ << "\n";
00178                 node_handle_.param("min_segmented_people_ratio_range", min_segmented_people_ratio_range_, 0.2);
00179                 std::cout << "min_segmented_people_ratio_range = " << min_segmented_people_ratio_range_ << "\n";
00180                 node_handle_.param("use_people_segmentation", use_people_segmentation_, true);
00181                 std::cout << "use_people_segmentation = " << use_people_segmentation_ << "\n";
00182                 node_handle_.param("tracking_range_m", tracking_range_m_, 0.3);
00183                 std::cout << "tracking_range_m = " << tracking_range_m_ << "\n";
00184                 node_handle_.param("face_identification_score_decay_rate", face_identification_score_decay_rate_, 0.9);
00185                 std::cout << "face_identification_score_decay_rate = " << face_identification_score_decay_rate_ << "\n";
00186                 node_handle_.param("min_face_identification_score_to_publish", min_face_identification_score_to_publish_, 0.9);
00187                 std::cout << "min_face_identification_score_to_publish = " << min_face_identification_score_to_publish_ << "\n";
00188                 node_handle_.param("fall_back_to_unknown_identification", fall_back_to_unknown_identification_, true);
00189                 std::cout << "fall_back_to_unknown_identification = " << fall_back_to_unknown_identification_ << "\n";
00190 
00191                 // subscribers
00192                 it_ = new image_transport::ImageTransport(node_handle_);
00193                 people_segmentation_image_sub_.subscribe(*it_, "people_segmentation_image", 1);
00194                 if (display_ == true)
00195                         color_image_sub_.subscribe(*it_, "colorimage", 1);
00196                 face_position_subscriber_.subscribe(node_handle_, "face_position_array_in", 1);
00197 
00198                 // input synchronization
00199                 sensor_msgs::Image::ConstPtr nullPtr;
00200                 if (use_people_segmentation_ == true)
00201                 {
00202                         if (display_ == false)
00203                         {
00204                                 sync_input_2_
00205                                                 = new message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_perception_msgs::DetectionArray, sensor_msgs::Image> >(2);
00206                                 sync_input_2_->connectInput(face_position_subscriber_, people_segmentation_image_sub_);
00207                                 sync_input_2_->registerCallback(boost::bind(&CobPeopleDetectionNodelet::inputCallback, this, _1, _2, nullPtr));
00208                         }
00209                         else
00210                         {
00211                                 sync_input_3_ = new message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_perception_msgs::DetectionArray, sensor_msgs::Image,
00212                                                 sensor_msgs::Image> >(3);
00213                                 sync_input_3_->connectInput(face_position_subscriber_, people_segmentation_image_sub_, color_image_sub_);
00214                                 sync_input_3_->registerCallback(boost::bind(&CobPeopleDetectionNodelet::inputCallback, this, _1, _2, _3));
00215                         }
00216                 }
00217                 else
00218                 {
00219                         if (display_ == true)
00220                         {
00221                                 sync_input_2_
00222                                                 = new message_filters::Synchronizer<message_filters::sync_policies::ApproximateTime<cob_perception_msgs::DetectionArray, sensor_msgs::Image> >(2);
00223                                 sync_input_2_->connectInput(face_position_subscriber_, color_image_sub_);
00224                                 sync_input_2_->registerCallback(boost::bind(&CobPeopleDetectionNodelet::inputCallback, this, _1, nullPtr, _2));
00225                         }
00226                         else
00227                         {
00228                                 face_position_subscriber_.registerCallback(boost::bind(&CobPeopleDetectionNodelet::inputCallback, this, _1, nullPtr, nullPtr));
00229                         }
00230                 }
00231 
00232                 // services
00233                 service_server_detect_people_ = node_handle_.advertiseService("detect_people", &CobPeopleDetectionNodelet::detectPeopleCallback, this);
00234 
00235                 // publishers
00236                 face_position_publisher_ = node_handle_.advertise<cob_perception_msgs::DetectionArray>("face_position_array", 1);
00237                 people_detection_image_pub_ = it_->advertise("people_detection_image", 1);
00238 
00239                 std::cout << "CobPeopleDetectionNodelet initialized.\n";
00240 
00241                 //ros::spin(); not necessary with nodelets
00242         }
00243 
00245         unsigned long convertColorImageMessageToMat(const sensor_msgs::Image::ConstPtr& image_msg, cv_bridge::CvImageConstPtr& image_ptr, cv::Mat& image)
00246         {
00247                 try
00248                 {
00249                         image_ptr = cv_bridge::toCvShare(image_msg, sensor_msgs::image_encodings::BGR8);
00250                 } catch (cv_bridge::Exception& e)
00251                 {
00252                         ROS_ERROR("PeopleDetection: cv_bridge exception: %s", e.what());
00253                         return ipa_Utils::RET_FAILED;
00254                 }
00255                 image = image_ptr->image;
00256 
00257                 return ipa_Utils::RET_OK;
00258         }
00259 
00266         unsigned long copyDetection(const cob_perception_msgs::Detection& src, cob_perception_msgs::Detection& dest, bool update = false,
00267                         unsigned int updateIndex = UINT_MAX)
00268         {
00269                 // 2D image coordinates
00270                 dest.mask.roi.x = src.mask.roi.x;
00271                 dest.mask.roi.y = src.mask.roi.y;
00272                 dest.mask.roi.width = src.mask.roi.width;
00273                 dest.mask.roi.height = src.mask.roi.height;
00274 
00275                 // 3D world coordinates
00276                 const geometry_msgs::Point* pointIn = &(src.pose.pose.position);
00277                 geometry_msgs::Point* pointOut = &(dest.pose.pose.position);
00278                 pointOut->x = pointIn->x;
00279                 pointOut->y = pointIn->y;
00280                 pointOut->z = pointIn->z;
00281 
00282                 // person ID
00283                 if (update == true)
00284                 {
00285                         // update label history
00286                         // if (src.label!="No face")
00287                         // {
00288                         if (face_identification_votes_[updateIndex].find(src.label) == face_identification_votes_[updateIndex].end())
00289                                 face_identification_votes_[updateIndex][src.label] = 1.0;
00290                         else
00291                                 face_identification_votes_[updateIndex][src.label] += 1.0;
00292                         // }
00293 
00294                         // apply voting decay with time and find most voted label
00295                         double max_score = 0;
00296                         dest.label = src.label;
00297                         for (std::map<std::string, double>::iterator face_identification_votes_it = face_identification_votes_[updateIndex].begin(); face_identification_votes_it
00298                                         != face_identification_votes_[updateIndex].end(); face_identification_votes_it++)
00299                         {
00300                                 face_identification_votes_it->second *= face_identification_score_decay_rate_;
00301                                 std::string label = face_identification_votes_it->first;
00302                                 if (((label != "Unknown" && fall_back_to_unknown_identification_ == false) || fall_back_to_unknown_identification_ == true) && label != "UnknownRange"
00303                                                 /*&& label!="No face"*/&& face_identification_votes_it->second > max_score)
00304                                 {
00305                                         max_score = face_identification_votes_it->second;
00306                                         dest.label = label;
00307                                 }
00308                         }
00309 
00310                         // 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)
00311                         if (face_identification_votes_[updateIndex][dest.label] > face_identification_votes_[updateIndex]["UnknownRange"])
00312                                 face_identification_votes_[updateIndex]["UnknownRange"] = face_identification_votes_[updateIndex][dest.label];
00313                         if (fall_back_to_unknown_identification_ == false)
00314                         {
00315                                 if (face_identification_votes_[updateIndex]["Unknown"] > face_identification_votes_[updateIndex]["UnknownRange"])
00316                                         face_identification_votes_[updateIndex]["UnknownRange"] = face_identification_votes_[updateIndex]["Unknown"];
00317                         }
00318                 }
00319                 else
00320                         dest.label = src.label;
00321 
00322                 if (dest.label == "UnknownRange")
00323                         dest.label = "Unknown";
00324 
00325                 // time stamp, detector (color or range)
00326                 // if (update==true)
00327                 // {
00328                 // if (src.detector=="color") dest.detector = "color";
00329                 // }
00330                 // else dest.detector = src.detector;
00331                 dest.detector = src.detector;
00332 
00333                 dest.header.stamp = ros::Time::now();
00334 
00335                 return ipa_Utils::RET_OK;
00336         }
00337 
00338         inline double abs(double x)
00339         {
00340                 return ((x < 0) ? -x : x);
00341         }
00342 
00346         double computeFacePositionDistance(const cob_perception_msgs::Detection& previous_detection, const cob_perception_msgs::Detection& current_detection)
00347         {
00348                 const geometry_msgs::Point* point_1 = &(previous_detection.pose.pose.position);
00349                 const geometry_msgs::Point* point_2 = &(current_detection.pose.pose.position);
00350 
00351                 double dx = abs(point_1->x - point_2->x);
00352                 double dy = abs(point_1->y - point_2->y);
00353                 double dz = abs(point_1->z - point_2->z);
00354 
00355                 // return a huge distance if the current face position is too far away from the recent
00356                 if (dx > tracking_range_m_ || dy > tracking_range_m_ || dz > tracking_range_m_)
00357                 {
00358                         // new face position is too distant to recent position
00359                         return DBL_MAX;
00360                 }
00361 
00362                 // return Euclidian distance if both faces are sufficiently close
00363                 double dist = dx * dx + dy * dy + dz * dz;
00364                 return dist;
00365         }
00366 
00369         unsigned long removeMultipleInstancesOfLabel()
00370         {
00371                 // check this for each recognized face
00372                 for (int i = 0; i < (int)face_position_accumulator_.size(); i++)
00373                 {
00374                         // label of this detection
00375                         std::string label = face_position_accumulator_[i].label;
00376 
00377                         // check whether this label has multiple occurrences if it is a real name
00378                         if (label != "Unknown" && label != "No face")
00379                         {
00380                                 for (int j = 0; j < (int)face_position_accumulator_.size(); j++)
00381                                 {
00382                                         if (j == i)
00383                                                 continue; // do not check yourself
00384 
00385                                         if (face_position_accumulator_[j].label == label)
00386                                         {
00387                                                 if (display_)
00388                                                         std::cout << "face_identification_votes_[i][" << label << "] = " << face_identification_votes_[i][label] << " face_identification_votes_[j][" << label
00389                                                                         << "] = " << face_identification_votes_[j][label] << "\n";
00390 
00391                                                 // correct this label to Unknown when some other instance has a higher score on this label
00392                                                 if (face_identification_votes_[i][label] < face_identification_votes_[j][label])
00393                                                 {
00394                                                         face_position_accumulator_[i].label = "Unknown";
00395                                                         // 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)
00396                                                         if (face_identification_votes_[i][label] > face_identification_votes_[i]["Unknown"])
00397                                                                 face_identification_votes_[i]["Unknown"] = face_identification_votes_[i][label];
00398                                                 }
00399                                         }
00400                                 }
00401                         }
00402                 }
00403 
00404                 return ipa_Utils::RET_OK;
00405         }
00406 
00407         unsigned long prepareFacePositionMessage(cob_perception_msgs::DetectionArray& face_position_msg_out)
00408         {
00409                 // publish face positions
00410                 std::vector<cob_perception_msgs::Detection> faces_to_publish;
00411                 for (int i = 0; i < (int)face_position_accumulator_.size(); i++)
00412                 {
00413                         if (display_)
00414                                 std::cout << "'UnknownRange' score: " << face_identification_votes_[i]["UnknownRange"] << " label '" << face_position_accumulator_[i].label << "' score: "
00415                                                 << face_identification_votes_[i][face_position_accumulator_[i].label] << " - ";
00416                         if (face_identification_votes_[i][face_position_accumulator_[i].label] > min_face_identification_score_to_publish_ || face_identification_votes_[i]["UnknownRange"]
00417                                         > min_face_identification_score_to_publish_)
00418                         {
00419                                 faces_to_publish.push_back(face_position_accumulator_[i]);
00420                                 if (display_)
00421                                         std::cout << "published\n";
00422                         }
00423                         else if (display_)
00424                                 std::cout << "not published\n";
00425                 }
00426                 face_position_msg_out.detections = faces_to_publish;
00427                 // hack: for WimiCare replace 'Unknown' by '0000'
00428                 //        for (int i=0; i<(int)face_position_msg_out.detections.size(); i++)
00429                 //        {
00430                 //                if (face_position_msg_out.detections[i].label=="Unknown")
00431                 //                        face_position_msg_out.detections[i].label = "0000";
00432                 //        }
00433                 face_position_msg_out.header.stamp = ros::Time::now();
00434 
00435                 return ipa_Utils::RET_OK;
00436         }
00437 
00439         void inputCallback(const cob_perception_msgs::DetectionArray::ConstPtr& face_position_msg_in, const sensor_msgs::Image::ConstPtr& people_segmentation_image_msg,
00440                         const sensor_msgs::Image::ConstPtr& color_image_msg)
00441         {
00442                 // convert segmentation image to cv::Mat
00443                 cv_bridge::CvImageConstPtr people_segmentation_image_ptr;
00444                 cv::Mat people_segmentation_image;
00445                 if (use_people_segmentation_ == true)
00446                         convertColorImageMessageToMat(people_segmentation_image_msg, people_segmentation_image_ptr, people_segmentation_image);
00447 
00448                 if (display_)
00449                         std::cout << "detections: " << face_position_msg_in->detections.size() << "\n";
00450 
00451                 // source image size
00452                 std::stringstream ss;
00453                 ss << face_position_msg_in->header.frame_id;
00454                 int width, height;
00455                 ss >> width;
00456                 ss >> height;
00457 
00458                 // delete old face positions in list
00459                 ros::Duration timeSpan(face_redetection_time_);
00460                 for (int i = 0; i < (int)face_position_accumulator_.size(); i++)
00461                 {
00462                         if ((ros::Time::now() - face_position_accumulator_[i].header.stamp) > timeSpan)
00463                         {
00464                                 face_position_accumulator_.erase(face_position_accumulator_.begin() + i);
00465                                 face_identification_votes_.erase(face_identification_votes_.begin() + i);
00466                         }
00467                 }
00468                 if (display_)
00469                         std::cout << "Old face positions deleted.\n";
00470 
00471                 // secure this section with a mutex
00472                 boost::timed_mutex::scoped_timed_lock lock(face_position_accumulator_mutex_, boost::posix_time::milliseconds(2000));
00473                 if (lock.owns_lock() == false)
00474                 {
00475                         ROS_ERROR("cob_people_detection::CobPeopleDetectionNodelet: Mutex was not freed during response time.");
00476                         return;
00477                 }
00478                 if (display_)
00479                         std::cout << "Got mutex.\n";
00480 
00481                 // verify face detections with people segmentation if enabled -> only accept detected faces if a person is segmented at that position
00482                 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
00483                 if (use_people_segmentation_ == true)
00484                 {
00485                         for (int i = 0; i < (int)face_position_msg_in->detections.size(); i++)
00486                         {
00487                                 const cob_perception_msgs::Detection* const det_in = &(face_position_msg_in->detections[i]);
00488                                 cv::Rect face;
00489                                 face.x = det_in->mask.roi.x;
00490                                 face.y = det_in->mask.roi.y;
00491                                 face.width = det_in->mask.roi.width;
00492                                 face.height = det_in->mask.roi.height;
00493 
00494                                 int numberBlackPixels = 0;
00495                                 //std::cout << "face: " << face.x << " " << face.y << " " << face.width << " " << face.height << "\n";
00496                                 for (int v = face.y; v < face.y + face.height; v++)
00497                                 {
00498                                         uchar* data = people_segmentation_image.ptr(v);
00499                                         for (int u = face.x; u < face.x + face.width; u++)
00500                                         {
00501                                                 int index = 3 * u;
00502                                                 if (data[index] == 0 && data[index + 1] == 0 && data[index + 2] == 0)
00503                                                         numberBlackPixels++;
00504                                         }
00505                                 }
00506                                 int faceArea = face.height * face.width;
00507                                 double segmentedPeopleRatio = (double)(faceArea - numberBlackPixels) / (double)faceArea;
00508 
00509                                 // if (display_) std::cout << "ratio: " << segmentedPeopleRatio << "\n";
00510                                 if ((det_in->detector == "color" && segmentedPeopleRatio < min_segmented_people_ratio_color_) || (det_in->detector == "range" && segmentedPeopleRatio
00511                                                 < min_segmented_people_ratio_range_))
00512                                 {
00513                                         // False detection
00514                                         if (display_)
00515                                                 std::cout << "False detection\n";
00516                                 }
00517                                 else
00518                                 {
00519                                         // Push index of this detection into the list
00520                                         face_detection_indices.push_back(i);
00521                                 }
00522                         }
00523                         if (display_)
00524                                 std::cout << "Verification with people segmentation done.\n";
00525                 }
00526                 else
00527                 {
00528                         for (unsigned int i = 0; i < face_position_msg_in->detections.size(); i++)
00529                                 face_detection_indices.push_back(i);
00530                 }
00531                 // match current detections with previous detections
00532                 // build distance matrix
00533                 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
00534                 std::map<int, std::map<int, double> >::iterator distance_matrix_it;
00535                 for (unsigned int previous_det = 0; previous_det < face_position_accumulator_.size(); previous_det++)
00536                 {
00537                         std::map<int, double> distance_row;
00538                         for (unsigned int i = 0; i < face_detection_indices.size(); i++)
00539                                 distance_row[face_detection_indices[i]] = computeFacePositionDistance(face_position_accumulator_[previous_det],
00540                                                 face_position_msg_in->detections[face_detection_indices[i]]);
00541                         distance_matrix[previous_det] = distance_row;
00542                 }
00543                 if (display_)
00544                         std::cout << "Distance matrix.\n";
00545 
00546                 // find matching faces between previous and current detections
00547                 unsigned int number_matchings = (face_position_accumulator_.size() < face_detection_indices.size()) ? face_position_accumulator_.size() : face_detection_indices.size();
00548                 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
00549                 for (unsigned int m = 0; m < number_matchings; m++)
00550                 {
00551                         // find minimum matching distance between any two elements of the distance_matrix
00552                         double min_dist = DBL_MAX;
00553                         int previous_min_index, current_min_index;
00554                         for (distance_matrix_it = distance_matrix.begin(); distance_matrix_it != distance_matrix.end(); distance_matrix_it++)
00555                         {
00556                                 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++)
00557                                 {
00558                                         if (distance_row_it->second < min_dist)
00559                                         {
00560                                                 min_dist = distance_row_it->second;
00561                                                 previous_min_index = distance_matrix_it->first;
00562                                                 current_min_index = distance_row_it->first;
00563                                         }
00564                                 }
00565                         }
00566 
00567                         // todo: consider size relation between color and depth image face frames!
00568 
00569                         // if there is no matching pair of detections interrupt the search for matchings at this point
00570                         if (min_dist == DBL_MAX)
00571                                 break;
00572 
00573                         // instantiate the matching
00574                         copyDetection(face_position_msg_in->detections[current_min_index], face_position_accumulator_[previous_min_index], true, previous_min_index);
00575                         // mark the respective entry in face_detection_indices as labeled
00576                         for (unsigned int i = 0; i < face_detection_indices.size(); i++)
00577                                 if (face_detection_indices[i] == current_min_index)
00578                                         current_detection_has_matching[i] = true;
00579 
00580                         // delete the row and column of the found matching so that both detections cannot be involved in any further matching again
00581                         distance_matrix.erase(previous_min_index);
00582                         for (distance_matrix_it = distance_matrix.begin(); distance_matrix_it != distance_matrix.end(); distance_matrix_it++)
00583                                 distance_matrix_it->second.erase(current_min_index);
00584                 }
00585                 if (display_)
00586                         std::cout << "Matches found.\n";
00587 
00588                 // create new detections for the unmatched of the current detections if they originate from the color image
00589                 for (unsigned int i = 0; i < face_detection_indices.size(); i++)
00590                 {
00591                         if (current_detection_has_matching[i] == false)
00592                         {
00593                                 const cob_perception_msgs::Detection* const det_in = &(face_position_msg_in->detections[face_detection_indices[i]]);
00594                                 if (det_in->detector == "color")
00595                                 {
00596                                         // save in accumulator
00597                                         if (display_)
00598                                                 std::cout << "\n***** New detection *****\n\n";
00599                                         cob_perception_msgs::Detection det_out;
00600                                         copyDetection(*det_in, det_out, false);
00601                                         det_out.pose.header.frame_id = face_position_msg_in->header.frame_id;
00602                                         face_position_accumulator_.push_back(det_out);
00603                                         // remember label history
00604                                         std::map<std::string, double> new_identification_data;
00605                                         //new_identification_data["Unknown"] = 0.0;
00606                                         new_identification_data["UnknownRange"] = 0.0;
00607                                         new_identification_data[det_in->label] = 1.0;
00608                                         face_identification_votes_.push_back(new_identification_data);
00609                                 }
00610                         }
00611                 }
00612                 if (display_)
00613                         std::cout << "New detections.\n";
00614 
00615                 // eliminate multiple instances of a label
00616                 removeMultipleInstancesOfLabel();
00617 
00618                 // publish face positions
00619                 cob_perception_msgs::DetectionArray face_position_msg_out;
00620                 /*      std::vector<cob_perception_msgs::Detection> faces_to_publish;
00621                  for (int i=0; i<(int)face_position_accumulator_.size(); i++)
00622                  {
00623                  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] << " - ";
00624                  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_)
00625                  {
00626                  faces_to_publish.push_back(face_position_accumulator_[i]);
00627                  if (display_) std::cout << "published\n";
00628                  }
00629                  else if (display_) std::cout << "not published\n";
00630                  }
00631                  face_position_msg_out.detections = faces_to_publish;
00632                  // hack: for WimiCare replace 'Unknown' by '0000'
00633                  for (int i=0; i<(int)face_position_msg_out.detections.size(); i++)
00634                  {
00635                  if (face_position_msg_out.detections[i].label=="Unknown")
00636                  face_position_msg_out.detections[i].label = "0000";
00637                  }
00638                  face_position_msg_out.header.stamp = ros::Time::now();
00639                  */
00640                 prepareFacePositionMessage(face_position_msg_out);
00641                 face_position_publisher_.publish(face_position_msg_out);
00642 
00643                 // display
00644                 if (display_ == true)
00645                 {
00646                         // convert image message to cv::Mat
00647                         cv_bridge::CvImageConstPtr colorImagePtr;
00648                         cv::Mat colorImage;
00649                         convertColorImageMessageToMat(color_image_msg, colorImagePtr, colorImage);
00650 
00651                         // display color image
00652                         for (int i = 0; i < (int)face_position_msg_out.detections.size(); i++)
00653                         {
00654                                 cv::Rect face;
00655                                 cob_perception_msgs::Rect& faceRect = face_position_msg_out.detections[i].mask.roi;
00656                                 face.x = faceRect.x;
00657                                 face.width = faceRect.width;
00658                                 face.y = faceRect.y;
00659                                 face.height = faceRect.height;
00660 
00661                                 if (face_position_msg_out.detections[i].detector == "range")
00662                                         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);
00663                                 else
00664                                         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);
00665 
00666                                 if (face_position_msg_out.detections[i].label == "Unknown")
00667                                         // Distance to face class is too high
00668                                         cv::putText(colorImage, "Unknown", cv::Point(face.x, face.y + face.height + 25), cv::FONT_HERSHEY_PLAIN, 2, CV_RGB( 255, 0, 0 ), 2);
00669                                 else if (face_position_msg_out.detections[i].label == "No face")
00670                                         // Distance to face space is too high
00671                                         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);
00672                                 else
00673                                         // Face classified
00674                                         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,
00675                                                         CV_RGB( 0, 255, 0 ), 2);
00676                         }
00677                         // publish image
00678                         cv_bridge::CvImage cv_ptr;
00679                         cv_ptr.image = colorImage;
00680                         cv_ptr.encoding = "bgr8";
00681                         people_detection_image_pub_.publish(cv_ptr.toImageMsg());
00682                 }
00683         }
00684 
00685         bool detectPeopleCallback(cob_people_detection::DetectPeople::Request &req, cob_people_detection::DetectPeople::Response &res)
00686         {
00687                 // secure this section with a mutex
00688                 boost::timed_mutex::scoped_timed_lock lock(face_position_accumulator_mutex_, boost::posix_time::milliseconds(2000));
00689                 if (lock.owns_lock() == false)
00690                 {
00691                         ROS_ERROR("cob_people_detection::CobPeopleDetectionNodelet: Mutex was not freed during response time.");
00692                         return false;
00693                 }
00694 
00695                 prepareFacePositionMessage(res.people_list);
00696                 //res.people_list.detections = face_position_accumulator_;
00697                 //res.people_list.header.stamp = ros::Time::now();
00698                 return true;
00699         }
00700 };
00701 
00702 }
00703 ;
00704 
00705 PLUGINLIB_EXPORT_CLASS(ipa_PeopleDetector::CobPeopleDetectionNodelet, nodelet::Nodelet);
00706 
00707 #endif // _PEOPLE_DETECTION_


cob_people_detection
Author(s): Richard Bormann , Thomas Zwölfer
autogenerated on Mon May 6 2019 02:32:06