zyonz_tof_color_driver_node.cpp
Go to the documentation of this file.
00001 #include "zyonz_tof_color_driver_node.h"
00002 #include <string>
00003 #include <iostream>
00004 
00005 //to save the image_callback
00006 #include <opencv/cv.h>
00007 #include <opencv/highgui.h>
00008 #include <cv_bridge/CvBridge.h>
00009 #include <boost/format.hpp>
00010 
00011 ZyonzTofColorDriverNode::ZyonzTofColorDriverNode(ros::NodeHandle &nh) : iri_base_driver::IriBaseNodeDriver<ZyonzTofColorDriver>(nh),    
00012 depth_sent_ (true), rgb_sent_ (true), intens_sent_ (true), zbuffer_threshold_(20), saveFile (false), saveFileCounter (0)
00013 {
00014   //init class attributes if necessary
00015   //this->loop_rate_ = 2;//in [Hz]
00016   /*
00017   std::string imageTopic;
00018   this->private_node_handle_.param<std::string>("image", imageTopic, "a");
00019   ROS_INFO("Image initializad at %d %s",imageTopic.length(),imageTopic.c_str());
00020   */
00021   /*
00022   if (ros::param::has("image"))
00023   {
00024     ros::param::get("image", image);
00025     ROS_INFO("Image initializad at %s",image.c_str());
00026   }
00027   */
00028   /*
00029   nh.getParam("/image", imageTopic);
00030   ROS_INFO("Image initializad at %d %s",imageTopic.length(),imageTopic.c_str());
00031   */
00032   
00033   //matrius de calibratge
00034   //TODO: llegir-les d'un fitxer
00035 //  K_<<822.24782,0,313.08856,0,822.34043,255.75672,0,0,1;
00036 //  K_<<1618.29, 0, 625.218,0 ,1618.29, 502.417,0,0,1; //NOVA
00037 //CAMCUBE_AQUESTA K_<< 1580,0,604.43,0,1585.13,519.16,0,0,1;//NOVA2
00038   //passa punts de la tof a la RGB
00039   //Aquesta és l'original, on hi havia una rotacio per culpa dels SR de les cameres
00040 //  P_<<-0.99995,-0.00912,-0.000585,-1.61384,0.00913,-0.99983,-0.01564,55.924639,-0.00044,-0.01564,0.99987,33.97095,0,0,0,1;
00041 //  P_<<0.999739, 0.0227623, 0.00193176, -7.13658, -0.0226342, 0.998442, -0.0510053, 66.2559, -0.00308975, 0.0509483, 0.998697,30.4039,0,0,0,1; //NOVA
00042 //  P_<<0.999739, 0.0227623, 0.00193176, -7.13658, -0.0226342, 0.998442, -0.0510053, 73.2559, -0.00308975, 0.0509483, 0.998697,36.4039,0,0,0,1; //NOVA
00043 //CAMCUBE_AQUESTA P_ << 1, 0, 0, -0.3921, 0, 1, 0, 59.2096, 0, 0, 1,20.8921,0,0,0,1;//NOVA2
00044 //  P_<<1, 0, 0, -7.13658, 0, 1, 0, 66.2559, 0, 0, 1,30.4039,0,0,0,1; 
00045 
00046 //  P_<<-0.99995,-0.00912,-0.000585,-0.00161384,0.00913,-0.99983,-0.01564,0.055924639,-0.00044,-0.01564,0.99987,0.03397095,0,0,0,1;
00047   kernel_size_=3;
00048   
00049   //CAMBOARD + rgb640x480
00050   
00051   K_<< 791.241, 0, 323.613, 0, 791.241, 266.511, 0, 0, 1;  
00052   P_ << 0.987, -0.028, -0.156, 54.0775, 0.0322, 0.999, 0.0209, 2.0674, 0.156, -0.0257, 0.988, 18.3983, 0, 0, 0, 1;
00053   // [init publishers]
00054   this->cloud2_raw_publisher_ = this->public_node_handle_.advertise<sensor_msgs::PointCloud2>("cloud2_raw", 10);
00055   
00056   // [init subscribers]
00057   this->input_intens_subscriber_ = this->public_node_handle_.subscribe("input_intensity", 5, &ZyonzTofColorDriverNode::input_intens_callback, this);
00058   //TODO s'ha de fer servir el ImageTransport!!
00059   //image_transport::ImageTransport it(nh);
00060 
00061   this->image_subscriber_ = this->public_node_handle_.subscribe("input_color", 10, &ZyonzTofColorDriverNode::image_callback, this);
00062   this->pointCloud_subscriber_ = this->public_node_handle_.subscribe("input_pointcloud", 10, &ZyonzTofColorDriverNode::pointCloud_callback, this);
00063   
00064   // [init services]
00065   this->saveImage_server_ = this->public_node_handle_.advertiseService("saveImage", &ZyonzTofColorDriverNode::saveImageCallback, this);
00066   
00067   // [init clients]
00068   
00069   // [init action servers]
00070   
00071   // [init action clients]
00072   
00073   
00074   
00075 }
00076 
00077 void ZyonzTofColorDriverNode::mainNodeThread(void)
00078 {
00079   //lock access to driver if necessary
00080   this->driver_.lock();
00081 
00082   // [fill msg Header if necessary]
00083   //<publisher_name>.header.stamp = ros::Time::now();
00084   //<publisher_name>.header.frame_id = "<publisher_topic_name>";
00085 
00086   // [fill msg structures]
00087   //this->PointCloud2_msg.data = my_var;
00088   
00089   // [fill srv structure and make request to the server]
00090   
00091   // [fill action structure and make request to the action server]
00092 
00093   // [publish messages]
00094 //  this->cloud2_raw_publisher_.publish(this->PointCloud2_msg_);
00095 
00096   //unlock access to driver if previously blocked
00097   this->driver_.unlock();  
00098 }
00099 
00100 /*  [subscriber callbacks] */
00101 void ZyonzTofColorDriverNode::input_intens_callback(const sensor_msgs::Image::ConstPtr& msg) 
00102 { 
00103 //  ROS_INFO("ZyonzTofColorDriverNode::input_intens_callback: New Message Received"); 
00104 
00105   //use appropiate mutex to shared variables if necessary 
00106   //this->driver_.lock(); 
00107   //this->input_intens_mutex_.enter(); 
00108 
00109   //std::cout << msg->data << std::endl; 
00110 
00111   //unlock previously blocked shared variables 
00112   //this->driver_.unlock(); 
00113   //this->input_intens_mutex_.exit();   
00114   
00115   intens_image_ = msg;
00116   intens_sent_ = false;
00117   processRgbAndDepth ();
00118 }
00119 void ZyonzTofColorDriverNode::image_callback(const sensor_msgs::Image::ConstPtr& msg) 
00120 { 
00121   //lock member message variable 
00122   //this->image_mutex_.enter(); 
00123 
00124   //lock access to driver if necessary 
00125   //this->driver_.lock(); 
00126 
00127   //std::cout << msg->data << std::endl; 
00128 
00129   //unlock access to driver if previously blocked 
00130   //this->driver_.unlock(); 
00131 
00132   //unlock member message variable 
00133   //this->image_mutex_.exit(); 
00134   rgb_image_ = msg;
00135   rgb_sent_ = false;
00136   processRgbAndDepth ();
00137 }
00138 void ZyonzTofColorDriverNode::pointCloud_callback(const sensor_msgs::PointCloud2::ConstPtr& msg) 
00139 { 
00140   //lock member message variable 
00141   //this->pointCloud_mutex_.enter(); 
00142 
00143   //lock access to driver if necessary 
00144   //this->driver_.lock(); 
00145 
00146   //std::cout << msg->data << std::endl; 
00147 
00148   //unlock access to driver if previously blocked 
00149   //this->driver_.unlock(); 
00150 
00151   //unlock member message variable 
00152   //this->pointCloud_mutex_.exit(); 
00153   cloud2_ = msg;
00154   depth_sent_ = false;
00155   processRgbAndDepth ();
00156 
00157 }
00158 
00159 
00160 void ZyonzTofColorDriverNode::processRgbAndDepth() {
00161   if ((!rgb_sent_) && (!depth_sent_) && (!intens_sent_)){
00162     //  MatrixXf Z_buffer_=MatrixXf::Zero(cloud2_->width,cloud2_->height);
00163     MatrixXf Z_buffer_=MatrixXf::Zero(rgb_image_->width,rgb_image_->height);
00164     
00165     //build the message if someone is listening
00166     if (cloud2_raw_publisher_.getNumSubscribers () > 0) 
00167     {
00168       ROS_DEBUG("Image Size %d %d %d",rgb_image_->width,rgb_image_->height,rgb_image_->step);
00169       ROS_DEBUG("Cloud Size %d %d",cloud2_->width,cloud2_->height);
00170       
00171       //initialize a pointcloud
00172       //TODO: do it in the constructor?
00173       //TODO: maybe we can reuse the same message instead of making a copy?
00174       PointCloud2_msg_.height         = cloud2_->height;
00175       PointCloud2_msg_.width          = cloud2_->width;
00176       PointCloud2_msg_.fields.resize (4);
00177       PointCloud2_msg_.fields[0].name = "x";
00178       PointCloud2_msg_.fields[1].name = "y";
00179       PointCloud2_msg_.fields[2].name = "z";
00180       PointCloud2_msg_.fields[3].name = "rgb";
00181       PointCloud2_msg_.header.stamp   = cloud2_->header.stamp;
00182       PointCloud2_msg_.header.frame_id = std::string ("/colorcam_frame");//cloud2_->header.frame_id;
00183       // Set all the fields types accordingly
00184       int offset = 0;
00185       for (size_t s = 0; s < PointCloud2_msg_.fields.size (); ++s, offset += 4)
00186       {
00187         PointCloud2_msg_.fields[s].offset   = offset;
00188         PointCloud2_msg_.fields[s].count    = 1;
00189         PointCloud2_msg_.fields[s].datatype = sensor_msgs::PointField::FLOAT32;
00190       }
00191       
00192       PointCloud2_msg_.point_step = offset;
00193       PointCloud2_msg_.row_step   = PointCloud2_msg_.point_step * PointCloud2_msg_.width;
00194       PointCloud2_msg_.data.resize (PointCloud2_msg_.row_step   * PointCloud2_msg_.height);
00195       PointCloud2_msg_.is_dense   = true; 
00196       
00197       //build the Z_buffer
00198       //TODO: fer una funció que projecti i no replicar el codi!!
00199       for (uint8_t i=0+kernel_size_;i<cloud2_->width-kernel_size_;i++)
00200       {
00201         for (uint8_t j=0+kernel_size_;j<cloud2_->height-kernel_size_;j++)
00202         {
00203           Vector4f point3D;
00204           int index2 = (i)*cloud2_->width +(j);
00205           float *pstep2 = (float*)&cloud2_->data[(index2) * cloud2_->point_step];
00206           //la matriu de calibratge esta en mm....
00207           
00208           point3D(0)=pstep2[0]*1000;
00209           point3D(1)=pstep2[1]*1000;
00210           point3D(2)=pstep2[2]*1000;
00211           point3D(3)=1.0;
00212           //std::cout << "point3D\n" << point3D<<std::endl;
00213           
00214           // put depth point onto rgb frame
00215           Vector4f tmp=P_*point3D;        
00216           // project depth point on the camera
00217           MatrixXf Kextended(3,4);
00218           //std::cout << "Kextended\n" << Kextended<<std::endl; 
00219           Kextended<<K_,Vector3f::Zero(3);
00220           
00221           Vector3f projectedPoint=Kextended*tmp;
00222           //std::cout << "projectedPoint\n" << projectedPoint<<std::endl; 
00223           
00224           //normalize
00225           int u=(int)(projectedPoint(0)/projectedPoint(2));
00226           int v=(int)(projectedPoint(1)/projectedPoint(2));
00227           //CAL CONSTRUIR PRIMER EL ZBUFFER
00228           //SI no quan descobrim un punt mal estiquetat de color no es pot tornar enrere!
00229           // El Z_buffer conté les profunditats dels punts en SR_rgb. Ha de tenir mida rgb ja que cal projectar els punts!
00230           //    if ((Z_buffer_(i,j)==0.0) ||(tmp(2)<Z_buffer_(i,j))) 
00231           if ((u>kernel_size_) && (u < (int)rgb_image_->width-kernel_size_) && (v>kernel_size_) && (v < (int)rgb_image_->height-kernel_size_)) 
00232           {
00233             if ((Z_buffer_(u,v)==0.0) ||(tmp(2)<Z_buffer_(u,v))) 
00234             {
00235               //              Z_buffer_(i,j)=tmp(2);
00236               //          Z_buffer_.block(i-kernel_size_,j-kernel_size_,2*kernel_size_+1,2*kernel_size_+1)=  MatrixXf::Constant(2*kernel_size_+1,2*kernel_size_+1, tmp(2));
00237               Z_buffer_.block(u-kernel_size_,v-kernel_size_,2*kernel_size_+1,2*kernel_size_+1)=  MatrixXf::Constant(2*kernel_size_+1,2*kernel_size_+1, tmp(2));
00238             }
00239           }
00240         }
00241       }
00242       
00243       //build the colored pointcloud
00244       for (uint i=0+kernel_size_;i<cloud2_->width-kernel_size_;i++)
00245       {
00246         for (uint j=0+kernel_size_;j<cloud2_->height-kernel_size_;j++)
00247         {
00248           Vector4f point3D;
00249           //int index2 = (i)*cloud2_->width +(j);
00250           int index2 = (j)*cloud2_->width +(i);
00251           float *pstep = (float*)&PointCloud2_msg_.data[(index2) * PointCloud2_msg_.point_step];
00252           float *pstep2 = (float*)&cloud2_->data[(index2) * cloud2_->point_step];
00253           
00254           //ATENTION!!!! Temporally save the original points
00255           if (saveFile) 
00256             outFile<<pstep2[0]<<" "<<pstep2[1]<<" "<<pstep2[2]<<" "<<0<<" "<<0<<" ";
00257           
00258           //if ((i==100)&&(j==100))
00259           //  std::cout << "point3D" << pstep2[0]<<" "<<pstep2[1]<<" "<<pstep2[2]<<std::endl;
00260           
00261           //la matriu de calibratge esta en mm....
00262             point3D(0)=pstep2[0]*1000;
00263             point3D(1)=pstep2[1]*1000;
00264             point3D(2)=pstep2[2]*1000;
00265             point3D(3)=1.0;
00266             //std::cout << "point3D\n" << point3D<<std::endl;
00267             
00268             // put depth point onto rgb frame
00269             Vector4f tmp=P_*point3D;    
00270             //  Vector4f tmp=point3D;   
00271             
00272             //copy data in the final pointcloud
00273             //la matriu de calibratge esta en mm.... pero el point cloud en metres
00274             pstep[0] =  tmp(0)/1000;
00275             pstep[1] =  tmp(1)/1000;
00276             pstep[2] =  tmp(2)/1000;
00277             //std::cout << "tmp\n" << tmp<<std::endl;        
00278             // project depth point on the camera
00279             MatrixXf Kextended(3,4);
00280             //std::cout << "Kextended\n" << Kextended<<std::endl; 
00281             Kextended<<K_,Vector3f::Zero(3);
00282             
00283             Vector3f projectedPoint=Kextended*tmp;
00284             //std::cout << "projectedPoint\n" << projectedPoint<<std::endl; 
00285             
00286             //normalize
00287             int u=(int)(projectedPoint(0)/projectedPoint(2));
00288             int v=(int)(projectedPoint(1)/projectedPoint(2));
00289             // if (saveFile) 
00290             //   outFile<<pstep[0]<<" "<<pstep[1]<<" "<<pstep[2]<<" "<<u<<" "<<v<<" ";
00291             //std::cout << "u,v\n" << u<<" "<<v<<std::endl;
00292             if ((u>kernel_size_) && (u < (int)rgb_image_->width-kernel_size_) && (v>kernel_size_) && (v<(int)rgb_image_->height-kernel_size_)) 
00293             {
00294               //check the Z_buffer
00295               //            if (((tmp(2)-zbuffer_threshold_)<Z_buffer_(i,j)) && (Z_buffer_(i,j) !=0 ))
00296               if (((tmp(2)-zbuffer_threshold_)<Z_buffer_(u,v)) && (Z_buffer_(u,v) !=0 ))
00297               {
00298                 int rgb_index = v*rgb_image_->step +u*3;
00299                 //            int8_t r = rgb_image_->data[(rgb_index)];//imagestep[0];
00300                 //            int8_t g = rgb_image_->data[(rgb_index)+1];//imagestep[1];
00301                 //            int8_t b = rgb_image_->data[(rgb_index)+2];//imagestep[2];
00302                 //            // Fill in RGB
00303                 int32_t rgb_packed = 0;
00304                 //            rgb_packed = (r << 16) | (g << 8) | b;
00305                 //rgb_packed = ((int8_t)rgb_image_->data[(rgb_index)] << 16) | ((int8_t)rgb_image_->data[(rgb_index)+1] <<8 ) | (int8_t)rgb_image_->data[(rgb_index)+2];
00306                 rgb_packed = (rgb_image_->data[(rgb_index)] << 16) | (rgb_image_->data[(rgb_index)+1] <<8 ) | rgb_image_->data[(rgb_index)+2];
00307                 memcpy(&pstep[3], &rgb_packed, sizeof(int32_t));
00308                 if (saveFile) 
00309                   outFile<<"0"<<std::endl;
00310               } else {
00311                 //std::cout<<"ZBUFFER "<<Z_buffer_(i,j)<<" tmp " << tmp(2) <<std::endl;
00312                 pstep[3] =  (0xff << 16) | (0x00 << 8) | 0x00; //red
00313                 if (saveFile) 
00314                   outFile<<"1"<<std::endl;
00315               }
00316             } else {
00317               int32_t rgb_packed = 0;
00318               memcpy(&pstep[3], &rgb_packed, sizeof(int32_t));
00319               //TODO: this is really out fo range!!!
00320               if (saveFile) outFile<<"0"<<std::endl;
00321             }
00322         }
00323       }   
00324       
00325       this->cloud2_raw_publisher_.publish(this->PointCloud2_msg_);
00326       
00327       
00328     }
00329     
00330     
00331     
00332     rgb_sent_   = true;
00333     depth_sent_ = true;
00334     intens_sent_ = true;
00335     
00336     if (saveFile) {
00337       outFile.close();
00338       sensor_msgs::CvBridge g_bridge;
00339       boost::format g_format;  
00340       g_format.parse("outRGB%04i.%s");
00341       if (g_bridge.fromImage(*rgb_image_, "bgr8")) {
00342         IplImage *image = g_bridge.toIpl();
00343         if (image) {
00344           std::string filename = (g_format % saveFileCounter % "png").str();
00345           cvSaveImage(filename.c_str(), image);
00346           ROS_INFO("Saved image %s", filename.c_str());
00347           
00348         } else {
00349           ROS_WARN("Couldn't save image, no data!");
00350         }
00351       } else {
00352         ROS_ERROR("Unable to convert %s image to bgr8", rgb_image_->encoding.c_str());
00353       }
00354       
00355       //and the intensity    
00356       g_format.parse("outINTENS%04i.%s");
00357       
00358       if (g_bridge.fromImage(*intens_image_, "bgr8")) {
00359         IplImage *image = g_bridge.toIpl();
00360         if (image) {
00361           std::string filename = (g_format % saveFileCounter % "png").str();
00362           cvSaveImage(filename.c_str(), image);
00363           ROS_INFO("Saved image %s", filename.c_str());
00364         } else {
00365           ROS_WARN("Couldn't save image, no data!");
00366         }
00367       }
00368       else {
00369         ROS_ERROR("Unable to convert %s image to bgr8", rgb_image_->encoding.c_str());
00370       }      
00371       
00372       saveFile = false; 
00373     }
00374   }
00375 }
00376 /*  [service callbacks] */
00377 bool ZyonzTofColorDriverNode::saveImageCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res) 
00378 { 
00379   //TODO: save the temporal variables and save monolitically here!!!
00380   //Take care with sichronization: both images should be the really used for computations!
00381 
00382   saveFileCounter++; //TODO: controlar el desbordament!!
00383   fileName="outCamCube";
00384   std::stringstream ss;
00385   ss << saveFileCounter;
00386   fileName+=ss.str(); // a vegades c++ no posa les coses f?cils!!!!
00387   fileName+=".m";
00388   //prepara el fitxer de profunditats
00389   outFile.open(fileName.c_str());   
00390   if( !outFile ) {
00391     ROS_INFO("ZyonzTofColorDriverNode::saveImageCallback: Error obrint el fitxer de sortida!");
00392     saveFile=false;
00393   } else {
00394     outFile<<"% X Y Z u v occlusion "<<std::endl;
00395     saveFile=true;
00396   }
00397 
00398   ROS_INFO("ZyonzTofColorDriverNode::saveImageCallback: New Request Received! %s", fileName.c_str()); 
00399 
00400 //use appropiate mutex to shared variables if necessary 
00401   //this->driver_.lock(); 
00402   //this->saveImage_mutex_.enter(); 
00403 
00404   
00405   
00406   //if(this->driver_.isRunning()) 
00407   //{ 
00408     //ROS_INFO("ZyonzTofColorDriverNode::saveImageCallback: Processin New Request!"); 
00409     //do operations with req and output on res 
00410     //res.data2 = req.data1 + my_var; 
00411   //} 
00412   //else 
00413   //{ 
00414     //ROS_INFO("ZyonzTofColorDriverNode::saveImageCallback: ERROR: driver is not on run mode yet."); 
00415   //} 
00416 
00417   //unlock previously blocked shared variables 
00418   //this->driver_.unlock(); 
00419   //this->saveImage_mutex_.exit(); 
00420 
00421   return true; 
00422 }
00423 
00424 /*  [action callbacks] */
00425 
00426 /*  [action requests] */
00427 
00428 void ZyonzTofColorDriverNode::postNodeOpenHook(void)
00429 {
00430 }
00431 
00432 void ZyonzTofColorDriverNode::addNodeDiagnostics(void)
00433 {
00434 }
00435 
00436 void ZyonzTofColorDriverNode::addNodeOpenedTests(void)
00437 {
00438 }
00439 
00440 void ZyonzTofColorDriverNode::addNodeStoppedTests(void)
00441 {
00442 }
00443 
00444 void ZyonzTofColorDriverNode::addNodeRunningTests(void)
00445 {
00446 }
00447 
00448 void ZyonzTofColorDriverNode::reconfigureNodeHook(int level)
00449 {
00450 }
00451 
00452 ZyonzTofColorDriverNode::~ZyonzTofColorDriverNode()
00453 {
00454   // [free dynamic memory]
00455 }
00456 
00457 /* main function */
00458 int main(int argc,char *argv[])
00459 {
00460   return driver_base::main<ZyonzTofColorDriverNode>(argc,argv,"zyonz_tof_color_driver");
00461 }


zyonz_tof_color
Author(s): Guillem Alenyà - IRI Robotics Lab
autogenerated on Fri Dec 6 2013 21:08:56