openni_range_image_registration.cpp
Go to the documentation of this file.
00001 /* \author Bastian Steder */
00002 
00003 #include <iostream>
00004 using namespace std;
00005 #include <pcl/io/openni_grabber.h>
00006 #include "pcl/range_image/range_image_planar.h"
00007 #include "pcl/common/common_headers.h"
00008 #include "pcl/visualization/range_image_visualizer.h"
00009 #include "pcl/visualization/pcl_visualizer.h"
00010 #include "pcl/console/parse.h"
00011 #include <boost/filesystem.hpp> 
00012 
00013 using namespace pcl;
00014 using namespace pcl::visualization;
00015 
00016 std::string device_id = "#1";
00017 std::string output_prefix = "openni_icp";
00018 std::string dir_name;
00019 
00020 float angular_resolution = 0.5f;
00021 
00022 float size_factor = 1.0;
00023 
00024 int icp_search_radius_consecutive = 3;
00025 int icp_num_iterations_consecutive = 20;
00026 int icp_search_radius_keyframe = 1;
00027 int icp_num_iterations_keyframe = 10;
00028 float new_keyframe_overlap = 0.85;
00029 
00030 float maximum_range = -1.0f;
00031 
00032 int max_no_of_threads = 1;
00033 bool capture = false;
00034 
00035 bool show_color_image = 0,
00036      show_range_image = 1,
00037      show_registered_clouds = 1;
00038 
00039 boost::mutex image_mutex;
00040 pcl::PointCloud<pcl::PointXYZ>::ConstPtr point_cloud_ptr;
00041 boost::shared_ptr<openni_wrapper::DepthImage> depth_image_ptr;
00042 boost::shared_ptr<openni_wrapper::Image> color_image_ptr;
00043 
00044 bool received_new_image_pair = false,
00045      received_new_depth_data = false;
00046 
00047 int range_image_counter=0, key_frame_counter=0;
00048 
00049 struct EventHelper
00050 {
00051   void 
00052   depthAndColorCB (const boost::shared_ptr<openni_wrapper::Image>& color_image,
00053                    const boost::shared_ptr<openni_wrapper::DepthImage>& depth_image, float constant)
00054   {
00055     (void)constant;  // No warning
00056     if (!image_mutex.try_lock ())
00057       return;
00058     depth_image_ptr = depth_image;
00059     color_image_ptr = color_image;
00060     image_mutex.unlock ();
00061     received_new_image_pair = true;
00062   }
00063   
00064   void
00065   depth_image_cb (const boost::shared_ptr<openni_wrapper::DepthImage>& depth_image)
00066   {
00067     if (!image_mutex.try_lock ())
00068       return;
00069     depth_image_ptr = depth_image;
00070     image_mutex.unlock ();
00071     received_new_depth_data = true;
00072   }
00073 };
00074 
00075 Eigen::Affine3f last_pose, last_keyframe_pose, current_pose=Eigen::Affine3f::Identity();
00076 
00077 void
00078 saveFrame()
00079 {
00080   if (!capture)
00081     return;
00082   
00083   stringstream filename_stream;
00084   filename_stream << setfill('0')<<setw(6)<<key_frame_counter;
00085   
00086   std::string info_filename = dir_name+"/"+filename_stream.str()+"_info.txt";
00087   std::ofstream info_file(info_filename.c_str());
00088   
00089   std::string depth_image_filename = dir_name+"/"+filename_stream.str()+"_depth_image.dat";
00090   const unsigned short* depth_map = depth_image_ptr->getDepthMetaData().Data();
00091   int width_depth_image = depth_image_ptr->getWidth (), height_depth_image = depth_image_ptr->getHeight ();
00092   int depth_image_size = width_depth_image*height_depth_image*sizeof(*depth_map);
00093   std::ofstream depth_image_file(depth_image_filename.c_str());
00094   depth_image_file.write((const char*)depth_map, depth_image_size);
00095   depth_image_file.close();
00096   
00097   info_file << "depth_image_filename "<<getFilenameWithoutPath (depth_image_filename)<<"\n"
00098             << "time_stamp_depth_image "  << depth_image_ptr->getTimeStamp () << "\n"
00099             << "frame_id_depth_image "  << depth_image_ptr->getFrameID () << "\n"
00100             << "width_depth_image "  << width_depth_image  << "\n"
00101             << "height_depth_image " << height_depth_image << "\n"
00102             << "focal_length_depth_image "  << depth_image_ptr->getFocalLength() << "\n";
00103   
00104   std::string color_image_filename = dir_name+"/"+filename_stream.str()+"_color_image.dat";
00105   const unsigned char* color_map = color_image_ptr->getMetaData().Data();
00106   int width_color_image = color_image_ptr->getWidth (),
00107       height_color_image = color_image_ptr->getHeight ();
00108   openni_wrapper::Image::Encoding encoding = color_image_ptr->getEncoding();
00109   int color_image_size = 0;
00110   if (encoding==openni_wrapper::Image::RGB)
00111     color_image_size = 3 * width_color_image*height_color_image;
00112   else if(encoding==openni_wrapper::Image::BAYER_GRBG)
00113     color_image_size = width_color_image*height_color_image;
00114   else if(encoding==openni_wrapper::Image::YUV422)
00115     color_image_size = 2 * width_color_image*height_color_image;
00116   std::ofstream color_image_file(color_image_filename.c_str());
00117   color_image_file.write((const char*)color_map, color_image_size);
00118   color_image_file.close();
00119   
00120   info_file << "color_image_filename "<<getFilenameWithoutPath (color_image_filename)<<"\n"
00121             << "time_stamp_color_image "  << color_image_ptr->getTimeStamp () << "\n"
00122             << "frame_id_color_image "  << color_image_ptr->getFrameID () << "\n"
00123             << "width_color_image "  << width_color_image  << "\n"
00124             << "height_color_image " << height_color_image << "\n";
00125   if (encoding==openni_wrapper::Image::RGB)
00126     info_file << "color_image_encoding RGB\n";
00127   else if(encoding==openni_wrapper::Image::BAYER_GRBG)
00128     info_file << "color_image_encoding BAYER_GRBG\n";
00129   else if(encoding==openni_wrapper::Image::YUV422)
00130     info_file << "color_image_encoding YUV422\n";
00131   
00132   Eigen::Affine3f pose_diff = Eigen::Affine3f::Identity();
00133   if (key_frame_counter > 1) {
00134     pose_diff = current_pose.inverse() * last_keyframe_pose;
00135   }
00136   Eigen::Vector3f translation = pose_diff.translation();
00137   Eigen::Quaternionf rotation = Eigen::Quaternionf(pose_diff.rotation());
00138   info_file << "pose_diff_translation_xyz "<<translation.x()<<" "<<translation.y()<<" "<<translation.z()<<"\n";
00139   info_file << "pose_diff_rotation_wxyz "<<rotation.w()<<" "<<rotation.x()<<" "<<rotation.y()<<" "<<rotation.z()<<"\n";
00140 
00141   
00142   info_file.close();
00143 }
00144 
00145 void
00146 printUsage (const char* progName)
00147 {
00148   cout << "\n\nUsage: "<<progName<<" [options] [scene.pcd] <model.pcl> [model_2.pcl] ... [model_n.pcl]\n\n"
00149        << "Options:\n"
00150        << "-------------------------------------------\n"
00151        << "-r <float>      angular resolution in degrees (default "<<angular_resolution<<")\n"
00152        << "-d <device_id>  set the device id (default \""<<device_id<<"\")\n"
00153        << "-t <int>        set the maximum number of threads for parallelization (default: "<<max_no_of_threads<<")\n"
00154        << "-c              save keyframes to disc\n"
00155        << "-m <float>      maximum range\n"
00156        << "-s <float>      size factor (default: "<<size_factor<<")\n"
00157        << "-h              this help\n"
00158        << "\n\n";
00159 }
00160 
00161 int main (int argc, char** argv)
00162 {
00163   // --------------------------------------
00164   // -----Parse Command Line Arguments-----
00165   // --------------------------------------
00166   if (pcl::console::find_argument (argc, argv, "-h") >= 0)
00167   {
00168     printUsage (argv[0]);
00169     return 0;
00170   }
00171   if (pcl::console::find_argument (argc, argv, "-c") >= 0)
00172   {
00173     capture = true;
00174     cout << "Switching capturing on.\n";
00175   }
00176   if (pcl::console::parse (argc, argv, "-d", device_id) >= 0)
00177     cout << "Using device id \""<<device_id<<"\".\n";
00178   if (pcl::console::parse (argc, argv, "-r", angular_resolution) >= 0)
00179     cout << "Setting angular resolution to "<<angular_resolution<<"deg.\n";
00180   if (pcl::console::parse (argc, argv, "-m", maximum_range) >= 0)
00181     cout << "Setting maximum range to "<<maximum_range<<"m.\n";
00182   angular_resolution = deg2rad (angular_resolution);
00183   if (pcl::console::parse (argc, argv, "-t", max_no_of_threads) >= 0)
00184     cout << "Setting maximum number of threads to "<< max_no_of_threads<<".\n";
00185   if (pcl::console::parse (argc, argv, "-s", size_factor) >= 0)
00186     cout << "Setting size factor to "<<size_factor<<".\n";
00187   
00188   float icp_max_distance_start_consecutive=size_factor*0.3, icp_max_distance_end_consecutive=size_factor*0.05;
00189   float icp_max_distance_start_keyframe=size_factor*0.15, icp_max_distance_end_keyframe=size_factor*0.05;
00190   float overlap_calculation_max_error = size_factor*0.25;
00191   
00192   RangeImage::max_no_of_threads = max_no_of_threads;
00193   
00194   RangeImageVisualizer range_image_widget ("Range Image"),
00195                        ir_image_widget ("IR Image"),
00196                        color_image_widget ("RGB Image");
00197   
00198   PCLVisualizer viewer ("3D Viewer");
00199   viewer.addCoordinateSystem (1.0f);
00200   viewer.setBackgroundColor (1, 1, 1);
00201   
00202   viewer.initCameraParameters ();
00203   viewer.camera_.pos[0] = 0.0;
00204   viewer.camera_.pos[1] = -0.3;
00205   viewer.camera_.pos[2] = -2.0;
00206   viewer.camera_.focal[0] = 0.0;
00207   viewer.camera_.focal[1] = 0.0+viewer.camera_.pos[1];
00208   viewer.camera_.focal[2] = 1.0;
00209   viewer.camera_.view[0] = 0.0;
00210   viewer.camera_.view[1] = -1.0;
00211   viewer.camera_.view[2] = 0.0;
00212   viewer.updateCamera();
00213 
00214   openni_wrapper::OpenNIDriver& driver = openni_wrapper::OpenNIDriver::getInstance ();
00215   if (driver.getNumberDevices () > 0)
00216   {
00217     for (unsigned deviceIdx = 0; deviceIdx < driver.getNumberDevices (); ++deviceIdx)
00218     {
00219       cout << "Device: " << deviceIdx + 1 << ", vendor: " << driver.getVendorName (deviceIdx)
00220            << ", product: " << driver.getProductName (deviceIdx) << ", connected: "
00221            << (int) driver.getBus (deviceIdx) << " @ " << (int) driver.getAddress (deviceIdx)
00222            << ", serial number: \'" << driver.getSerialNumber (deviceIdx) << "\'\n";
00223     }
00224   }
00225   else
00226   {
00227     cout << "\nNo devices connected.\n\n";
00228     return 1;
00229   }
00230   
00231   pcl::Grabber* interface = new pcl::OpenNIGrabber (device_id);
00232   EventHelper event_helper;
00233   
00234   //boost::function<void (const boost::shared_ptr<openni_wrapper::DepthImage>&) > f_depth_image =
00235     //boost::bind (&EventHelper::depth_image_cb, &event_helper, _1);
00236   //boost::signals2::connection c_depth_image = interface->registerCallback (f_depth_image);
00237   
00238   boost::function<void (const boost::shared_ptr<openni_wrapper::Image>&,
00239                         const boost::shared_ptr<openni_wrapper::DepthImage>&,
00240                         float) > f_image_pair =
00241     boost::bind (&EventHelper::depthAndColorCB, &event_helper, _1, _2, _3);
00242   boost::signals2::connection c_image_pair = interface->registerCallback (f_image_pair);
00243   
00244   cout << "Starting grabber\n";
00245   interface->start ();
00246   cout << "Done\n";
00247   
00248   boost::shared_ptr<RangeImagePlanar> range_image_ptr (new RangeImagePlanar);
00249   RangeImagePlanar& range_image = *range_image_ptr;
00250   boost::shared_ptr<RangeImagePlanar> last_range_image_ptr (new RangeImagePlanar);
00251   RangeImagePlanar& last_range_image = *last_range_image_ptr;
00252   boost::shared_ptr<RangeImagePlanar> last_keyframe_range_image_ptr (new RangeImagePlanar);
00253   RangeImagePlanar& last_keyframe_range_image = *last_keyframe_range_image_ptr;
00254   
00255   if (capture)
00256   {
00257     boost::posix_time::ptime current_time(boost::posix_time::second_clock::local_time());
00258     stringstream ss;
00259     boost::posix_time::time_facet* time_format = new boost::posix_time::time_facet("%Y_%m_%d__%H_%M_%S");
00260     ss.imbue(std::locale(ss.getloc(), time_format));
00261     ss << output_prefix << "_" << current_time;
00262     dir_name = ss.str();
00263     cout << "Creating directory \""<<dir_name<<"\" to save captured data.\n";
00264     boost::filesystem::create_directory(dir_name);
00265   }
00266   
00267   double last_50_frames_start_time = 0;
00268   
00269   while (true)
00270   {
00271     if (show_registered_clouds)
00272       viewer.spinOnce (10);
00273     if (show_color_image || show_range_image)
00274       ImageWidgetWX::spinOnce ();  // process GUI events
00275     boost::this_thread::sleep (boost::posix_time::microseconds (1000));
00276     
00277     bool got_new_range_image = false;
00278     if (!received_new_image_pair || !image_mutex.try_lock ())
00279       continue;
00280     
00281     received_new_image_pair = false;
00282     
00283     // Depth Image
00284     unsigned long time_stamp_depth_image = depth_image_ptr->getTimeStamp ();
00285     int frame_id_depth_image = depth_image_ptr->getFrameID ();
00286     const unsigned short* depth_map = depth_image_ptr->getDepthMetaData().Data();
00287     int width_depth_image = depth_image_ptr->getWidth (), height_depth_image = depth_image_ptr->getHeight ();
00288     float focal_length_x = depth_image_ptr->getFocalLength(), focal_length_y = focal_length_x;
00289     float original_angular_resolution = asinf (0.5f*float(width_depth_image)/float(focal_length_x)) /
00290                                               (0.5f*float(width_depth_image));
00291     float desired_angular_resolution = angular_resolution;
00292     std::swap(last_range_image, range_image);
00293     range_image.setDepthImage (depth_map, width_depth_image, height_depth_image,
00294                                width_depth_image/2, height_depth_image/2,
00295                                focal_length_x, focal_length_y, desired_angular_resolution);
00296     
00297     if (maximum_range > 0.0f)
00298     {
00299       for (int point_idx=0; point_idx<range_image.points.size(); ++point_idx)
00300         if (range_image.points[point_idx].range > maximum_range)
00301           range_image.points[point_idx].range = std::numeric_limits<float>::infinity ();
00302     }
00303 
00304     if (show_range_image)
00305       range_image_widget.setRangeImage (range_image, 0.0f, 10.0f);
00306     
00307     // Color Image
00308     unsigned long time_stamp_color_image = color_image_ptr->getTimeStamp ();
00309     int frame_id_color_image = color_image_ptr->getFrameID ();
00310     openni_wrapper::Image::Encoding encoding = color_image_ptr->getEncoding();
00311     //if (encoding==openni_wrapper::Image::RGB)
00312       //cout << "Image encoding is RGB.\n";
00313     //else if(encoding==openni_wrapper::Image::BAYER_GRBG)
00314       //cout << "Image encoding is BAYER_GRBG.\n";
00315     //else if(encoding==openni_wrapper::Image::YUV422)
00316       //cout << "Image encoding is YUV422.\n";
00317     const unsigned char* color_map = color_image_ptr->getMetaData().Data();
00318     int width_color_image = color_image_ptr->getWidth (), height_color_image = color_image_ptr->getHeight ();
00319     
00320     if (show_color_image)
00321     {
00322       if (encoding==openni_wrapper::Image::RGB)
00323         color_image_widget.setRGBImage(color_map, width_color_image, height_color_image);
00324       else if(encoding==openni_wrapper::Image::BAYER_GRBG)
00325         color_image_widget.setBayerGRBGImage(color_map, width_color_image, height_color_image);
00326     }
00327     
00328     if (!range_image.points.empty())
00329     {
00330       got_new_range_image = true;
00331       ++range_image_counter;
00332     }
00333     
00334     if (range_image_counter == 1)
00335     {
00336       last_keyframe_range_image = range_image;
00337       key_frame_counter = 1;
00338       last_pose = last_keyframe_pose = current_pose = Eigen::Affine3f::Identity();
00339       last_50_frames_start_time = getTime();
00340       cout << "k" << std::flush;
00341       saveFrame();
00342       image_mutex.unlock ();
00343       continue;
00344     }
00345     
00346     double icp_time = -getTime();
00347     Eigen::Affine3f consecutive_pose_diff_initial_guess = Eigen::Affine3f::Identity(),
00348                     keyframe_pose_diff_initial_guess = Eigen::Affine3f::Identity();
00349     last_pose = current_pose;
00350     Eigen::Affine3f consecutive_icp_pose_diff = range_image.doIcp(last_range_image,
00351                       consecutive_pose_diff_initial_guess, icp_search_radius_consecutive,
00352                       icp_max_distance_start_consecutive, icp_max_distance_end_consecutive,
00353                       icp_num_iterations_consecutive, 3, 1),
00354                     consecutive_icp_pose = last_pose * consecutive_icp_pose_diff.inverse();
00355     keyframe_pose_diff_initial_guess = consecutive_icp_pose.inverse() * last_keyframe_pose;
00356     
00357     Eigen::Affine3f keyframe_icp_pose_diff = range_image.doIcp(last_keyframe_range_image,
00358                                                keyframe_pose_diff_initial_guess, icp_search_radius_keyframe,
00359                                                icp_max_distance_start_keyframe, icp_max_distance_end_keyframe,
00360                                                icp_num_iterations_keyframe, 3, 1),
00361                     keyframe_icp_pose = last_keyframe_pose * keyframe_icp_pose_diff.inverse();
00362     //Eigen::Affine3f keyframe_icp_pose_diff = keyframe_pose_diff_initial_guess,
00363                     //keyframe_icp_pose = last_keyframe_pose * keyframe_icp_pose_diff.inverse();
00364     icp_time += getTime();
00365     //cout << PVARN(icp_time);
00366 
00367     double overlap_time = -getTime();
00368     // TODO: error range dependent
00369     float overlap = std::min(
00370       range_image.getOverlap(last_keyframe_range_image, keyframe_icp_pose_diff,
00371                              2, overlap_calculation_max_error, 3),
00372       last_keyframe_range_image.getOverlap(range_image, keyframe_icp_pose_diff.inverse(),
00373                                            1, overlap_calculation_max_error, 1));
00374     overlap_time += getTime();
00375     //cout << PVARN(overlap_time);
00376     
00377     current_pose = keyframe_icp_pose;
00378     
00379     if (overlap < new_keyframe_overlap)
00380     {
00381       cout << "k" << std::flush;
00382       ++key_frame_counter;
00383       saveFrame();
00384       last_keyframe_range_image = range_image;
00385       last_keyframe_pose = current_pose;
00386     }
00387     else
00388       cout << "." << std::flush;
00389     //cout << overlap << " " << std::flush;
00390     
00391     
00392     image_mutex.unlock ();
00393     
00395     if (range_image_counter%50 == 0)
00396     {
00397       if (range_image_counter > 1)
00398         cout << "\nFramerate: "<<50.0f / (getTime()-last_50_frames_start_time)<<"fps.\n";
00399       last_50_frames_start_time = getTime();
00400     }
00401     
00403     
00404     if (show_registered_clouds)
00405     {
00406       PointCloud<PointXYZ>::Ptr transformed_cloud_ptr(new PointCloud<PointXYZ>);
00407       PointCloud<PointXYZ>& transformed_cloud = *transformed_cloud_ptr;
00408       for (unsigned int i=0; i<range_image.points.size(); ++i)
00409       {
00410         if (range_image.isValid(i))
00411         {
00412           transformed_cloud.points.push_back(PointXYZ());
00413           transformed_cloud.points.back().getVector3fMap() = current_pose * range_image.points[i].getVector3fMap();
00414         }
00415       }
00416       
00417       PointCloudColorHandlerCustom<pcl::PointXYZ> color_handler_transformed_cloud (transformed_cloud_ptr, 0, 0, 0);
00418       if (!viewer.updatePointCloud<pcl::PointXYZ> (transformed_cloud_ptr, color_handler_transformed_cloud,
00419                                                    "transformed cloud"))
00420         viewer.addPointCloud<pcl::PointXYZ> (transformed_cloud_ptr, color_handler_transformed_cloud,
00421                                              "transformed cloud");
00422     }
00423   }
00424   
00425   interface->stop ();
00426 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


narf_recognition
Author(s): Juergen Hess
autogenerated on Wed Dec 26 2012 16:37:09