00001
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;
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
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
00235
00236
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 ();
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
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
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
00312
00313
00314
00315
00316
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
00363
00364 icp_time += getTime();
00365
00366
00367 double overlap_time = -getTime();
00368
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
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
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 }