00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 #include <stdlib.h>
00053 #include <string>
00054 #include <math.h>
00055 #include <algorithm>
00056 #include <iostream>
00057 #include <vector>
00058 #include "head_pose_estimation/CRForestEstimator.h"
00059
00060 #include <ros/ros.h>
00061 #include "sensor_msgs/Image.h"
00062 #include "sensor_msgs/PointCloud2.h"
00063 #include "image_transport/image_transport.h"
00064 #include <cv_bridge/cv_bridge.h>
00065 #include <sensor_msgs/image_encodings.h>
00066
00067 #include <pcl_ros/point_cloud.h>
00068 #include <pcl/point_types.h>
00069
00070 #include <kdl/frames.hpp>
00071 #include <angles/angles.h>
00072 #include <geometry_msgs/PoseStamped.h>
00073 #include <geometry_msgs/PointStamped.h>
00074
00075 #include <tf/transform_listener.h>
00076 #include <tf/transform_broadcaster.h>
00077
00078 #include "people_msgs/PositionMeasurement.h"
00079 #include "people_msgs/PositionMeasurementArray.h"
00080
00081 typedef pcl::PointCloud<pcl::PointXYZ> PointCloud;
00082
00083 using namespace std;
00084 using namespace cv;
00085 using namespace angles;
00086
00087
00088 string g_treepath;
00089
00090 int g_ntrees;
00091
00092 int g_p_width;
00093
00094 int g_p_height;
00095
00096 int g_max_z = 0;
00097
00098 int g_th = 400;
00099
00100 float g_prob_th = 1.0f;
00101
00102 double g_maxv = 800.f;
00103
00104 int g_stride = 5;
00105
00106 double g_larger_radius_ratio = 1.f;
00107
00108 double g_smaller_radius_ratio = 6.f;
00109
00110
00111 CRForestEstimator* g_Estimate;
00112
00113 Mat g_im3D;
00114
00115
00116 string g_head_target_frame;
00117
00118 bool g_head_depth_ready = false;
00119 bool g_cloud_ready = false;
00120 bool g_transform_ready = false;
00121
00122 double g_head_depth = 0.5;
00123
00124 string g_cloud_frame;
00125
00126 double g_roll_bias = 0;
00127 double g_pitch_bias = 0;
00128 double g_yaw_bias = 0;
00129
00130 CRForestEstimator estimator;
00131 ros::Publisher pose_pub;
00132
00133 tf::TransformListener* listener;
00134 tf::TransformBroadcaster* broadcaster;
00135 tf::StampedTransform g_transform;
00136
00137 std::vector< cv::Vec<float,POSE_SIZE> > g_means;
00138 std::vector< std::vector< Vote > > g_clusters;
00139 std::vector< Vote > g_votes;
00140
00141 void loadConfig() {
00142 ros::NodeHandle nh("~");
00143 nh.param("tree_path", g_treepath, string("trees/tree"));
00144 nh.param("ntrees", g_ntrees, 10);
00145 nh.param("max_variance", g_maxv, 800.0);
00146 nh.param("larger_radius_ratio", g_larger_radius_ratio, 1.0);
00147 nh.param("smaller_radius_ratio",g_smaller_radius_ratio, 6.0);
00148 nh.param("stride", g_stride, 5);
00149 nh.param("head_threshold", g_th, 400);
00150 nh.param("head_target_frame", g_head_target_frame, string("/camera_depth_frame"));
00151 nh.param("angular_bias_roll", g_roll_bias, 0.0);
00152 nh.param("angular_bias_pitch", g_pitch_bias, 0.0);
00153 nh.param("angular_bias_yaw", g_yaw_bias, 0.0);
00154
00155
00156 }
00157
00158 void peopleCallback(const people_msgs::PositionMeasurementArray::ConstPtr& msg) {
00159 if(g_cloud_ready && (msg->people.size() > 0)) {
00160 g_head_depth_ready = true;
00161 people_msgs::PositionMeasurement person = msg->people[0];
00162 geometry_msgs::PointStamped head_point, head_point_transformed;
00163 head_point.header = person.header;
00164 head_point.point = person.pos;
00165 listener->transformPoint(g_cloud_frame, head_point, head_point_transformed);
00166 g_head_depth = head_point_transformed.point.z;
00167 }
00168 }
00169
00170 void cloudCallback(const sensor_msgs::PointCloud2ConstPtr& msg)
00171 {
00172 PointCloud cloud;
00173 pcl::fromROSMsg(*msg, cloud);
00174
00175 g_cloud_frame = cloud.header.frame_id;
00176 g_cloud_ready = true;
00177
00178 if(!g_head_depth_ready) return;
00179
00180 Mat img3D;
00181 img3D = Mat::zeros(cloud.height, cloud.width, CV_32FC3);
00182
00183
00184 int yMin, xMin, yMax, xMax;
00185 yMin = 0; xMin = 0;
00186 yMax = img3D.rows; xMax = img3D.cols;
00187
00188
00189 for(int y = yMin ; y < img3D.rows; y++) {
00190 Vec3f* img3Di = img3D.ptr<Vec3f>(y);
00191
00192 for(int x = xMin; x < img3D.cols; x++) {
00193 pcl::PointXYZ p = cloud.at(x,y);
00194 if((p.z>g_head_depth-0.2) && (p.z<g_head_depth+0.2)) {
00195 img3Di[x][0] = p.x*1000;
00196 img3Di[x][1] = p.y*1000;
00197 img3Di[x][2] = hypot(img3Di[x][0], p.z*1000);
00198
00199 } else {
00200 img3Di[x] = 0;
00201 }
00202 }
00203 }
00204
00205 g_means.clear();
00206 g_votes.clear();
00207 g_clusters.clear();
00208
00209
00210 estimator.estimate( img3D,
00211 g_means,
00212 g_clusters,
00213 g_votes,
00214 g_stride,
00215 g_maxv,
00216 g_prob_th,
00217 g_larger_radius_ratio,
00218 g_smaller_radius_ratio,
00219 false,
00220 g_th
00221 );
00222
00223
00224 if(g_means.size() > 0) {
00225 geometry_msgs::PoseStamped pose_msg;
00226 pose_msg.header.frame_id = msg->header.frame_id;
00227
00228 cv::Vec<float,POSE_SIZE> pose(g_means[0]);
00229
00230 tf::Quaternion q;
00231 q.setRPY(
00232 from_degrees( pose[5]+180+g_roll_bias ),
00233 from_degrees(-pose[3]+180+g_pitch_bias),
00234 from_degrees(-pose[4]+ g_yaw_bias )
00235 );
00236
00237 geometry_msgs::PointStamped head_point;
00238 geometry_msgs::PointStamped head_point_transformed;
00239
00240 head_point.header = pose_msg.header;
00241
00242 head_point.point.x = pose[0]/1000;
00243 head_point.point.y = pose[1]/1000;
00244 head_point.point.z = pose[2]/1000;
00245
00246 try {
00247 listener->waitForTransform(head_point.header.frame_id, g_head_target_frame, ros::Time::now(), ros::Duration(2.0));
00248 listener->transformPoint(g_head_target_frame, head_point, head_point_transformed);
00249 } catch(tf::TransformException ex) {
00250 ROS_WARN(
00251 "Transform exception, when transforming point from %s to %s\ndropping pose (don't worry, this is probably ok)",
00252 head_point.header.frame_id.c_str(), g_head_target_frame.c_str());
00253 ROS_WARN("Exception was %s", ex.what());
00254 return;
00255 }
00256
00257 tf::Transform trans;
00258
00259 pose_msg.pose.position = head_point_transformed.point;
00260 pose_msg.header.frame_id = head_point_transformed.header.frame_id;
00261
00262 pose_msg.pose.orientation.x = q.x();
00263 pose_msg.pose.orientation.y = q.y();
00264 pose_msg.pose.orientation.z = q.z();
00265 pose_msg.pose.orientation.w = q.w();
00266
00267 trans.setOrigin(tf::Vector3(
00268 pose_msg.pose.position.x,
00269 pose_msg.pose.position.y,
00270 pose_msg.pose.position.z
00271 ));
00272 trans.setRotation(q);
00273 g_transform = tf::StampedTransform(trans, pose_msg.header.stamp, pose_msg.header.frame_id, "head_origin");
00274
00275 g_transform_ready = true;
00276 pose_msg.header.stamp = ros::Time::now();
00277 geometry_msgs::PoseStamped zero_pose;
00278 zero_pose.header.frame_id = "head_origin";
00279 zero_pose.header.stamp = ros::Time::now();
00280 zero_pose.pose.orientation.w = 1;
00281
00282 pose_pub.publish(zero_pose);
00283 }
00284 }
00285
00286 int main(int argc, char* argv[])
00287 {
00288 ros::init(argc, argv, "head_pose_estimator");
00289 ros::NodeHandle nh;
00290
00291 listener = new tf::TransformListener();
00292 broadcaster = new tf::TransformBroadcaster();
00293
00294 image_transport::ImageTransport it(nh);
00295 ros::Subscriber cloud_sub = nh.subscribe<sensor_msgs::PointCloud2>("cloud", 1, cloudCallback);
00296 ros::Subscriber face_pos_sub = nh.subscribe<people_msgs::PositionMeasurementArray>("/face_detector/people_tracker_measurements_array", 1, peopleCallback);
00297
00298 pose_pub = nh.advertise<geometry_msgs::PoseStamped>("head_pose", 1);
00299
00300 loadConfig();
00301 ROS_INFO("tree path: %s", g_treepath.c_str());
00302 if( !estimator.loadForest(g_treepath.c_str(), g_ntrees) ){
00303 ROS_ERROR("could not read forest!");
00304 exit(-1);
00305 }
00306
00307 ros::Rate rate(20);
00308 while(ros::ok()) {
00309 if(g_transform_ready) {
00310 g_transform.stamp_ = ros::Time::now() + ros::Duration(1.0);
00311 broadcaster->sendTransform(g_transform);
00312 }
00313 ros::spinOnce();
00314 rate.sleep();
00315 }
00316 return 0;
00317 }