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 #include <boost/thread/thread.hpp>
00037 #include <boost/thread/mutex.hpp>
00038 #include <boost/thread/condition.hpp>
00039
00040 #include <ros/ros.h>
00041 #include <tf/transform_listener.h>
00042 #include <sensor_msgs/PointCloud.h>
00043 #include <mapping_msgs/PolygonalMap.h>
00044 #include <body_msgs/Hands.h>
00045 #include <sensor_msgs/point_cloud_conversion.h>
00046 #include <pcl_tools/pcl_utils.h>
00047 #include <nnn/nnn.hpp>
00048 #include <pcl_tools/segfast.hpp>
00049
00050
00051 #include "pcl/io/pcd_io.h"
00052 #include "pcl/point_types.h"
00053 #include <pcl/ModelCoefficients.h>
00054
00055 #include <pcl/io/pcd_io.h>
00056 #include <pcl/point_types.h>
00057
00058 #include <pcl/features/normal_3d.h>
00059
00060 #include <pcl/filters/extract_indices.h>
00061 #include <pcl/filters/passthrough.h>
00062
00063 #include <pcl/sample_consensus/method_types.h>
00064 #include <pcl/sample_consensus/model_types.h>
00065 #include <pcl/segmentation/sac_segmentation.h>
00066
00067
00068 class TimeEvaluator{
00069 timeval tmark;
00070 std::vector<double> times;
00071 std::vector<std::string> eventnames;
00072 std::string name;
00073
00074
00075 public:
00076 TimeEvaluator(std::string _name="Time Evaluator"){
00077 name=_name;
00078
00079
00080 gettimeofday(&tmark, NULL);
00081
00082 }
00083
00084 void mark(std::string _name=""){
00085
00086 if(_name.size())
00087 eventnames.push_back(_name);
00088 else{
00089 int count=eventnames.size();
00090 char tname[10];
00091 sprintf(tname,"E%d",count);
00092 eventnames.push_back(std::string(tname));
00093 }
00094
00095 struct timeval tv;
00096 gettimeofday(&tv, NULL);
00097 times.push_back((double)(tv.tv_sec-tmark.tv_sec) + (tv.tv_usec-tmark.tv_usec)/1000000.0);
00098 }
00099
00100 void print(){
00101 std::cout<<name;
00102 for(uint i=0;i<times.size();++i)
00103 std::cout<<" "<<eventnames[i]<<": "<< std::setprecision (5) << times[i];
00104 std::cout<<std::endl;
00105 }
00106
00107
00108
00109
00110 };
00111
00112
00113
00114 float gdist(pcl::PointXYZ pt, Eigen::Vector4f v){
00115 return sqrt((pt.x-v(0))*(pt.x-v(0))+(pt.y-v(1))*(pt.y-v(1))+(pt.z-v(2))*(pt.z-v(2)));
00116 }
00117
00118 void flipvec(Eigen::Vector4f palm, Eigen::Vector4f fcentroid,Eigen::Vector4f &dir ){
00119 if((fcentroid-palm).dot(dir) <0)
00120 dir=dir*-1.0;
00121
00122 }
00123
00124 geometry_msgs::Point32 eigenToMsgPoint32(Eigen::Vector4f v){
00125 geometry_msgs::Point32 p;
00126 p.x=v(0); p.y=v(1); p.z=v(2);
00127 return p;
00128 }
00129 geometry_msgs::Point eigenToMsgPoint(Eigen::Vector4f v){
00130 geometry_msgs::Point p;
00131 p.x=v(0); p.y=v(1); p.z=v(2);
00132 return p;
00133 }
00134
00135 pcl::PointXYZ eigenToPclPoint(Eigen::Vector4f v){
00136 pcl::PointXYZ p;
00137 p.x=v(0); p.y=v(1); p.z=v(2);
00138 return p;
00139 }
00140
00141
00142
00143
00144
00145
00146 bool findNearbyPts(pcl::PointCloud<pcl::PointXYZ> &cloud, std::vector<int> &cloudpts, Eigen::Vector4f ¢roid){
00147 std::vector<int> inds(cloud.size(),1);
00148
00149 std::vector<int> nearpts;
00150 std::vector<int> temp;
00151 for(uint i=0;i<cloudpts.size(); ++i) inds[cloudpts[i]]=-1;
00152 for(uint i=0;i<cloudpts.size(); ++i){
00153 if(inds[cloudpts[i]]==-1){
00154 NNN(cloud,cloud.points[cloudpts[i]],temp, .05);
00155 mapping_msgs::PolygonalMap pmap;
00156 geometry_msgs::Polygon p;
00157 for(uint j=0;j<temp.size(); ++j){
00158 if(inds[temp[j]]==1){
00159 nearpts.push_back(temp[j]);
00160 inds[temp[j]]=2;
00161 }
00162 else
00163 inds[temp[j]]=-2;
00164 }
00165 }
00166 }
00167
00168
00169 if(nearpts.size())
00170
00171 pcl::compute3DCentroid(cloud,nearpts,centroid);
00172 else
00173 return false;
00174 return true;
00175 }
00176
00177
00178
00179 bool getNearBlobs2(pcl::PointCloud<pcl::PointXYZ> &cloud, std::vector<pcl::PointCloud<pcl::PointXYZ> > &clouds, std::vector< Eigen::Vector4f> &nearcents ){
00180 pcl::PointCloud<pcl::PointXYZ> cloudout;
00181 pcl::PointXYZ pt,pt1,pt2; pt.x=pt.y=pt.z=0;
00182 std::vector<int> inds1,inds2,inds3(cloud.size(),1);
00183 std::vector<float> dists;
00184 Eigen::Vector4f centroid1,centroid2,nearcent1;
00185
00186
00187
00188 TimeEvaluator te("getNearBlobs2: ");
00189
00190
00191
00192 NNN(cloud,pt,inds1,dists, 1.0);
00193 int ind=0; double smallestdist;
00194 for(uint i=0;i<dists.size(); ++i){
00195 if(dists[i]<smallestdist || i==0 ){
00196 ind=inds1[i];
00197 smallestdist=dists[i];
00198 }
00199 }
00200 smallestdist=sqrt(smallestdist);
00201 pt1=cloud.points[ind];
00202
00203 te.mark("closest pt");
00204
00205
00206 NNN(cloud,pt1,inds2, .1);
00207
00208
00209 if(inds2.size() < 100){
00210 std::cout<<"very few points ";
00211 return false;
00212 }
00213
00214 te.mark("nearby pts");
00215
00216
00217
00218
00219
00220 pcl::compute3DCentroid(cloud,inds2,centroid1);
00221 pt2.x=centroid1(0); pt2.y=centroid1(1)-.02; pt2.z=centroid1(2);
00222 NNN(cloud,pt2,inds2, .1);
00223
00224
00225 std::vector<int> temp;
00226 NNN(cloud,pt2,temp, .15);
00227
00228 if(!findNearbyPts(cloud,temp,nearcent1))
00229 return false;
00230
00231
00232 te.mark("find arm");
00233
00234 pcl::compute3DCentroid(cloud,inds2,centroid1);
00235 pt2.x=centroid1(0); pt2.y=centroid1(1)-.01; pt2.z=centroid1(2);
00236 NNN(cloud,pt2,inds2, .1);
00237
00238
00239 getSubCloud(cloud,inds2,cloudout);
00240
00241
00242 te.mark("save sub ");
00243
00244
00245
00246
00247 for(uint i=0;i<inds2.size(); ++i) inds3[inds2[i]]=0;
00248 pcl::compute3DCentroid(cloudout,centroid1);
00249 int s1,s2=0;
00250 s1=inds2.size();
00251
00252 NNN(cloud,pt,inds2, centroid1.norm());
00253 for(uint i=0;i<inds2.size(); ++i){
00254 if(inds3[inds2[i]]) ++s2;
00255 }
00256 if(((float)s2)/((float)s1) > .3){
00257 std::cout<<"No hands detected ";
00258 return false;
00259 }
00260
00261
00262 te.mark("classify ");
00263
00264
00265 clouds.push_back(cloudout);
00266
00267 nearcents.push_back(nearcent1);
00268
00269
00270
00271 smallestdist+=.3;
00272 smallestdist*=smallestdist;
00273
00274 bool foundpt=false;
00275 for(uint i=0;i<dists.size(); ++i){
00276
00277
00278
00279
00280
00281 if(dists[i]<smallestdist && inds3[i] && gdist(cloud.points[inds1[i]],centroid1) > .2 && gdist(cloud.points[inds1[i]],nearcent1) >.3){
00282
00283
00284 ind=inds1[i];
00285 smallestdist=dists[i];
00286 foundpt=true;
00287 }
00288 }
00289
00290 if(foundpt){
00291
00292 pcl::PointCloud<pcl::PointXYZ> cloudout2;
00293 NNN(cloud,cloud.points[ind],inds2, .1);
00294 pcl::compute3DCentroid(cloud,inds2,centroid2);
00295 pt2.x=centroid2(0); pt2.y=centroid2(1)-.02; pt2.z=centroid2(2);
00296 NNN(cloud,pt2,inds2, .1);
00297 pcl::compute3DCentroid(cloud,inds2,centroid2);
00298 pt2.x=centroid2(0); pt2.y=centroid2(1)-.01; pt2.z=centroid2(2);
00299 NNN(cloud,pt2,inds2, .1);
00300
00301
00302 if(inds2.size()<100) return true;
00303
00304
00305
00306 for(uint i=0;i<inds2.size(); ++i)
00307 if(inds3[inds2[i]]==0)
00308 return true;
00309
00310 NNN(cloud,pt2,temp, .15);
00311
00312 if(!findNearbyPts(cloud,temp,nearcent1))
00313 return true;
00314
00315 getSubCloud(cloud,inds2,cloudout2);
00316 clouds.push_back(cloudout2);
00317 nearcents.push_back(nearcent1);
00318
00319 }
00320
00321
00322
00323 return true;
00324
00325 }
00326
00327
00328 class HandDetector
00329 {
00330
00331 private:
00332 ros::NodeHandle n_;
00333 ros::Publisher cloudpub_[2],handspub_;
00334 ros::Subscriber sub_;
00335 std::string fixedframe;
00336
00337 public:
00338
00339 HandDetector()
00340 {
00341 handspub_ = n_.advertise<body_msgs::Hands> ("hands", 1);
00342 cloudpub_[0] = n_.advertise<sensor_msgs::PointCloud2> ("hand0_cloud", 1);
00343 cloudpub_[1] = n_.advertise<sensor_msgs::PointCloud2> ("hand1_cloud", 1);
00344 sub_=n_.subscribe("/camera/rgb/points", 1, &HandDetector::cloudcb, this);
00345
00346 }
00347
00348
00349
00350
00351 void makeHand(pcl::PointCloud<pcl::PointXYZ> &cloud,Eigen::Vector4f &_arm, body_msgs::Hand &handmsg){
00352 Eigen::Vector4f centroid;
00353 handmsg.thumb=-1;
00354 handmsg.stamp=cloud.header.stamp;
00355 pcl::compute3DCentroid (cloud, centroid);
00356 handmsg.arm=eigenToMsgPoint(_arm);
00357 handmsg.state="unprocessed";
00358 handmsg.palm.translation.x=centroid(0);
00359 handmsg.palm.translation.y=centroid(1);
00360 handmsg.palm.translation.z=centroid(2);
00361 pcl::toROSMsg(cloud,handmsg.handcloud);
00362 handmsg.handcloud.header=cloud.header;
00363
00364 }
00365
00366
00367 void cloudcb(const sensor_msgs::PointCloud2ConstPtr &scan){
00368 timeval t0=g_tick();
00369 sensor_msgs::PointCloud2 cloud2;
00370 pcl::PointCloud<pcl::PointXYZ> cloud;
00371 pcl::fromROSMsg(*scan,cloud);
00372 std::vector<Eigen::Vector4f> arm_center;
00373 std::vector<pcl::PointCloud<pcl::PointXYZ> > initialclouds;
00374 std::cout<<" pre blob time: "<<g_tock(t0)<<" ";
00375 if(!getNearBlobs2(cloud,initialclouds,arm_center)){
00376 std::cout<<" no hands detected "<<std::endl;
00377 return;
00378 }
00379 std::cout<<" blob time: "<<g_tock(t0)<<" ";
00380
00381 body_msgs::Hand hand1,hand2;
00382 body_msgs::Hands hands;
00383
00384
00385 if(initialclouds.size()==1){
00386 makeHand(initialclouds[0],arm_center[0],hand1);
00387 hands.hands.push_back(hand1);
00388 cloudpub_[0].publish(hand1.handcloud);
00389 handspub_.publish(hands);
00390 }
00391
00392
00393 if(initialclouds.size()==2){
00394 makeHand(initialclouds[0],arm_center[0],hand1);
00395 makeHand(initialclouds[1],arm_center[1],hand2);
00396
00397 if(hand1.palm.translation.x < hand2.palm.translation.x){
00398 hands.hands.push_back(hand1);
00399 hands.hands.push_back(hand2);
00400 }
00401 else{
00402 hands.hands.push_back(hand2);
00403 hands.hands.push_back(hand1);
00404 }
00405 cloudpub_[0].publish(hands.hands[0].handcloud);
00406 cloudpub_[1].publish(hands.hands[1].handcloud);
00407 handspub_.publish(hands);
00408 }
00409
00410
00411 std::cout<<" total time: "<<g_tock(t0)<<std::endl;
00412 }
00413
00414 } ;
00415
00416
00417
00418
00419 int main(int argc, char **argv)
00420 {
00421 ros::init(argc, argv, "hand_detector");
00422 ros::NodeHandle n;
00423 HandDetector detector;
00424 ros::spin();
00425 return 0;
00426 }