linemod_nodelet.cpp
Go to the documentation of this file.
1 // -*- mode: c++ -*-
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2014, JSK Lab
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the JSK Lab nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 #define BOOST_PARAMETER_MAX_ARITY 7
36 
37 #include <limits>
38 #include "jsk_pcl_ros/linemod.h"
40 #include <boost/filesystem.hpp>
41 #include <boost/format.hpp>
42 #include <pcl/recognition/color_gradient_modality.h>
43 #include <pcl/recognition/surface_normal_modality.h>
44 #include <pcl/filters/extract_indices.h>
45 #include <pcl/io/pcd_io.h>
46 #include <jsk_topic_tools/rosparam_utils.h>
47 #include <glob.h>
48 #include <boost/algorithm/string/predicate.hpp>
49 #include <pcl/common/transforms.h>
50 #include <pcl/range_image/range_image_planar.h>
52 #include <cv_bridge/cv_bridge.h>
54 #include <pcl/kdtree/kdtree_flann.h>
55 #include <yaml-cpp/yaml.h>
56 #include <pcl/common/common.h>
59 
60 #if ( CV_MAJOR_VERSION >= 4)
61 #include <opencv2/imgproc/imgproc_c.h>
62 #endif
63 
64 namespace jsk_pcl_ros
65 {
67  {
68  PCLNodelet::onInit();
69  pnh_->param("output_file", output_file_, std::string("template"));
70  pnh_->param("sample_viewpoint", sample_viewpoint_, true);
71  pnh_->param("sample_viewpoint_angle_step", sample_viewpoint_angle_step_,
72  40.0);
73  pnh_->param("sample_viewpoint_angle_min", sample_viewpoint_angle_min_,
74  -80.0);
75  pnh_->param("sample_viewpoint_angle_max", sample_viewpoint_angle_max_,
76  80.0);
77  pnh_->param("sample_viewpoint_radius_step", sample_viewpoint_radius_step_,
78  0.2);
79  pnh_->param("sample_viewpoint_radius_min", sample_viewpoint_radius_min_,
80  0.4);
81  pnh_->param("sample_viewpoint_radius_max", sample_viewpoint_radius_max_,
82  0.8);
83  pnh_->param("n_points", n_points_, 150);
84  if (!sample_viewpoint_) {
85  sub_input_.subscribe(*pnh_, "input", 1);
86  sub_indices_.subscribe(*pnh_, "input/indices", 1);
87  sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
88  sync_->connectInput(sub_input_, sub_indices_);
89  sync_->registerCallback(boost::bind(&LINEMODTrainer::store,
90  this, _1, _2));
91  }
92  else {
93  sub_input_nonsync_ = pnh_->subscribe("input", 1,
95  this);
96  sub_camera_info_nonsync_ = pnh_->subscribe(
97  "input/info", 1,
99  this);
100  pub_range_image_ = pnh_->advertise<sensor_msgs::Image>(
101  "output/range_image", 1);
102  pub_colored_range_image_ = pnh_->advertise<sensor_msgs::Image>(
103  "output/colored_range_image", 1);
104  pub_sample_cloud_ = pnh_->advertise<sensor_msgs::PointCloud2>(
105  "output/sample_cloud", 1);
106  }
108  = pnh_->advertiseService(
109  "start_training", &LINEMODTrainer::startTraining,
110  this);
112  = pnh_->advertiseService(
113  "clear", &LINEMODTrainer::clearData,
114  this);
115  }
116 
118  // message_filters::Synchronizer needs to be called reset
119  // before message_filters::Subscriber is freed.
120  // Calling reset fixes the following error on shutdown of the nodelet:
121  // terminate called after throwing an instance of
122  // 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error> >'
123  // what(): boost: mutex lock failed in pthread_mutex_lock: Invalid argument
124  // Also see https://github.com/ros/ros_comm/issues/720 .
125  sync_.reset();
126  }
127 
129  const sensor_msgs::PointCloud2::ConstPtr& cloud_msg,
130  const PCLIndicesMsg::ConstPtr& indices_msg)
131  {
132  boost::mutex::scoped_lock lock(mutex_);
133  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud
134  (new pcl::PointCloud<pcl::PointXYZRGBA>);
135  pcl::fromROSMsg(*cloud_msg, *cloud);
136  pcl::PointIndices::Ptr indices(new pcl::PointIndices);
137  pcl_conversions::toPCL(*indices_msg, *indices);
138  samples_.push_back(cloud);
139  sample_indices_.push_back(indices);
140  NODELET_INFO("%lu samples", samples_.size());
141  }
142 
144  const sensor_msgs::PointCloud2::ConstPtr& cloud_msg)
145  {
146  boost::mutex::scoped_lock lock(mutex_);
147  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud
148  (new pcl::PointCloud<pcl::PointXYZRGBA>);
149  pcl::fromROSMsg(*cloud_msg, *cloud);
150  samples_before_sampling_.push_back(cloud);
151  NODELET_INFO("%lu samples", samples_.size());
152  }
153 
155  const sensor_msgs::CameraInfo::ConstPtr& info_msg)
156  {
157  boost::mutex::scoped_lock lock(mutex_);
159  }
160 
162  std_srvs::Empty::Request& req,
163  std_srvs::Empty::Response& res)
164  {
165  boost::mutex::scoped_lock lock(mutex_);
166  NODELET_INFO("clearing %lu samples", samples_.size());
167  samples_.clear();
168  sample_indices_.clear();
169  return true;
170  }
171 
173  const Eigen::Affine3f& transform,
174  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr raw_cloud,
176  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr colored_cloud,
177  pcl::PointIndices& mask)
178  {
179  int width = model.fullResolution().width;
180  int height = model.fullResolution().height;
181  double fx = model.fx();
182  double fy = model.fy();
183  double cx = model.cx();
184  double cy = model.cy();
185  Eigen::Affine3f viewpoint_transform = transform;
186  Eigen::Affine3f object_transform = viewpoint_transform.inverse();
187  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud
188  (new pcl::PointCloud<pcl::PointXYZRGBA>);
189  pcl::transformPointCloud<pcl::PointXYZRGBA>(
190  *raw_cloud, *cloud, object_transform);
191  pcl::RangeImagePlanar range_image;
192  Eigen::Affine3f dummytrans;
193  dummytrans.setIdentity();
194  range_image.createFromPointCloudWithFixedSize(
195  *cloud, width, height,
196  cx, cy, fx, fy, dummytrans);
197  cv::Mat mat(range_image.height, range_image.width, CV_32FC1);
198  float *tmpf = (float *)mat.ptr();
199  for(unsigned int i = 0; i < range_image.height * range_image.width; i++) {
200  tmpf[i] = range_image.points[i].z;
201  }
202  std_msgs::Header dummy_header;
203  dummy_header.stamp = ros::Time::now();
204  dummy_header.frame_id = camera_info_->header.frame_id;
205  cv_bridge::CvImage range_bridge(dummy_header,
206  "32FC1",
207  mat);
208  pub_range_image_.publish(range_bridge.toImageMsg());
209  pcl::KdTreeFLANN<pcl::PointXYZRGBA>::Ptr
210  kdtree (new pcl::KdTreeFLANN<pcl::PointXYZRGBA>);
211  kdtree->setInputCloud(cloud);
212 
213  colored_cloud->width = range_image.width;
214  colored_cloud->height = range_image.height;
215  colored_cloud->is_dense = range_image.is_dense;
216  pcl::PointXYZRGBA nan_point;
217  nan_point.x = nan_point.y = nan_point.z
218  = std::numeric_limits<float>::quiet_NaN();
219  pcl::PointIndices::Ptr mask_indices (new pcl::PointIndices);
220  colored_cloud->points.resize(range_image.points.size());
221 
222  cv::Mat colored_image = cv::Mat::zeros(
223  range_image.height, range_image.width, CV_8UC3);
224  for (size_t pi = 0; pi < range_image.points.size(); pi++) {
225  if (std::isnan(range_image.points[pi].x) ||
226  std::isnan(range_image.points[pi].y) ||
227  std::isnan(range_image.points[pi].z)) {
228  // nan
229  colored_cloud->points[pi] = nan_point;
230  }
231  else {
232  pcl::PointXYZRGBA input_point;
233  input_point.x = range_image.points[pi].x;
234  input_point.y = range_image.points[pi].y;
235  input_point.z = range_image.points[pi].z;
236  std::vector<int> indices;
237  std::vector<float> distances;
238  kdtree->nearestKSearch(input_point, 1, indices, distances);
239  if (indices.size() > 0) {
240  input_point.rgba = cloud->points[indices[0]].rgba;
241  }
242  colored_image.at<cv::Vec3b>(pi / range_image.width,
243  pi % range_image.width)
244  = cv::Vec3b(cloud->points[indices[0]].r,
245  cloud->points[indices[0]].g,
246  cloud->points[indices[0]].b);
247  colored_cloud->points[pi] = input_point;
248  }
249  }
250  for (size_t pi = 0; pi < range_image.points.size(); pi++) {
251  if (!std::isnan(range_image.points[pi].x) &&
252  !std::isnan(range_image.points[pi].y) &&
253  !std::isnan(range_image.points[pi].z)) {
254  // nan
255  mask.indices.push_back(pi);
256  }
257  }
258  cv_bridge::CvImage colored_range_bridge(dummy_header,
260  colored_image);
261  pub_colored_range_image_.publish(colored_range_bridge.toImageMsg());
262  // // trick, rgba -> rgb
263  sensor_msgs::PointCloud2 ros_sample_cloud;
264  pcl::toROSMsg(*colored_cloud, ros_sample_cloud);
265  pcl::PointCloud<pcl::PointXYZRGB> rgb_cloud;
266  pcl::fromROSMsg(ros_sample_cloud, rgb_cloud);
267  pcl::toROSMsg(rgb_cloud, ros_sample_cloud);
268  ros_sample_cloud.header = dummy_header;
269  pub_sample_cloud_.publish(ros_sample_cloud);
270  }
271 
273  {
274  NODELET_INFO("Start LINEMOD training from %lu samples", samples_before_sampling_.size());
275  if (!camera_info_) {
276  NODELET_FATAL("no camera info is available");
277  return;
278  }
279  if (samples_before_sampling_.size() != 1) {
280  NODELET_FATAL("we expect only one training pointcloud, but it has %lu pointclouds",
281  samples_before_sampling_.size());
282  return;
283  }
284 
286  model.fromCameraInfo(camera_info_);
287 
288  if (samples_before_sampling_.size() != 1) {
289  NODELET_FATAL("we expect only one sample data");
290  return;
291  }
298  n_points_);
299  std::vector<Eigen::Affine3f> transforms;
300  transforms.resize(sampler.sampleNum());
301  for (size_t i = 0; i < sampler.sampleNum(); i++) {
302  Eigen::Affine3f transform;
303  sampler.get(transform);
304  transforms[i] = transform;
305  sampler.next();
306  }
307 
308  // NB:
309  // This line is super important.
310  // dummy Range Image to avoid static method initialization in
311  // multi-thread environment. In detail,
312  // pcl::RangeImagePlanar::createLookupTables is not thread-safe.
313  pcl::RangeImagePlanar dummy_range_image;
314 
315  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr raw_cloud
317 
318  // prepare for multi-threaded optimization
319  std::vector<pcl::ColorGradientModality<pcl::PointXYZRGBA> >
320  color_modalities (sampler.sampleNum());
321  std::vector<pcl::SurfaceNormalModality<pcl::PointXYZRGBA> >
322  surface_norm_modalities (sampler.sampleNum());
323  std::vector<pcl::MaskMap> mask_maps (sampler.sampleNum());
324  std::vector<pcl::RegionXY> regions (sampler.sampleNum());
325  boost::mutex train_mutex;
326  pcl::LINEMOD linemod;
327  int counter = 0;
328  std::vector<Eigen::Affine3f> pose_in_order_of_training;
329 #ifdef _OPENMP
330 #pragma omp parallel for
331 #endif
332  for (size_t j = 0; j < sampler.sampleNum(); j++) {
333 
334  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGBA>);
335  pcl::PointIndices::Ptr indices(new pcl::PointIndices);
336  organizedPointCloudWithViewPoint(transforms[j], raw_cloud, model,
337  cloud, *indices);
338  // generate mask and modalities
339  pcl::ColorGradientModality<pcl::PointXYZRGBA> color_modality;
340  pcl::SurfaceNormalModality<pcl::PointXYZRGBA> surface_norm_mod;
341  pcl::MaskMap mask_map(model.fullResolution().width,
342  model.fullResolution().height);
343  pcl::RegionXY region;
345  color_modality, surface_norm_mod,
346  mask_map, region);
347  std::vector<pcl::QuantizableModality*> modalities(2);
348  modalities[0] = &color_modality;
349  modalities[1] = &surface_norm_mod;
350  std::vector<pcl::MaskMap*> masks(2);
351  masks[0] = &mask_map;
352  masks[1] = &mask_map;
353  {
354  boost::mutex::scoped_lock lock(train_mutex);
355  ++counter;
356  NODELET_INFO("training: %d/%lu", counter, sampler.sampleNum());
357  linemod.createAndAddTemplate(modalities, masks, region);
358  pose_in_order_of_training.push_back(transforms[j]);
359  }
360  }
361  // dump result into file
362  // 1. linemod file
363  // 2. original pointcloud into .pcd file
364  // 3. pose yaml about the template
365  std::ofstream linemod_file;
366  const std::string linemod_file_name = output_file_ + ".linemod";
367  NODELET_INFO("writing to %s", linemod_file_name.c_str());
368  linemod_file.open(linemod_file_name.c_str(),
369  std::ofstream::out | std::ofstream::binary);
370  linemod.serialize(linemod_file);
371  linemod_file.close();
372  const std::string pcd_file_name = output_file_ + ".pcd";
373  NODELET_INFO("writing to %s", pcd_file_name.c_str());
374  pcl::PCDWriter writer;
375  writer.writeBinaryCompressed(pcd_file_name, *raw_cloud);
376  // pose yaml
377  std::ofstream pose_file;
378  const std::string pose_file_name = output_file_ + "_poses.yaml";
379  NODELET_INFO("writing to %s", pose_file_name.c_str());
380  pose_file.open(pose_file_name.c_str(), std::ofstream::out);
381  pose_file << "template_poses: [" << std::endl;
382  for (size_t i = 0; i < pose_in_order_of_training.size(); i++) {
383  Eigen::Affine3f pose = pose_in_order_of_training[i];
384  Eigen::Vector3f pos(pose.translation());
385  Eigen::Quaternionf rot(pose.rotation());
386  pose_file << "["
387  << pos[0] << ", " << pos[1] << ", " << pos[2] << ", "
388  << rot.x() << ", " << rot.y() << ", " << rot.z() << ", " << rot.w() << "]";
389  if (i != pose_in_order_of_training.size() - 1) {
390  pose_file << ", " << std::endl;
391  }
392  else {
393  pose_file << "]" << std::endl;
394  }
395  }
396  pose_file.close();
397  NODELET_INFO("done");
398  }
399 
401  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud,
402  pcl::PointIndices::Ptr mask,
403  pcl::ColorGradientModality<pcl::PointXYZRGBA>& color_grad_mod,
404  pcl::SurfaceNormalModality<pcl::PointXYZRGBA>& surface_norm_mod,
405  pcl::MaskMap& mask_map,
406  pcl::RegionXY& region)
407  {
408  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr masked_cloud
409  (new pcl::PointCloud<pcl::PointXYZRGBA>);
410  pcl::ExtractIndices<pcl::PointXYZRGBA> ex;
411  ex.setKeepOrganized(true);
412  ex.setInputCloud(cloud);
413  ex.setIndices(mask);
414  ex.filter(*masked_cloud);
415  color_grad_mod.setInputCloud(masked_cloud);
416  color_grad_mod.processInputData();
417  surface_norm_mod.setInputCloud(cloud);
418  surface_norm_mod.processInputData();
419  size_t min_x(masked_cloud->width), min_y(masked_cloud->height), max_x(0), max_y(0);
420  for (size_t j = 0; j < masked_cloud->height; ++j) {
421  for (size_t i = 0; i < masked_cloud->width; ++i) {
422  pcl::PointXYZRGBA p
423  = masked_cloud->points[j * masked_cloud->width + i];
424  if (!std::isnan(p.x) && !std::isnan(p.y) && !std::isnan(p.z)) {
425  mask_map(i, j) = 1;
426  min_x = std::min(min_x, i);
427  max_x = std::max(max_x, i);
428  min_y = std::min(min_y, j);
429  max_y = std::max(max_y, j);
430  }
431  else {
432  mask_map(i, j) = 0;
433  }
434  }
435  }
436  region.x = static_cast<int>(min_x);
437  region.y = static_cast<int>(min_y);
438  region.width = static_cast<int>(max_x - min_x + 1);
439  region.height = static_cast<int>(max_y - min_y + 1);
440  }
441 
442 
443  std::vector<std::string> LINEMODTrainer::trainOneData(
444  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud,
445  pcl::PointIndices::Ptr mask,
446  std::string& tempstr,
447  int i)
448  {
449  pcl::LINEMOD linemod;
450  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr masked_cloud
451  (new pcl::PointCloud<pcl::PointXYZRGBA>);
452  pcl::ExtractIndices<pcl::PointXYZRGBA> ex;
453  ex.setKeepOrganized(true);
454  ex.setInputCloud(cloud);
455  ex.setIndices(mask);
456  ex.filter(*masked_cloud);
457  pcl::ColorGradientModality<pcl::PointXYZRGBA> color_grad_mod;
458  color_grad_mod.setInputCloud(masked_cloud);
459  color_grad_mod.processInputData();
460  pcl::SurfaceNormalModality<pcl::PointXYZRGBA> surface_norm_mod;
461  surface_norm_mod.setInputCloud(masked_cloud);
462  surface_norm_mod.processInputData();
463  std::vector<pcl::QuantizableModality*> modalities(2);
464  modalities[0] = &color_grad_mod;
465  modalities[1] = &surface_norm_mod;
466  size_t min_x(masked_cloud->width), min_y(masked_cloud->height), max_x(0), max_y(0);
467  pcl::MaskMap mask_map(masked_cloud->width, masked_cloud->height);
468  for (size_t j = 0; j < masked_cloud->height; ++j) {
469  for (size_t i = 0; i < masked_cloud->width; ++i) {
470  pcl::PointXYZRGBA p
471  = masked_cloud->points[j * masked_cloud->width + i];
472  if (!std::isnan(p.x) && !std::isnan(p.y) && !std::isnan(p.z)) {
473  mask_map(i, j) = 1;
474  min_x = std::min(min_x, i);
475  max_x = std::max(max_x, i);
476  min_y = std::min(min_y, j);
477  max_y = std::max(max_y, j);
478  }
479  else {
480  mask_map(i, j) = 0;
481  }
482  }
483  }
484  std::vector<pcl::MaskMap*> masks(2);
485  masks[0] = &mask_map;
486  masks[1] = &mask_map;
487  pcl::RegionXY region;
488  region.x = static_cast<int>(min_x);
489  region.y = static_cast<int>(min_y);
490  region.width = static_cast<int>(max_x - min_x + 1);
491  region.height = static_cast<int>(max_y - min_y + 1);
492  linemod.createAndAddTemplate(modalities, masks, region);
493 
494  std::vector<std::string> ret;
495  {
496  // sqmmt
497  std::stringstream filename_stream;
498  filename_stream << boost::format("%s/%05d_template.sqmmt") % tempstr % i;
499  std::string filename = filename_stream.str();
500  std::cerr << "writing " << filename << std::endl;
501  std::ofstream file_stream;
502  file_stream.open(filename.c_str(),
503  std::ofstream::out | std::ofstream::binary);
504  linemod.getTemplate(0).serialize(file_stream);
505  file_stream.close();
506  ret.push_back(filename);
507  }
508  {
509  // pcd
510  std::stringstream filename_stream;
511  filename_stream << boost::format("%s/%05d_template.pcd") % tempstr % i;
512  std::string filename = filename_stream.str();
513  std::cerr << "writing " << filename << std::endl;
514  pcl::PCDWriter writer;
515  writer.writeBinaryCompressed(filename, *masked_cloud);
516  ret.push_back(filename);
517  }
518  return ret;
519  }
520 
522  {
523  NODELET_INFO("Start LINEMOD training from %lu samples", samples_.size());
524  boost::filesystem::path temp = boost::filesystem::unique_path();
525  boost::filesystem::create_directory(temp);
526  std::string tempstr = temp.native();
527  NODELET_INFO("mkdir %s", tempstr.c_str());
528  std::vector<std::string> all_files;
529  for (size_t i = 0; i < samples_.size(); i++) {
530  NODELET_INFO("Processing %lu-th data", i);
531  pcl::PointIndices::Ptr mask = sample_indices_[i];
532  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud = samples_[i];
533  //std::vector<std::string> files = trainOneData(cloud, mask, tempstr, i);
534  // for (size_t i = 0; i < files.size(); i++) {
535  // all_files.push_back(files[i]);
536  // }
537  }
538  tar(tempstr, output_file_);
539  NODELET_INFO("done");
540  }
541 
542  void LINEMODTrainer::tar(const std::string& directory, const std::string& output)
543  {
544  std::stringstream command_stream;
545  command_stream << "tar --format=ustar -cf " << output << " " << directory << "/*";
546  NODELET_INFO("executing %s", command_stream.str().c_str());
547  int ret = system(command_stream.str().c_str());
548  }
549 
551  std_srvs::Empty::Request& req,
552  std_srvs::Empty::Response& res)
553  {
554  boost::mutex::scoped_lock lock(mutex_);
555  if (sample_viewpoint_) {
557  }
558  else {
560  }
561  return true;
562  }
563 
565  {
566  DiagnosticNodelet::onInit();
567  pnh_->param("template_file", template_file_, std::string("template"));
568  // load original point and poses
569  template_cloud_.reset(new pcl::PointCloud<pcl::PointXYZRGBA>);
570  pcl::PCDReader reader;
571  reader.read(template_file_ + ".pcd", *template_cloud_);
572  const std::string pose_yaml = template_file_ + "_poses.yaml";
573  YAML::Node doc;
574 #ifdef USE_OLD_YAML
575  std::ifstream pose_fin;
576  pose_fin.open(pose_yaml.c_str(), std::ifstream::in);
577  YAML::Parser parser(pose_fin);
578  while (parser.GetNextDocument(doc)) {
579  setTemplate(doc);
580  }
581  pose_fin.close();
582 #else
583  // yaml-cpp is greater than 0.5.0
584  doc = YAML::LoadFile(pose_yaml);
585  setTemplate(doc);
586 #endif
587 
588 
589  srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
590  dynamic_reconfigure::Server<Config>::CallbackType f =
591  boost::bind (
593  srv_->setCallback (f);
594 
595  pub_cloud_ = advertise<sensor_msgs::PointCloud2>(*pnh_, "output", 1);
596  pub_detect_mask_ = advertise<sensor_msgs::Image>(*pnh_, "output/mask", 1);
597  pub_pose_ = advertise<geometry_msgs::PoseStamped>(*pnh_, "output/pose", 1);
598  pub_original_template_cloud_ = advertise<sensor_msgs::PointCloud2>(
599  *pnh_, "output/template", 1);
600 
601  onInitPostProcess();
602  }
603 
605  {
606  sub_cloud_ = pnh_->subscribe("input", 1, &LINEMODDetector::detect, this);
607  }
608 
610  {
612  }
613 
614  void LINEMODDetector::setTemplate(YAML::Node doc)
615  {
616  const YAML::Node& template_pose_yaml = doc["template_poses"];
617  for (size_t i = 0; i < template_pose_yaml.size(); i++) {
618  const YAML::Node& pose = template_pose_yaml[i];
619  Eigen::Affine3f trans = jsk_recognition_utils::affineFromYAMLNode(pose);
620  template_poses_.push_back(trans);
621  // set template_bboxes
622  pcl::PointCloud<pcl::PointXYZRGBA> transformed_cloud;
623  pcl::transformPointCloud<pcl::PointXYZRGBA>(*template_cloud_, transformed_cloud, trans);
624  // compute size of bounding box
625  Eigen::Vector4f minpt, maxpt;
626  pcl::getMinMax3D<pcl::PointXYZRGBA>(transformed_cloud, minpt, maxpt);
627  jsk_recognition_msgs::BoundingBox bbox = jsk_recognition_utils::boundingBoxFromPointCloud(transformed_cloud);
628  //ROS_INFO("bounding box size: [%f, %f, %f]", bbox.dimensions.x, bbox.dimensions.y, bbox.dimensions.z);
629  template_bboxes_.push_back(bbox);
630  }
631  }
632 
633  void LINEMODDetector::configCallback(Config &config, uint32_t level)
634  {
635  boost::mutex::scoped_lock lock(mutex_);
636  gradient_magnitude_threshold_ = config.gradient_magnitude_threshold;
637  detection_threshold_ = config.detection_threshold;
638  color_gradient_mod_.setGradientMagnitudeThreshold(gradient_magnitude_threshold_);
639  linemod_.setDetectionThreshold(detection_threshold_);
640 
641  // desearlize
642  const std::string linemod_file = template_file_ + ".linemod";
643  std::ifstream linemod_in;
644  linemod_in.open(linemod_file.c_str(), std::ifstream::in);
645  linemod_.deserialize(linemod_in);
646  linemod_in.close();
647  }
648 
649  // pcl removed the method by 1.13, no harm in defining it ourselves to use below
650 #if __cplusplus >= 201103L
651 #define pcl_isfinite(x) std::isfinite(x)
652 #endif
653 
655  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud,
656  const pcl::SparseQuantizedMultiModTemplate& linemod_template,
657  const pcl::LINEMODDetection& linemod_detection,
658  Eigen::Vector3f& center)
659  {
660  const size_t start_x = std::max(linemod_detection.x, 0);
661  const size_t start_y = std::max(linemod_detection.y, 0);
662  const size_t end_x = std::min(
663  static_cast<size_t> (start_x + linemod_template.region.width * linemod_detection.scale),
664  static_cast<size_t> (cloud->width));
665  const size_t end_y = std::min(
666  static_cast<size_t> (start_y + linemod_template.region.height * linemod_detection.scale),
667  static_cast<size_t> (cloud->height));
668  size_t counter = 0;
669  for (size_t row_index = start_y; row_index < end_y; ++row_index) {
670  for (size_t col_index = start_x; col_index < end_x; ++col_index) {
671  const pcl::PointXYZRGBA & point = (*cloud) (col_index, row_index);
672  if (pcl_isfinite (point.x) &&
673  pcl_isfinite (point.y) &&
674  pcl_isfinite (point.z)) {
675  center = center + point.getVector3fMap();
676  ++counter;
677  }
678  }
679  }
680  center = center / counter;
681  }
682 
684  const sensor_msgs::PointCloud2::ConstPtr& cloud_msg)
685  {
686  NODELET_INFO("detect");
687  vital_checker_->poke();
688  boost::mutex::scoped_lock lock(mutex_);
689  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
690  cloud (new pcl::PointCloud<pcl::PointXYZRGBA>);
691  pcl::fromROSMsg(*cloud_msg, *cloud);
692 
693  surface_normal_mod_.setInputCloud(cloud);
694  surface_normal_mod_.processInputData ();
695  color_gradient_mod_.setInputCloud (cloud);
696  color_gradient_mod_.processInputData ();
697  std::vector<pcl::LINEMODDetection> linemod_detections;
698  std::vector<pcl::QuantizableModality*> modalities;
699  modalities.push_back(&color_gradient_mod_);
700  modalities.push_back(&surface_normal_mod_);
701  linemod_.detectTemplatesSemiScaleInvariant(modalities, linemod_detections,
702  0.6944444f, 1.44f, 1.2f);
703  NODELET_INFO("detected %lu result", linemod_detections.size());
704  // lookup the best result
705  if (linemod_detections.size() > 0) {
706  double max_score = 0;
707  size_t max_template_id = 0;
708  double max_scale = 0;
709  pcl::LINEMODDetection linemod_detection;
710  for (size_t i = 0; i < linemod_detections.size(); i++) {
711  const pcl::LINEMODDetection& detection = linemod_detections[i];
712  if (max_score < detection.score) {
713  linemod_detection = detection;
714  max_score = detection.score;
715  }
716  }
717 
718  const pcl::SparseQuantizedMultiModTemplate& linemod_template =
719  linemod_.getTemplate(linemod_detection.template_id);
720  Eigen::Vector3f center(0, 0, 0);
722  cloud, linemod_template, linemod_detection, center);
723  // publish mask image here
724  cv::Mat detect_mask = cv::Mat::zeros(cloud->height, cloud->width, CV_8UC1);
725  int scaled_template_width
726  = linemod_template.region.width * linemod_detection.scale;
727  int scaled_template_height
728  = linemod_template.region.height * linemod_detection.scale;
729  cv::rectangle(
730  detect_mask,
731  cv::Point(linemod_detection.x, linemod_detection.y),
732  cv::Point(linemod_detection.x + scaled_template_width,
733  linemod_detection.y + scaled_template_height),
734  cv::Scalar(255), CV_FILLED);
735  pub_detect_mask_.publish(cv_bridge::CvImage(cloud_msg->header,
736  "8UC1",
737  detect_mask).toImageMsg());
738  // compute translation
739  jsk_recognition_msgs::BoundingBox bbox = template_bboxes_[linemod_detection.template_id];
740  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr
741  result (new pcl::PointCloud<pcl::PointXYZRGBA>);
742  pcl::transformPointCloud<pcl::PointXYZRGBA>(
743  *template_cloud_, *result, template_poses_[linemod_detection.template_id]);
744  Eigen::Vector4f minpt, maxpt;
745  pcl::getMinMax3D<pcl::PointXYZRGBA>(*result, minpt, maxpt);
746  Eigen::Vector4f template_center = (minpt + maxpt) / 2;
747  Eigen::Vector3f translation = center - Eigen::Vector3f(template_center[0],
748  template_center[1],
749  template_center[2]);
750  Eigen::Affine3f pose = template_poses_[linemod_detection.template_id] * Eigen::Translation3f(translation);
751  geometry_msgs::PoseStamped ros_pose;
752  tf::poseEigenToMsg(pose, ros_pose.pose);
753  ros_pose.header = cloud_msg->header;
754  pub_pose_.publish(ros_pose);
755  for (size_t i = 0; i < result->points.size(); i++) {
756  result->points[i].getVector3fMap()
757  = result->points[i].getVector3fMap() + translation;
758  }
759  sensor_msgs::PointCloud2 ros_result;
760  pcl::toROSMsg(*result, ros_result);
761  ros_result.header = cloud_msg->header;
762  pub_cloud_.publish(ros_result);
763  sensor_msgs::PointCloud2 ros_template;
764  pcl::toROSMsg(*template_cloud_, ros_template);
765  ros_template.header = cloud_msg->header;
767  }
768  }
769 }
770 
extract_top_polygon_likelihood.ex
ex
Definition: extract_top_polygon_likelihood.py:51
result
def result
jsk_pcl_ros::LINEMODDetector::onInit
virtual void onInit()
Definition: linemod_nodelet.cpp:564
rot
rot
jsk_pcl_ros::LINEMODTrainer::sample_viewpoint_angle_min_
double sample_viewpoint_angle_min_
Definition: linemod.h:215
NODELET_FATAL
#define NODELET_FATAL(...)
jsk_recognition_utils::boundingBoxFromPointCloud
jsk_recognition_msgs::BoundingBox boundingBoxFromPointCloud(const pcl::PointCloud< PointT > &cloud)
depth_error_calibration.lock
lock
Definition: depth_error_calibration.py:32
nodelet_topic_tools::NodeletLazy::pnh_
boost::shared_ptr< ros::NodeHandle > pnh_
jsk_pcl_ros::LINEMODTrainer::sample_indices_
std::vector< pcl::PointIndices::Ptr > sample_indices_
Definition: linemod.h:209
_2
boost::arg< 2 > _2
jsk_pcl_ros::LINEMODTrainer::pub_colored_range_image_
ros::Publisher pub_colored_range_image_
Definition: linemod.h:202
image_encodings.h
jsk_pcl_ros::ViewpointSampler::sampleNum
virtual size_t sampleNum()
Definition: viewpoint_sampler.cpp:107
jsk_pcl_ros::LINEMODTrainer::camera_info_
sensor_msgs::CameraInfo::ConstPtr camera_info_
Definition: linemod.h:206
jsk_pcl_ros::LINEMODDetector::pub_detect_mask_
ros::Publisher pub_detect_mask_
Definition: linemod.h:157
i
int i
cv_bridge::CvImage::toImageMsg
sensor_msgs::ImagePtr toImageMsg() const
jsk_pcl_ros::LINEMODTrainer::subscribeCloud
virtual void subscribeCloud(const sensor_msgs::PointCloud2::ConstPtr &cloud_msg)
Definition: linemod_nodelet.cpp:143
jsk_pcl_ros::LINEMODDetector::color_gradient_mod_
pcl::ColorGradientModality< pcl::PointXYZRGBA > color_gradient_mod_
Definition: linemod.h:174
pos
pos
jsk_pcl_ros::LINEMODTrainer::start_training_srv_
ros::ServiceServer start_training_srv_
Definition: linemod.h:199
jsk_pcl_ros::LINEMODTrainer::pub_range_image_
ros::Publisher pub_range_image_
Definition: linemod.h:201
p
p
jsk_pcl_ros::LINEMODTrainer::generateLINEMODTrainingData
virtual void generateLINEMODTrainingData(pcl::PointCloud< pcl::PointXYZRGBA >::Ptr cloud, pcl::PointIndices::Ptr mask, pcl::ColorGradientModality< pcl::PointXYZRGBA > &color_grad_mod, pcl::SurfaceNormalModality< pcl::PointXYZRGBA > &surface_norm_mod, pcl::MaskMap &mask_map, pcl::RegionXY &region)
Definition: linemod_nodelet.cpp:400
jsk_pcl_ros::ViewpointSampler::get
virtual void get(Eigen::Affine3f &transform)
Definition: viewpoint_sampler.cpp:121
jsk_pcl_ros::LINEMODDetector::linemod_
pcl::LINEMOD linemod_
Definition: linemod.h:170
jsk_pcl_ros::LINEMODTrainer::sync_
boost::shared_ptr< message_filters::Synchronizer< SyncPolicy > > sync_
Definition: linemod.h:196
jsk_pcl_ros::ViewpointSampler::next
virtual void next()
Definition: viewpoint_sampler.cpp:94
jsk_pcl_ros::LINEMODDetector::subscribe
virtual void subscribe()
Definition: linemod_nodelet.cpp:604
jsk_pcl_ros::min
double min(const OneDataStat &d)
wrapper function for min method for boost::function
Definition: one_data_stat.h:126
jsk_pcl_ros::LINEMODTrainer::clearData
virtual bool clearData(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
Definition: linemod_nodelet.cpp:161
pcl_conversions::toPCL
void toPCL(const pcl_msgs::ModelCoefficients &mc, pcl::ModelCoefficients &pcl_mc)
jsk_pcl_ros::LINEMODTrainer::sample_viewpoint_angle_max_
double sample_viewpoint_angle_max_
Definition: linemod.h:217
jsk_pcl_ros::LINEMODDetector::detect
virtual void detect(const sensor_msgs::PointCloud2::ConstPtr &cloud_msg)
Definition: linemod_nodelet.cpp:683
jsk_pcl_ros::LINEMODDetector::template_cloud_
pcl::PointCloud< pcl::PointXYZRGBA >::Ptr template_cloud_
Definition: linemod.h:171
geo_util.h
jsk_pcl_ros::LINEMODTrainer::sample_viewpoint_angle_step_
double sample_viewpoint_angle_step_
Definition: linemod.h:213
jsk_pcl_ros::LINEMODTrainer::n_points_
int n_points_
Definition: linemod.h:219
jsk_recognition_utils::affineFromYAMLNode
Eigen::Affine3f affineFromYAMLNode(const YAML::Node &pose)
ros::Subscriber::shutdown
void shutdown()
doc
doc
parser
transform
template Halfspace< double > transform(const Halfspace< double > &a, const Transform3< double > &tf)
sensor_msgs::image_encodings::RGB8
const std::string RGB8
pcl::fromROSMsg
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
jsk_pcl_ros::LINEMODTrainer::pub_sample_cloud_
ros::Publisher pub_sample_cloud_
Definition: linemod.h:203
jsk_pcl_ros::LINEMODTrainer::sub_camera_info_nonsync_
ros::Subscriber sub_camera_info_nonsync_
Definition: linemod.h:205
ros::Publisher::publish
void publish(const boost::shared_ptr< M > &message) const
jsk_pcl_ros::LINEMODDetector::unsubscribe
virtual void unsubscribe()
Definition: linemod_nodelet.cpp:609
jsk_pcl_ros::LINEMODTrainer::trainWithoutViewpointSampling
virtual void trainWithoutViewpointSampling()
Definition: linemod_nodelet.cpp:521
cloud
cloud
jsk_pcl_ros::LINEMODTrainer::samples_
std::vector< pcl::PointCloud< pcl::PointXYZRGBA >::Ptr > samples_
Definition: linemod.h:208
jsk_pcl_ros::LINEMODTrainer::sub_input_nonsync_
ros::Subscriber sub_input_nonsync_
Definition: linemod.h:204
pose
pose
class_list_macros.h
jsk_pcl_ros::LINEMODTrainer::trainOneData
virtual std::vector< std::string > trainOneData(pcl::PointCloud< pcl::PointXYZRGBA >::Ptr cloud, pcl::PointIndices::Ptr mask, std::string &tempstr, int i)
Definition: linemod_nodelet.cpp:443
jsk_pcl_ros
Definition: add_color_from_image.h:51
jsk_pcl_ros::LINEMODTrainer::sample_viewpoint_radius_max_
double sample_viewpoint_radius_max_
Definition: linemod.h:218
filename
std::string filename
jsk_pcl_ros::LINEMODDetector::configCallback
virtual void configCallback(Config &config, uint32_t level)
Definition: linemod_nodelet.cpp:633
jsk_pcl_ros::LINEMODDetector::template_poses_
std::vector< Eigen::Affine3f > template_poses_
Definition: linemod.h:172
jsk_pcl_ros::LINEMODTrainer::samples_before_sampling_
std::vector< pcl::PointCloud< pcl::PointXYZRGBA >::Ptr > samples_before_sampling_
Definition: linemod.h:207
jsk_pcl_ros::LINEMODTrainer::startTraining
virtual bool startTraining(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
Definition: linemod_nodelet.cpp:550
jsk_pcl_ros::ViewpointSampler
Definition: viewpoint_sampler.h:77
jsk_pcl_ros::LINEMODDetector::Config
LINEMODDetectorConfig Config
Definition: linemod.h:133
jsk_pcl_ros::LINEMODDetector::template_bboxes_
std::vector< jsk_recognition_msgs::BoundingBox > template_bboxes_
Definition: linemod.h:173
_1
boost::arg< 1 > _1
jsk_pcl_ros::LINEMODDetector::pub_pose_
ros::Publisher pub_pose_
Definition: linemod.h:158
linemod.h
jsk_pcl_ros::LINEMODTrainer
Definition: linemod.h:148
tf::poseEigenToMsg
void poseEigenToMsg(const Eigen::Affine3d &e, geometry_msgs::Pose &m)
dump_depth_error.writer
writer
Definition: dump_depth_error.py:40
jsk_pcl_ros::LINEMODTrainer::store
virtual void store(const sensor_msgs::PointCloud2::ConstPtr &cloud_msg, const PCLIndicesMsg::ConstPtr &indices_msg)
Definition: linemod_nodelet.cpp:128
jsk_pcl_ros::LINEMODTrainer::sample_viewpoint_radius_step_
double sample_viewpoint_radius_step_
Definition: linemod.h:214
jsk_pcl_ros::LINEMODTrainer::tar
virtual void tar(const std::string &directory, const std::string &output)
Definition: linemod_nodelet.cpp:542
jsk_pcl_ros::LINEMODTrainer::organizedPointCloudWithViewPoint
virtual void organizedPointCloudWithViewPoint(const Eigen::Affine3f &transform, pcl::PointCloud< pcl::PointXYZRGBA >::Ptr raw_cloud, const image_geometry::PinholeCameraModel &model, pcl::PointCloud< pcl::PointXYZRGBA >::Ptr output, pcl::PointIndices &mask)
Definition: linemod_nodelet.cpp:172
point
std::chrono::system_clock::time_point point
depth_error_calibration.model
model
Definition: depth_error_calibration.py:37
jsk_pcl_ros::LINEMODTrainer::trainWithViewpointSampling
virtual void trainWithViewpointSampling()
Definition: linemod_nodelet.cpp:272
message_filters::Subscriber::subscribe
void subscribe()
NODELET_INFO
#define NODELET_INFO(...)
jsk_pcl_ros::LINEMODDetector::mutex_
boost::mutex mutex_
Definition: linemod.h:160
jsk_pcl_ros::LINEMODTrainer::sample_viewpoint_
bool sample_viewpoint_
Definition: linemod.h:212
jsk_pcl_ros::LINEMODDetector::surface_normal_mod_
pcl::SurfaceNormalModality< pcl::PointXYZRGBA > surface_normal_mod_
Definition: linemod.h:175
nodelet::Nodelet
jsk_pcl_ros::LINEMODDetector::sub_cloud_
ros::Subscriber sub_cloud_
Definition: linemod.h:155
width
width
image_geometry::PinholeCameraModel
jsk_pcl_ros::LINEMODTrainer::sample_viewpoint_radius_min_
double sample_viewpoint_radius_min_
Definition: linemod.h:216
pcl_util.h
cv_bridge.h
dump_depth_error.f
f
Definition: dump_depth_error.py:39
jsk_pcl_ros::LINEMODDetector::detection_threshold_
double detection_threshold_
Definition: linemod.h:168
jsk_pcl_ros::LINEMODDetector::pub_original_template_cloud_
ros::Publisher pub_original_template_cloud_
Definition: linemod.h:159
cv_bridge::CvImage
jsk_pcl_ros::LINEMODTrainer::~LINEMODTrainer
virtual ~LINEMODTrainer()
Definition: linemod_nodelet.cpp:117
jsk_pcl_ros::LINEMODTrainer::sub_indices_
message_filters::Subscriber< PCLIndicesMsg > sub_indices_
Definition: linemod.h:198
viewpoint_sampler.h
pcl::toROSMsg
void toROSMsg(const pcl::PointCloud< T > &cloud, sensor_msgs::Image &msg)
mutex
boost::mutex mutex
global mutex.
Definition: depth_camera_error_visualization.cpp:86
jsk_pcl_ros::LINEMODDetector
Definition: linemod.h:98
jsk_pcl_ros::LINEMODDetector::pub_cloud_
ros::Publisher pub_cloud_
Definition: linemod.h:156
jsk_pcl_ros::LINEMODTrainer::onInit
virtual void onInit()
Definition: linemod_nodelet.cpp:66
height
height
jsk_pcl_ros::LINEMODTrainer::output_file_
std::string output_file_
Definition: linemod.h:211
jsk_pcl_ros::LINEMODDetector::computeCenterOfTemplate
virtual void computeCenterOfTemplate(pcl::PointCloud< pcl::PointXYZRGBA >::Ptr cloud, const pcl::SparseQuantizedMultiModTemplate &linemod_template, const pcl::LINEMODDetection &linemod_detection, Eigen::Vector3f &center)
Definition: linemod_nodelet.cpp:654
jsk_pcl_ros::LINEMODTrainer::clear_data_srv_
ros::ServiceServer clear_data_srv_
Definition: linemod.h:200
PLUGINLIB_EXPORT_CLASS
PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros::LINEMODTrainer, nodelet::Nodelet)
jsk_pcl_ros::LINEMODTrainer::mutex_
boost::mutex mutex_
Definition: linemod.h:210
config
config
jsk_pcl_ros::LINEMODTrainer::sub_input_
message_filters::Subscriber< sensor_msgs::PointCloud2 > sub_input_
Definition: linemod.h:197
pose_with_covariance_sample.counter
int counter
Definition: pose_with_covariance_sample.py:11
jsk_pcl_ros::LINEMODDetector::setTemplate
virtual void setTemplate(YAML::Node doc)
Definition: linemod_nodelet.cpp:614
jsk_pcl_ros::LINEMODDetector::template_file_
std::string template_file_
Definition: linemod.h:166
sample_pointcloud_localization_client.req
req
Definition: sample_pointcloud_localization_client.py:15
jsk_pcl_ros::LINEMODDetector::gradient_magnitude_threshold_
double gradient_magnitude_threshold_
Definition: linemod.h:167
plot_depth_error.reader
reader
Definition: plot_depth_error.py:17
sample_empty_service_caller.res
res
Definition: sample_empty_service_caller.py:14
info_msg
info_msg
jsk_pcl_ros::LINEMODDetector::srv_
boost::shared_ptr< dynamic_reconfigure::Server< Config > > srv_
Definition: linemod.h:161
jsk_pcl_ros::LINEMODTrainer::subscribeCameraInfo
virtual void subscribeCameraInfo(const sensor_msgs::CameraInfo::ConstPtr &info_msg)
Definition: linemod_nodelet.cpp:154
ros::Time::now
static Time now()
pcl_conversions.h


jsk_pcl_ros
Author(s): Yohei Kakiuchi
autogenerated on Tue Jan 7 2025 04:05:45