openni_object_recognition.cpp
Go to the documentation of this file.
00001 /* \author Bastian Steder */
00002 
00003 /* ---[ */
00004 #include <iostream>
00005 using namespace std;
00006 #include "object_recognition/object_recognition_helper.h"
00007 #include <pcl/io/openni_grabber.h>
00008 #include "pcl/console/parse.h"
00009 
00010 #include "pcl/io/pcd_io.h"
00011 #include "pcl/range_image/range_image.h"
00012 #include "pcl/features/narf.h"
00013 #include "pcl/common/point_correspondence.h"
00014 #include "pcl/common/poses_from_matches.h"
00015 #include "pcl/features/range_image_border_extractor.h"
00016 #include "pcl/keypoints/narf_keypoint.h"
00017 #include "pcl/range_image/range_image_planar.h"
00018 #include "sensor_msgs/Image.h"
00019 #include "pcl/common/file_io.h"
00020 #include "pcl/common/common_headers.h"
00021 #include "pcl/visualization/range_image_visualizer.h"
00022 #include "pcl/visualization/pcl_visualizer.h"
00023 
00024 
00025 using namespace pcl;
00026 using namespace pcl::visualization;
00027 
00028 ObjectRecognitionHelper object_recognition_helper;
00029 ObjectRecognitionHelper::Parameters& orh_params = object_recognition_helper.getParameters ();
00030 FalsePositivesFilter& false_positives_filter = object_recognition_helper.getFalsePositivesFilter ();
00031 FalsePositivesFilter::Parameters& fpf_params = false_positives_filter.getParameters ();
00032 
00033 int& max_no_of_threads = orh_params.max_no_of_threads;
00034 bool& use_rotation_invariance = orh_params.use_rotation_invariance;
00035 float& angular_resolution = orh_params.angular_resolution;
00036 RangeImage::CoordinateFrame& coordinate_frame = orh_params.coordinate_frame;
00037 float& max_descriptor_distance = orh_params.max_descriptor_distance;
00038 bool& set_unseen_to_max_range = orh_params.set_unseen_to_max_range;
00039 bool single_view_model = orh_params.single_view_model;
00040 
00041 float noise_level_factor = 0.05;    // Factor regarding average model radius
00042 float support_size_factor = 0.5f;  // Factor regarding average model radius
00043 float support_size = -1.0f;
00044 
00045 bool show_found_objects = 1;
00046 bool do_plane_extraction = false;
00047 
00048 std::string device_id = "#1";
00049 
00050 void printUsage (const char* progName)
00051 {
00052   cout << "\n\nUsage: "<<progName<<" [options] [scene.pcd] <model.pcl> [model_2.pcl] ... [model_n.pcl]\n\n"
00053        << "Options:\n"
00054        << "-------------------------------------------\n"
00055        << "-d <device_id>  set the device id (default \""<<device_id<<"\")\n"
00056        << "-i <bool>    do ICP (default "<< (int)fpf_params.do_icp<<").\n"
00057        << "-r <float>   angular resolution in degrees (default "<<rad2deg (angular_resolution)<<"deg)\n"
00058        << "-v <float>   min validation point score (default "<<fpf_params.min_validation_point_score<<")\n"
00059        << "-c <int>     coordinate frame (default "<<coordinate_frame<<")\n"
00060        << "-b           activate single view model, which tells the system that the given model point cloud\n"
00061        <<             " is not of the complete object, but only one view of it - no view sampling will be performed.\n"
00062        << "-o           use orientation invariant version\n"
00063        << "-f <float>   do view simulation filtering with this minimum score.\n"
00064        << "-x <float>   use maximum range for found objects.\n"
00065        << "-n <float>   set the maximum descriptor distance (default: "<<max_descriptor_distance<<")\n"
00066        << "-t <int>     set the maximum number of threads for parallelization (default: "<<max_no_of_threads<<")\n"
00067        << "-p           plane extraction - remove big planes from the scene before trying to find objects.\n"
00068        << "-s <float>   the support size used for keypoint and feature extraction"
00069        <<               " (default: "<<support_size_factor<<" times the average model radius)\n"
00070        << "-l1 <int>    start sampling layer (default: "<<orh_params.view_sampling_first_layer<<")\n"
00071        << "-l2 <int>    end sampling layer (default: "<<orh_params.view_sampling_last_layer<<")\n"
00072        << "-h           this help\n"
00073        << "\n\n";
00074 }
00075 
00076 
00077 boost::mutex depth_image_mutex;
00078 boost::shared_ptr<openni_wrapper::DepthImage> depth_image_ptr;
00079 
00080 bool received_new_depth_data = false;
00081 struct EventHelper
00082 {
00083   void
00084   depth_image_cb (const boost::shared_ptr<openni_wrapper::DepthImage>& depth_image)
00085   {
00086     if (depth_image_mutex.try_lock ())
00087     {
00088       depth_image_ptr = depth_image;
00089       depth_image_mutex.unlock ();
00090       received_new_depth_data = true;
00091     }
00092   }
00093 };
00094 
00095 
00096 int main (int argc, char** argv)
00097 {
00098   orh_params.view_sampling_first_layer = 0;
00099   orh_params.view_sampling_last_layer = 0;
00100 
00101   // --------------------------------------
00102   // -----Parse Command Line Arguments-----
00103   // --------------------------------------
00104   if (pcl::console::find_argument (argc, argv, "-h") >= 0)
00105   {
00106     printUsage (argv[0]);
00107     return 0;
00108   }
00109   if (pcl::console::parse (argc, argv, "-t", max_no_of_threads) >= 0)
00110     cout << "Setting maximum number of threads to "<< max_no_of_threads<<".\n";
00111   if (pcl::console::parse (argc, argv, "-i", fpf_params.do_icp) >= 0)
00112     cout << "Will "<< (fpf_params.do_icp?"":"not ")<<"use ICP.\n";
00113   if (pcl::console::find_argument (argc, argv, "-b") >= 0)
00114   {
00115     single_view_model = true;
00116     cout << "Setting single_view_model to true.\n";
00117   }
00118   if (pcl::console::find_argument (argc, argv, "-p") >= 0)
00119   {
00120     do_plane_extraction = true;
00121     cout << "Will perform plane extraction.\n";
00122   }
00123   if (pcl::console::parse (argc, argv, "-d", device_id) >= 0)
00124     cout << "Using device id \""<<device_id<<"\".\n";
00125   if (pcl::console::find_argument (argc, argv, "-o") >= 0)
00126   {
00127     use_rotation_invariance = true;
00128     cout << "Using rotational invariant version of the features.\n";
00129   }
00130   int tmp_coordinate_frame;
00131   if (pcl::console::parse (argc, argv, "-c", tmp_coordinate_frame) >= 0)
00132   {
00133     coordinate_frame = pcl::RangeImage::CoordinateFrame (tmp_coordinate_frame);
00134     cout << "Using coordinate frame "<< (int)coordinate_frame<<".\n";
00135   }
00136   if (pcl::console::parse (argc, argv, "-s", support_size) >= 0)
00137     cout << "Setting support size to "<<support_size<<".\n";
00138   if (pcl::console::parse (argc, argv, "-l1", orh_params.view_sampling_first_layer) >= 0)
00139     cout << "Setting first sampling layer to "<<orh_params.view_sampling_first_layer<<".\n";
00140   if (pcl::console::parse (argc, argv, "-l2", orh_params.view_sampling_last_layer) >= 0)
00141     cout << "Setting last sampling layer to "<<orh_params.view_sampling_last_layer<<".\n";
00142   if (orh_params.view_sampling_first_layer > orh_params.view_sampling_last_layer) {
00143     cerr << "\n\n\nFirst sampling layer has to be less or equal to last sampling layer!\n\n";
00144     return 1;
00145   }
00146   if (pcl::console::parse (argc, argv, "-v", fpf_params.min_validation_point_score) >= 0)
00147   {
00148     fpf_params.do_validation_point_filtering = true;
00149     cout << "Setting minimum validation point score to "<<fpf_params.min_view_simulation_score<<".\n";
00150   }
00151   if (pcl::console::parse (argc, argv, "-x", fpf_params.maximum_range_for_found_objects) >= 0)
00152     cout << "Setting maximum range for found objects to "<<fpf_params.maximum_range_for_found_objects<<".\n";
00153   if (pcl::console::parse (argc, argv, "-n", max_descriptor_distance) >= 0)
00154     cout << "Setting maximum descriptor distance to "<<max_descriptor_distance<<".\n";
00155   if (pcl::console::parse (argc, argv, "-f", fpf_params.min_view_simulation_score) >= 0)
00156   {
00157     fpf_params.do_view_simulation_filtering = true;
00158     cout << "Setting minimum view simulation score to "<<fpf_params.min_view_simulation_score<<".\n";
00159   }
00160   if (pcl::console::parse (argc, argv, "-r", angular_resolution) >= 0) {
00161     cout << "Setting angular resolution to "<<angular_resolution<<"deg.\n";
00162     angular_resolution = deg2rad (angular_resolution);
00163   }
00164   
00165   
00166   set_unseen_to_max_range = true;
00167   
00168   // -----------------------
00169   // -----Read pcd file-----
00170   // -----------------------
00171   std::vector<int> pcd_filename_indices = pcl::console::parse_file_extension_argument (argc, argv, "pcd");
00172   if (pcd_filename_indices.empty ())
00173   {
00174     cout << "\nNo *.pcd file for model given.\n\n";
00175     exit (0);
00176   }
00177   vector<string> model_filenames;
00178   for (int i=0; i<pcd_filename_indices.size (); ++i)
00179     model_filenames.push_back (argv[pcd_filename_indices[i]]);
00180   ObjectModelList& object_models = object_recognition_helper.getIntermediateElements ().object_models;
00181   if (!object_recognition_helper.addObjectModelsFromPcdFiles (model_filenames))
00182   {
00183     printUsage (argv[0]);
00184     exit (1);
00185   }
00186   
00187   float average_model_radius = object_models.getAverageModelRadius ();
00188   
00189   if (support_size < 0.0f)
00190     support_size = support_size_factor * average_model_radius;
00191   float noise_level = noise_level_factor * average_model_radius;
00192   
00193   //float initial_max_plane_error = 0.02f;
00194   float initial_max_plane_error = 0.2f*average_model_radius;
00195   float minimum_plane_size = 0.5f;
00196   if (do_plane_extraction)
00197   {
00198     minimum_plane_size = 1.2f * object_models.getMaximumPlaneSize (initial_max_plane_error);
00199     cout << PVARN (minimum_plane_size);
00200   }
00201   
00202   cout << "\n-----\n"
00203        << "The average object model radius is "<<average_model_radius<<"m.\n"
00204        << "  => using support size "<<support_size<<"m.\n"
00205        << "  => using noise level "<<noise_level<<"m.\n"
00206        << "-----\n\n";
00207   orh_params.support_size = support_size;
00208   orh_params.noise_level = noise_level;
00209   
00210   object_recognition_helper.extractModelFeatures ();
00211   std::vector<Narf*>& database_features = object_recognition_helper.getIntermediateElements ().database_features;
00212   std::vector<ObjectModelList::FeatureSource>& database_feature_sources = 
00213     object_recognition_helper.getIntermediateElements ().database_feature_sources;
00214   
00215   // ------------------------------------------------------------------
00216   
00217   vector<string> point_clouds_in_viewer;
00218   RangeImageVisualizer scene_range_image_widget ("scene range image");
00219   
00220   PCLVisualizer viewer ("3D Viewer");
00221   viewer.addCoordinateSystem (1.0f);
00222   viewer.setBackgroundColor (1, 1, 1);
00223   
00224   viewer.initCameraParameters ();
00225   viewer.camera_.pos[0] = 0.0;
00226   viewer.camera_.pos[1] = -0.3;
00227   viewer.camera_.pos[2] = -2.0;
00228   viewer.camera_.focal[0] = 0.0;
00229   viewer.camera_.focal[1] = 0.0+viewer.camera_.pos[1];
00230   viewer.camera_.focal[2] = 1.0;
00231   viewer.camera_.view[0] = 0.0;
00232   viewer.camera_.view[1] = -1.0;
00233   viewer.camera_.view[2] = 0.0;
00234   viewer.updateCamera ();
00235 
00236   openni_wrapper::OpenNIDriver& driver = openni_wrapper::OpenNIDriver::getInstance ();
00237   if (driver.getNumberDevices () > 0)
00238   {
00239     for (unsigned deviceIdx = 0; deviceIdx < driver.getNumberDevices (); ++deviceIdx)
00240     {
00241       cout << "Device: " << deviceIdx + 1 << ", vendor: " << driver.getVendorName (deviceIdx)
00242            << ", product: " << driver.getProductName (deviceIdx) << ", connected: "
00243            << (int) driver.getBus (deviceIdx) << " @ " << (int) driver.getAddress (deviceIdx)
00244            << ", serial number: \'" << driver.getSerialNumber (deviceIdx) << "\'\n";
00245     }
00246   }
00247   else
00248   {
00249     cout << "\nNo devices connected.\n\n";
00250     return 1;
00251   }
00252   
00253   pcl::Grabber* interface = new pcl::OpenNIGrabber (device_id);
00254   EventHelper event_helper;
00255   //boost::function<void (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr&) > f_point_cloud =
00256     //boost::bind (&EventHelper::cloud_cb, &event_helper, _1);
00257   //boost::signals2::connection c_point_cloud = interface->registerCallback (f_point_cloud);
00258   
00259   boost::function<void (const boost::shared_ptr<openni_wrapper::DepthImage>&) > f_depth_image =
00260     boost::bind (&EventHelper::depth_image_cb, &event_helper, _1);
00261   boost::signals2::connection c_depth_image = interface->registerCallback (f_depth_image);
00262   
00263   cout << "Starting grabber\n";
00264   interface->start ();
00265   cout << "Done\n";
00266   //bool first = true;
00267   
00268   while (!viewer.wasStopped ()) // && (node_handle==NULL || node_handle->ok ()))
00269   {
00270     viewer.spinOnce ();
00271     scene_range_image_widget.spinOnce ();  // process GUI events
00272     //if (live_scenes)
00273       //ros::spinOnce ();
00274     boost::this_thread::sleep (boost::posix_time::microseconds (100000));
00275     
00276     bool got_new_range_image = false;
00277     if (received_new_depth_data && depth_image_mutex.try_lock ())
00278     {
00279       received_new_depth_data = false;
00280       if (object_recognition_helper.createRangeImageFromOpenniDepthImage (*depth_image_ptr))
00281         got_new_range_image = true;
00282       depth_image_mutex.unlock ();
00283     }
00284     
00285     if (!got_new_range_image)
00286       continue;
00287     got_new_range_image = false;
00288     cout << "Got new data.\n";
00289     
00290     boost::shared_ptr<RangeImage>& scene_range_image_ptr =
00291       object_recognition_helper.getIntermediateElements ().scene_range_image_ptr;
00292     RangeImage& scene_range_image = *scene_range_image_ptr;   
00293     
00294     if (do_plane_extraction)
00295     {
00296       PointWithRange farRangePoint;
00297       farRangePoint.x=farRangePoint.y=farRangePoint.z = std::numeric_limits<float>::quiet_NaN ();
00298       farRangePoint.range = std::numeric_limits<float>::infinity ();
00299       std::vector<RangeImage::ExtractedPlane> planes;
00300       scene_range_image.extractPlanes (initial_max_plane_error, planes);
00301       //std::sort (planes.begin (), planes.end (), RangeImage::isLargerPlane);
00302       //for (int plane_idx=0; plane_idx<=0; ++plane_idx)
00303       for (int plane_idx=0; plane_idx<int (planes.size ()); ++plane_idx)
00304       {
00305         const RangeImage::ExtractedPlane& plane = planes[plane_idx];
00306         if (plane.maximum_extensions[2] <= minimum_plane_size)
00307           continue;
00308         //cout << "Removing plane of size "<<plane.maximum_extensions[2]<<"m ("<<plane.point_indices.size ()<<" points).\n";
00309         for (int plane_point_idx=0; plane_point_idx<int (plane.point_indices.size ()); ++plane_point_idx)
00310           scene_range_image.points[plane.point_indices[plane_point_idx]] = farRangePoint;
00311       }
00312     }
00313     
00314     object_recognition_helper.extractSceneFeatures ();
00315     object_recognition_helper.extractPoseEstimates ();
00316     std::vector<PosesFromMatches::PoseEstimatesVector>& pose_estimates_per_model = 
00317       object_recognition_helper.filterFalsePositives ();
00318     //object_recognition_helper.printTimings ();
00319     
00320     
00322     scene_range_image_widget.showRangeImage (scene_range_image);
00323     
00324     static bool first_range_image = true;
00325     PointCloudColorHandlerCustom<pcl::PointWithRange> color_handler_cloud (scene_range_image_ptr, 0, 0, 0);
00326     if (first_range_image)
00327     {
00328       viewer.addPointCloud<pcl::PointWithRange> (scene_range_image_ptr, color_handler_cloud, "scene range image");
00329       first_range_image = false;
00330     }
00331     else
00332     {
00333       viewer.updatePointCloud<pcl::PointWithRange> (scene_range_image_ptr, color_handler_cloud, "scene range image");
00334     }
00335     
00336     vector<boost::shared_ptr<ObjectModel::PointCloudType> > objects_in_scene;  // For visualization
00337     for (unsigned int model_idx=0; model_idx<object_models.size (); ++model_idx)
00338     {
00339       PosesFromMatches::PoseEstimatesVector& pose_estimates = pose_estimates_per_model[model_idx];
00340       ObjectModel& object_model = *object_models[model_idx];
00341       for (unsigned int pose_estimate_idx=0; pose_estimate_idx<pose_estimates.size () && show_found_objects;
00342                                                                                         ++pose_estimate_idx)
00343       {
00344         const PosesFromMatches::PoseEstimate& pose_estimate = pose_estimates[pose_estimate_idx];
00345         objects_in_scene.push_back (boost::shared_ptr<ObjectModel::PointCloudType> (new ObjectModel::PointCloudType));
00346         object_model.getTransformedPointCloud (pose_estimate.transformation, *objects_in_scene.back ());
00347       }
00348     }
00349     
00350     for (unsigned int i=0; i<point_clouds_in_viewer.size (); ++i)
00351       viewer.removePointCloud (point_clouds_in_viewer[i]);
00352     point_clouds_in_viewer.clear ();
00353     
00354     for (unsigned int i=0; i<objects_in_scene.size (); ++i)
00355     {
00356       stringstream ss;
00357       ss<<"Found object "<<i;
00358       point_clouds_in_viewer.push_back (ss.str ());
00359       PointCloudColorHandlerRandom<ObjectModel::PointCloudType::PointType> color_handler (objects_in_scene[i]);
00360       viewer.addPointCloud<ObjectModel::PointCloudType::PointType> (objects_in_scene[i], color_handler, point_clouds_in_viewer.back ());
00361     }
00362   }
00363 
00364   interface->stop ();
00365 }
 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