00001
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;
00042 float support_size_factor = 0.5f;
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
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
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
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
00256
00257
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
00267
00268 while (!viewer.wasStopped ())
00269 {
00270 viewer.spinOnce ();
00271 scene_range_image_widget.spinOnce ();
00272
00273
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
00302
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
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
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;
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 }