47 #include <boost/filesystem.hpp> 48 #include <boost/thread/mutex.hpp> 50 #include <people_msgs/PositionMeasurement.h> 51 #include <people_msgs/PositionMeasurementArray.h> 57 #include "sensor_msgs/CameraInfo.h" 58 #include "sensor_msgs/Image.h" 59 #include "stereo_msgs/DisparityImage.h" 63 #include "sensor_msgs/PointCloud.h" 64 #include "geometry_msgs/Point32.h" 66 #include "opencv/cxcore.hpp" 67 #include "opencv/cv.hpp" 68 #include "opencv/highgui.h" 75 #include <face_detector/FaceDetectorAction.h> 173 people_msgs::PositionMeasurement
pos;
186 boost::mutex cv_mutex_,
pos_mutex_, limage_mutex_, dimage_mutex_;
193 BIGDIST_M(1000000.0),
195 as_(nh_, name, false),
207 faces_ =
new Faces();
208 double face_size_min_m, face_size_max_m, max_face_z_m, face_sep_dist_m;
214 local_nh.
param(
"classifier_name", name_, std::string(
""));
215 local_nh.
param(
"classifier_filename", haar_filename_, std::string(
""));
216 local_nh.
param(
"classifier_reliability", reliability_, 0.0);
217 local_nh.
param(
"do_display", do_display_,
false);
218 local_nh.
param(
"do_continuous", do_continuous_,
true);
219 local_nh.
param(
"do_publish_faces_of_unknown_size", do_publish_unknown_,
false);
220 local_nh.
param(
"use_depth", use_depth_,
true);
221 local_nh.
param(
"use_external_init", external_init_,
false);
226 local_nh.
param(
"use_rgbd", use_rgbd_,
false);
227 local_nh.
param(
"queue_size", queue_size, 5);
228 local_nh.
param(
"approximate_sync", approx,
false);
233 cv::namedWindow(
"Face detector: Face Detection", CV_WINDOW_AUTOSIZE);
240 faces_->
initFaceDetectionDepth(1, haar_filename_, face_size_min_m, face_size_max_m, max_face_z_m, face_sep_dist_m);
248 depth_topic_ =
ros::names::clean(camera_ +
"/" + depth_ns_ +
"/" + depth_image_);
249 camera_info_topic_ =
ros::names::clean(camera_ +
"/" + rgb_ns_ +
"/camera_info");
250 depth_info_topic_ =
ros::names::clean(camera_ +
"/" + depth_ns_ +
"/camera_info");
252 ROS_DEBUG(
"camera_topic_: %s", camera_topic_.c_str());
253 ROS_DEBUG(
"depth_topic_: %s", depth_topic_.c_str());
254 ROS_DEBUG(
"camera_info_topic_: %s", camera_info_topic_.c_str());
255 ROS_DEBUG(
"depth_info_topic_: %s", depth_info_topic_.c_str());
257 local_nh.
param(
"fixed_frame", fixed_frame_, std::string(
"camera_rgb_optical_frame"));
261 approximate_depth_sync_.reset(
new ApproximateDepthSync(ApproximateDepthPolicy(queue_size),
262 image_sub_, depth_image_sub_, c1_info_sub_, c2_info_sub_));
263 approximate_depth_sync_->registerCallback(boost::bind(&FaceDetector::imageCBAllDepth,
264 this, _1, _2, _3, _4));
268 exact_depth_sync_.reset(
new ExactDepthSync(ExactDepthPolicy(queue_size),
269 image_sub_, depth_image_sub_, c1_info_sub_, c2_info_sub_));
270 exact_depth_sync_->registerCallback(boost::bind(&FaceDetector::imageCBAllDepth,
271 this, _1, _2, _3, _4));
283 left_camera_info_topic_ =
ros::names::clean(stereo_namespace_ +
"/left/camera_info");
284 right_camera_info_topic_ =
ros::names::clean(stereo_namespace_ +
"/right/camera_info");
286 local_nh.
param(
"fixed_frame", fixed_frame_, stereo_namespace_.append(
"_optical_frame"));
290 approximate_disp_sync_.reset(
new ApproximateDispSync(ApproximateDispPolicy(queue_size),
291 image_sub_, disp_image_sub_, c1_info_sub_, c2_info_sub_));
292 approximate_disp_sync_->registerCallback(boost::bind(&FaceDetector::imageCBAllDisp,
293 this, _1, _2, _3, _4));
297 exact_disp_sync_.reset(
new ExactDispSync(ExactDispPolicy(queue_size),
298 image_sub_, disp_image_sub_, c1_info_sub_, c2_info_sub_));
299 exact_disp_sync_->registerCallback(boost::bind(&FaceDetector::imageCBAllDisp,
300 this, _1, _2, _3, _4));
308 ROS_INFO_STREAM_NAMED(
"face_detector",
"You must subscribe to one of FaceDetector's outbound topics or else it will not publish anything.");
311 boost::mutex::scoped_lock lock(connect_mutex_);
314 pos_array_pub_ = nh_.
advertise<people_msgs::PositionMeasurementArray>(
"face_detector/people_tracker_measurements_array", 1, pos_pub_connect_cb, pos_pub_connect_cb);
316 cloud_pub_ = nh_.
advertise<sensor_msgs::PointCloud>(
"face_detector/faces_cloud", 0, cloud_pub_connect_cb, cloud_pub_connect_cb);
321 if (!do_continuous_) connectCb();
331 cv_image_out_.release();
335 cv::destroyWindow(
"Face detector: Face Detection");
348 boost::mutex::scoped_lock lock(connect_mutex_);
353 ROS_INFO_STREAM_NAMED(
"face_detector",
"You have unsubscribed to FaceDetector's outbound topics, so it will no longer publish anything.");
362 image_sub_.
subscribe(it_, camera_topic_, 3);
363 depth_image_sub_.
subscribe(it_, depth_topic_, 3);
364 c1_info_sub_.
subscribe(nh_, camera_info_topic_, 3);
365 c2_info_sub_.
subscribe(nh_, depth_info_topic_, 3);
377 ROS_INFO_STREAM_NAMED(
"face_detector",
"You have unsubscribed to FaceDetector's outbound topics, so it will no longer publish anything.");
386 image_sub_.
subscribe(it_, left_topic_, 3);
387 disp_image_sub_.
subscribe(nh_, disparity_topic_, 3);
388 c1_info_sub_.
subscribe(nh_, left_camera_info_topic_, 3);
389 c2_info_sub_.
subscribe(nh_, right_camera_info_topic_, 3);
454 void imageCBAllDepth(
const sensor_msgs::Image::ConstPtr &image,
const sensor_msgs::Image::ConstPtr& depth_image,
const sensor_msgs::CameraInfo::ConstPtr& c1_info,
const sensor_msgs::CameraInfo::ConstPtr& c2_info)
458 if (!do_continuous_ && !as_.
isActive())
462 result_.face_positions.clear();
472 cv::Mat depth_32fc1 = cv_depth_ptr->image;
473 if (depth_image->encoding !=
"32FC1")
475 cv_depth_ptr->image.convertTo(depth_32fc1, CV_32FC1, 0.001);
485 cv_image_out_ = (cv_image_ptr->image).clone();
488 struct timeval timeofday;
489 gettimeofday(&timeofday, NULL);
492 vector<Box2D3D> faces_vector = faces_->
detectAllFacesDepth(cv_image_ptr->image, 1.0, depth_32fc1, &cam_model_);
493 gettimeofday(&timeofday, NULL);
498 matchAndDisplay(faces_vector, image->header);
509 void imageCBAllDisp(
const sensor_msgs::Image::ConstPtr &image,
const stereo_msgs::DisparityImage::ConstPtr& disp_image,
const sensor_msgs::CameraInfo::ConstPtr& c1_info,
const sensor_msgs::CameraInfo::ConstPtr& c2_info)
513 if (!do_continuous_ && !as_.
isActive())
517 result_.face_positions.clear();
533 cv_image_out_ = (cv_image_ptr->image).clone();
536 struct timeval timeofday;
537 gettimeofday(&timeofday, NULL);
540 vector<Box2D3D> faces_vector = faces_->
detectAllFacesDisparity(cv_image_ptr->image, 1.0, cv_disp_ptr->image, &cam_model_);
541 gettimeofday(&timeofday, NULL);
546 matchAndDisplay(faces_vector, image->header);
554 bool found_faces =
false;
557 sensor_msgs::PointCloud cloud;
558 cloud.header.stamp = header.stamp;
559 cloud.header.frame_id = header.frame_id;
561 if (faces_vector.size() > 0)
566 map<string, RestampedPositionMeasurement>::iterator it;
567 it = pos_list_.begin();
568 while (it != pos_list_.end())
573 pos_list_.erase(it++);
583 tf_.
transformPoint(header.frame_id, header.stamp, loc, fixed_frame_, loc);
584 (*it).second.pos.header.stamp = header.stamp;
585 (*it).second.pos.pos.x = loc[0];
586 (*it).second.pos.pos.y = loc[1];
587 (*it).second.pos.pos.z = loc[2];
599 people_msgs::PositionMeasurement pos;
600 people_msgs::PositionMeasurementArray pos_array;
602 for (uint iface = 0; iface < faces_vector.size(); iface++)
604 one_face = &faces_vector[iface];
606 if (one_face->
status ==
"good" || (one_face->
status ==
"unknown" && do_publish_unknown_))
612 pos.header.stamp = header.stamp;
617 pos.header.frame_id = header.frame_id;
618 pos.reliability = reliability_;
619 pos.initialization = 1;
620 pos.covariance[0] = 0.04;
621 pos.covariance[1] = 0.0;
622 pos.covariance[2] = 0.0;
623 pos.covariance[3] = 0.0;
624 pos.covariance[4] = 0.04;
625 pos.covariance[5] = 0.0;
626 pos.covariance[6] = 0.0;
627 pos.covariance[7] = 0.0;
628 pos.covariance[8] = 0.04;
633 double dist, mindist = BIGDIST_M;
634 map<string, RestampedPositionMeasurement>::iterator close_it = pos_list_.end();
635 for (it = pos_list_.begin(); it != pos_list_.end(); it++)
637 dist = pow((*it).second.pos.pos.x - pos.pos.x, 2.0) + pow((*it).second.pos.pos.y - pos.pos.y, 2.0) + pow((*it).second.pos.pos.z - pos.pos.z, 2.0);
638 if (dist <= faces_->face_sep_dist_m_ && dist < mindist)
644 if (close_it != pos_list_.end())
646 pos.object_id = (*close_it).second.pos.object_id;
647 if (mindist < (*close_it).second.dist)
649 (*close_it).second.restamp = header.stamp;
650 (*close_it).second.dist = mindist;
651 (*close_it).second.pos = pos;
658 pos.object_id =
static_cast<ostringstream*
>(&(ostringstream() << max_id_))->str();
659 ROS_INFO_STREAM_NAMED(
"face_detector",
"Didn't find face to match, starting new ID " << pos.object_id);
661 result_.face_positions.push_back(pos);
667 pos_array.header.stamp = header.stamp;
668 pos_array.header.frame_id = header.frame_id;
669 pos_array.people = result_.face_positions;
670 if (pos_array.people.size() > 0)
672 pos_array_pub_.
publish(pos_array);
675 map<string, RestampedPositionMeasurement>::iterator it;
676 for (uint ipa = 0; ipa < pos_array.people.size(); ipa++)
678 it = pos_list_.find(pos_array.people[ipa].object_id);
680 rpm.
pos = pos_array.people[ipa];
681 rpm.
restamp = pos_array.people[ipa].header.stamp;
682 rpm.
dist = BIGDIST_M;
683 if (it == pos_list_.end())
685 pos_list_.insert(pair<string, RestampedPositionMeasurement>(pos_array.people[ipa].object_id, rpm));
687 else if ((pos_array.people[ipa].header.stamp - (*it).second.pos.header.stamp) >
ros::Duration().
fromSec(-1.0))
695 for (it = pos_list_.begin(); it != pos_list_.end(); it++)
697 (*it).second.
dist = BIGDIST_M;
709 cloud.channels.resize(1);
710 cloud.channels[0].name =
"intensity";
712 for (uint iface = 0; iface < faces_vector.size(); iface++)
714 one_face = &faces_vector[iface];
717 if (one_face->
status ==
"good")
720 geometry_msgs::Point32 p;
724 cloud.points.push_back(p);
725 cloud.channels[0].values.push_back(1.0
f);
740 displayFacesOnImage(faces_vector);
747 ROS_INFO_STREAM_NAMED(
"face_detector",
"Number of faces found: " << faces_vector.size() <<
", number with good depth and size: " << ngood);
750 if (!do_continuous_ && found_faces)
762 for (uint iface = 0; iface < faces_vector.size(); iface++)
764 one_face = &faces_vector[iface];
769 if (one_face->
status ==
"good")
771 color = cv::Scalar(0, 255, 0);
773 else if (one_face->
status ==
"unknown")
775 color = cv::Scalar(255, 0, 0);
779 color = cv::Scalar(0, 0, 255);
782 cv::rectangle(cv_image_out_,
783 cv::Point(one_face->
box2d.x, one_face->
box2d.y),
784 cv::Point(one_face->
box2d.x + one_face->
box2d.width, one_face->
box2d.y + one_face->
box2d.height), color, 4);
788 cv::imshow(
"Face detector: Face Detection", cv_image_out_);
799 int main(
int argc,
char **argv)
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
message_filters::Subscriber< sensor_msgs::CameraInfo > c2_info_sub_
image_transport::SubscriberFilter depth_image_sub_
boost::shared_ptr< const Goal > acceptNewGoal()
string right_camera_info_topic_
image_geometry::StereoCameraModel cam_model_
A structure for holding information about boxes in 2d and 3d.
boost::function< void(const SingleSubscriberPublisher &)> SubscriberStatusCallback
boost::shared_ptr< ApproximateDepthSync > approximate_depth_sync_
static void pointMsgToTF(const geometry_msgs::Point &msg_v, Point &bt_v)
message_filters::Synchronizer< ExactDepthPolicy > ExactDepthSync
void publish(const boost::shared_ptr< M > &message) const
string left_camera_info_topic_
bool fromCameraInfo(const sensor_msgs::CameraInfo &left, const sensor_msgs::CameraInfo &right)
Time & fromNSec(uint64_t t)
void displayFacesOnImage(vector< Box2D3D > faces_vector)
boost::shared_ptr< ExactDispSync > exact_disp_sync_
face_detector::FaceDetectorFeedback feedback_
image_transport::ImageTransport it_
std::string resolveName(const std::string &name, bool remap=true) const
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
ROSCPP_DECL const std::string & getName()
message_filters::sync_policies::ApproximateTime< sensor_msgs::Image, stereo_msgs::DisparityImage, sensor_msgs::CameraInfo, sensor_msgs::CameraInfo > ApproximateDispPolicy
#define ROS_INFO_STREAM_NAMED(name, args)
ROSCPP_DECL std::string clean(const std::string &name)
map< string, RestampedPositionMeasurement > pos_list_
face_detector::FaceDetectorResult result_
message_filters::Synchronizer< ApproximateDispPolicy > ApproximateDispSync
message_filters::sync_policies::ApproximateTime< sensor_msgs::Image, sensor_msgs::Image, sensor_msgs::CameraInfo, sensor_msgs::CameraInfo > ApproximateDepthPolicy
Position message callback.
void setSucceeded(const Result &result=Result(), const std::string &text=std::string(""))
ROSCPP_DECL void spin(Spinner &spinner)
void imageCBAllDepth(const sensor_msgs::Image::ConstPtr &image, const sensor_msgs::Image::ConstPtr &depth_image, const sensor_msgs::CameraInfo::ConstPtr &c1_info, const sensor_msgs::CameraInfo::ConstPtr &c2_info)
Image callback for synced messages.
FaceDetector(std::string name)
message_filters::Subscriber< sensor_msgs::CameraInfo > c1_info_sub_
ros::Publisher pos_array_pub_
message_filters::sync_policies::ExactTime< sensor_msgs::Image, stereo_msgs::DisparityImage, sensor_msgs::CameraInfo, sensor_msgs::CameraInfo > ExactDispPolicy
void setPreempted(const Result &result=Result(), const std::string &text=std::string(""))
string camera_info_topic_
message_filters::Synchronizer< ExactDispPolicy > ExactDispSync
tf::TransformListener tf_
Duration & fromSec(double t)
actionlib::SimpleActionServer< face_detector::FaceDetectorAction > as_
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
void registerPreemptCallback(boost::function< void()> cb)
const Subscriber & getSubscriber() const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
int main(int argc, char **argv)
message_filters::sync_policies::ExactTime< sensor_msgs::Image, sensor_msgs::Image, sensor_msgs::CameraInfo, sensor_msgs::CameraInfo > ExactDepthPolicy
vector< Box2D3D > detectAllFacesDisparity(const cv::Mat &image, double threshold, const cv::Mat &disparity_image, image_geometry::StereoCameraModel *cam_model)
Detect all faces in an image and disparity image.
void subscribe(ImageTransport &it, const std::string &base_topic, uint32_t queue_size, const TransportHints &transport_hints=TransportHints())
void initFaceDetectionDepth(uint num_cascades, string haar_classifier_filename, double face_size_min_m, double face_size_max_m, double max_face_z_m, double face_sep_dist_m)
Initialize the face detector with images and depth.
vector< Box2D3D > detectAllFacesDepth(const cv::Mat &image, double threshold, const cv::Mat &depth_image, image_geometry::StereoCameraModel *cam_model)
Detect all faces in an image and depth image.
uint32_t getNumSubscribers() const
void subscribe(ros::NodeHandle &nh, const std::string &topic, uint32_t queue_size, const ros::TransportHints &transport_hints=ros::TransportHints(), ros::CallbackQueueInterface *callback_queue=0)
boost::shared_ptr< ExactDepthSync > exact_depth_sync_
Contains a list of faces and functions that can be performed on that list. This includes utility task...
image_transport::SubscriberFilter image_sub_
void initFaceDetectionDisparity(uint num_cascades, string haar_classifier_filename, double face_size_min_m, double face_size_max_m, double max_face_z_m, double face_sep_dist_m)
Initialize the face detector with images and disparities.
boost::shared_ptr< ApproximateDispSync > approximate_disp_sync_
message_filters::Subscriber< stereo_msgs::DisparityImage > disp_image_sub_
void registerGoalCallback(boost::function< void()> cb)
boost::mutex connect_mutex_
void matchAndDisplay(vector< Box2D3D > faces_vector, std_msgs::Header header)
void imageCBAllDisp(const sensor_msgs::Image::ConstPtr &image, const stereo_msgs::DisparityImage::ConstPtr &disp_image, const sensor_msgs::CameraInfo::ConstPtr &c1_info, const sensor_msgs::CameraInfo::ConstPtr &c2_info)
Image callback for synced messages.
ros::Publisher cloud_pub_
message_filters::Synchronizer< ApproximateDepthPolicy > ApproximateDepthSync
void operator()(void const *) const
people_msgs::PositionMeasurement pos