softkinetic_start.cpp
Go to the documentation of this file.
1 
49 #ifdef _MSC_VER
50 #include <windows.h>
51 #endif
52 
53 #include <stdio.h>
54 #include <signal.h>
55 #include <vector>
56 #include <exception>
57 #include <iostream>
58 #include <iomanip>
59 #include <fstream>
60 
61 // ROS include files
62 #include <ros/ros.h>
63 #include <ros/callback_queue.h>
64 #include <std_msgs/Int32.h>
65 #include <sensor_msgs/PointCloud2.h>
68 
69 #include <pcl_ros/point_cloud.h>
70 #include <pcl_ros/io/pcd_io.h>
71 #include <pcl/io/io.h>
72 #include <pcl/point_types.h>
73 #include <pcl/range_image/range_image.h>
74 #include <pcl/filters/radius_outlier_removal.h>
75 #include <pcl/filters/voxel_grid.h>
76 #include <pcl/filters/passthrough.h>
77 #include <pcl/filters/frustum_culling.h>
78 
82 
83 #include <cv_bridge/cv_bridge.h>
84 #include <opencv2/imgproc/imgproc.hpp>
85 
88 
89 #include <dynamic_reconfigure/server.h>
90 #include <softkinetic_camera/SoftkineticConfig.h>
91 
92 #include <DepthSense.hxx>
93 
94 using namespace DepthSense;
95 using namespace message_filters;
96 using namespace std;
97 
99 
100 Context g_context;
101 DepthNode g_dnode;
102 ColorNode g_cnode;
103 //AudioNode g_anode;
104 
105 uint32_t g_aFrames = 0;
106 uint32_t g_cFrames = 0;
107 uint32_t g_dFrames = 0;
108 
109 bool g_bDeviceFound = false;
110 
117 
118 sensor_msgs::CameraInfo rgb_info;
119 sensor_msgs::CameraInfo depth_info;
120 
121 sensor_msgs::Image img_rgb;
122 sensor_msgs::Image img_mono;
123 sensor_msgs::Image img_depth;
124 sensor_msgs::PointCloud2 cloud;
125 
126 cv::Mat cv_img_rgb; // Open CV image containers
127 cv::Mat cv_img_yuy2;
128 cv::Mat cv_img_mono;
129 cv::Mat cv_img_depth;
130 
131 std_msgs::Int32 test_int;
132 
133 /* Confidence threshold for DepthNode configuration */
135 
136 /* Parameters for downsampling cloud */
139 
140 /* Parameters for radius filter */
144 
145 /* Parameters for passthrough filer */
147 double limit_min;
148 double limit_max;
149 
150 /* Parameters for frustum culling filer */
152 double hfov;
153 double vfov;
154 double near_plane;
155 double far_plane;
156 
157 /* Shutdown request */
158 bool ros_node_shutdown = false;
159 
160 /* Depth sensor parameters */
162 DepthSense::DepthNode::CameraMode depth_mode;
163 DepthSense::FrameFormat depth_frame_format;
165 
166 /* Color sensor parameters */
168 DepthSense::CompressionType color_compression;
169 DepthSense::FrameFormat color_frame_format;
171 
172 /* Serial Number parameters */
174 std::string serial;
175 
176 DepthSense::DepthNode::CameraMode depthMode(const std::string& depth_mode_str)
177 {
178  if ( depth_mode_str == "long" )
179  return DepthNode::CAMERA_MODE_LONG_RANGE;
180  else // if ( depth_mode_str == "close" )
181  return DepthNode::CAMERA_MODE_CLOSE_MODE;
182 }
183 
184 DepthSense::FrameFormat depthFrameFormat(const std::string& depth_frame_format_str)
185 {
186  if ( depth_frame_format_str == "QQVGA" )
187  return FRAME_FORMAT_QQVGA;
188  else if ( depth_frame_format_str == "QVGA" )
189  return FRAME_FORMAT_QVGA;
190  else // if ( depth_frame_format_str == "VGA" )
191  return FRAME_FORMAT_VGA;
192 }
193 
194 DepthSense::CompressionType colorCompression(const std::string& color_compression_str)
195 {
196  if ( color_compression_str == "YUY2" )
197  return COMPRESSION_TYPE_YUY2;
198  else // if ( color_compression_str == "MJPEG" )
199  return COMPRESSION_TYPE_MJPEG;
200 }
201 
202 DepthSense::FrameFormat colorFrameFormat(const std::string& color_frame_format_str)
203 {
204  if ( color_frame_format_str == "QQVGA" )
205  return FRAME_FORMAT_QQVGA;
206  else if ( color_frame_format_str == "QVGA" )
207  return FRAME_FORMAT_QVGA;
208  else if ( color_frame_format_str == "VGA" )
209  return FRAME_FORMAT_VGA;
210  else if ( color_frame_format_str == "NHD" )
211  return FRAME_FORMAT_NHD;
212  else // if ( color_frame_format_str == "WXGA_H" )
213  return FRAME_FORMAT_WXGA_H;
214 }
215 
216 /*----------------------------------------------------------------------------*/
217 // New audio sample event handler
218 void onNewAudioSample(AudioNode node, AudioNode::NewSampleReceivedData data)
219 {
220  //printf("A#%u: %d\n",g_aFrames,data.audioData.size());
221  ++g_aFrames;
222 }
223 
224 /*----------------------------------------------------------------------------*/
225 // New color sample event handler
226 void onNewColorSample(ColorNode node, ColorNode::NewSampleReceivedData data)
227 {
228  // If this is the first sample, we fill all the constant values
229  // on image and camera info messages to increase working rate
230  if (img_rgb.data.size() == 0)
231  {
232  // Create two sensor_msg::Image for color and grayscale images on new camera image
233  int32_t w, h;
234  FrameFormat_toResolution(data.captureConfiguration.frameFormat, &w, &h);
235 
236  img_rgb.width = w;
237  img_rgb.height = h;
238  img_rgb.encoding = "bgr8";
239  img_rgb.data.resize(w * h * 3);
240  img_rgb.step = w * 3;
241 
242  img_mono.width = w;
243  img_mono.height = h;
244  img_mono.encoding = "mono8";
245  img_mono.data.resize(w * h);
246  img_mono.step = w;
247 
248  cv_img_rgb.create(h, w, CV_8UC3);
249  if (color_compression == COMPRESSION_TYPE_YUY2)
250  cv_img_yuy2.create(h, w, CV_8UC2);
251  }
252 
253  if (color_compression == COMPRESSION_TYPE_YUY2)
254  {
255  // Color images come compressed as YUY2, so we must convert them to BGR
256  cv_img_yuy2.data = reinterpret_cast<uchar *>(
257  const_cast<uint8_t *>(static_cast<const uint8_t *>(data.colorMap)));
258  cvtColor(cv_img_yuy2, cv_img_rgb, CV_YUV2BGR_YUY2);
259  }
260  else
261  {
262  // Nothing special to do for MJPEG stream; just cast and reuse the camera data
263  cv_img_rgb.data = reinterpret_cast<uchar *>(
264  const_cast<uint8_t *>(static_cast<const uint8_t *>(data.colorMap)));
265  }
266  // Create also a gray-scale image from the BGR one
267  cvtColor(cv_img_rgb, cv_img_mono, CV_BGR2GRAY);
268 
269  // Dump both on ROS image messages
270  std::memcpy(img_rgb.data.data(), cv_img_rgb.ptr(), img_rgb.data.size());
271  std::memcpy(img_mono.data.data(), cv_img_mono.ptr(), img_mono.data.size());
272 
273  // Ensure that all the images and camera info are timestamped and have the proper frame id
274  img_rgb.header.stamp = ros::Time::now();
275  img_mono.header = img_rgb.header;
276  rgb_info.header = img_rgb.header;
277 
278  // Publish the rgb and mono images and camera info
279  pub_rgb.publish(img_rgb);
280  pub_mono.publish(img_mono);
281 
282  pub_rgb_info.publish(rgb_info);
283 
284  ++g_cFrames;
285 }
286 
287 /*----------------------------------------------------------------------------*/
288 
289 void downsampleCloud(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_to_filter)
290 {
291  pcl::VoxelGrid<pcl::PointXYZRGB> sor;
292  sor.setInputCloud(cloud_to_filter);
294  // apply filter
295  ROS_DEBUG_STREAM("Starting downsampling");
296  int before = cloud_to_filter->size();
297  double old = ros::Time::now().toSec();
298  sor.filter(*cloud_to_filter);
299  double new_ = ros::Time::now().toSec() - old;
300  int after = cloud_to_filter->size();
301  ROS_DEBUG_STREAM("downsampled in " << new_ << " seconds; "
302  << "points reduced from " << before << " to " << after);
303 }
304 
305 void filterCloudRadiusBased(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_to_filter)
306 {
307  // Radius outlier removal filter:
308  pcl::RadiusOutlierRemoval<pcl::PointXYZRGB> ror;
309  ror.setInputCloud(cloud_to_filter);
310  ror.setRadiusSearch(search_radius);
311  ror.setMinNeighborsInRadius(min_neighbours);
312  ror.setKeepOrganized(true);
313  // apply filter
314  ROS_DEBUG_STREAM("Starting radius outlier removal filtering");
315  int before = cloud_to_filter->size();
316  double old = ros::Time::now().toSec();
317  ror.filter(*cloud_to_filter);
318  double new_ = ros::Time::now().toSec() - old;
319  int after = cloud_to_filter->size();
320  ROS_DEBUG_STREAM("filtered in " << new_ << " seconds; "
321  << "points reduced from " << before << " to " << after);
322 }
323 
324 void filterPassThrough(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_to_filter)
325 {
326  // Passthrough filter:
327  pcl::PassThrough<pcl::PointXYZRGB> pt;
328  pt.setInputCloud(cloud_to_filter);
329  pt.setFilterFieldName("x");
330  pt.setFilterLimits(limit_min, limit_max);
331  pt.setKeepOrganized(true);
332  // apply filter
333  ROS_DEBUG_STREAM("Starting passthrough filtering");
334  int before = cloud_to_filter->size();
335  double old = ros::Time::now().toSec();
336  pt.filter(*cloud_to_filter);
337  double new_= ros::Time::now().toSec() - old;
338  int after = cloud_to_filter->size();
339  ROS_DEBUG_STREAM("filtered in " << new_ << " seconds; "
340  << "points reduced from " << before << " to " << after);
341 }
342 
343 void filterFrustumCulling(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_to_filter)
344 {
345  // Frustum culling filter:
346  pcl::FrustumCulling<pcl::PointXYZRGB> fc;
347  fc.setInputCloud(cloud_to_filter);
348  // PCL assumes a coordinate system where X is forward, Y is up, and Z is right.
349  // Therefore we must convert from the traditional camera coordinate system
350  // (X right, Y down, Z forward), which is used by this RGBD camera.
351  // See:
352  // http://docs.pointclouds.org/trunk/classpcl_1_1_frustum_culling.html#ae22a939225ebbe244fcca8712133fcf3
353  // XXX We are not using the same frame for the pointcloud as kinect! see issue #46
354  Eigen::Matrix4f pose = Eigen::Matrix4f::Identity();
355  Eigen::Matrix4f T;
356  T << 1, 0, 0, 0,
357  0, 0, 1, 0,
358  0,-1, 0, 0,
359  0, 0, 0, 1;
360  pose *= T;
361 
362  fc.setCameraPose(pose);
363  fc.setHorizontalFOV(hfov);
364  fc.setVerticalFOV(vfov);
365  fc.setNearPlaneDistance(near_plane);
366  fc.setFarPlaneDistance(far_plane);
367  fc.setKeepOrganized(true);
368  // apply filter
369  ROS_DEBUG_STREAM("Starting frustum culling filtering");
370  int before = cloud_to_filter->size();
371  double old = ros::Time::now().toSec();
372  fc.filter(*cloud_to_filter);
373  double new_= ros::Time::now().toSec() - old;
374  int after = cloud_to_filter->size();
375  ROS_DEBUG_STREAM("filtered in " << new_ << " seconds; "
376  << "points reduced from " << before << " to " << after);
377 }
378 
379 void setupCameraInfo(const DepthSense::IntrinsicParameters& params, sensor_msgs::CameraInfo& cam_info)
380 {
381  cam_info.distortion_model = "plumb_bob";
382  cam_info.height = params.height;
383  cam_info.width = params.width;
384 
385  // Distortion parameters D = [k1, k2, t1, t2, k3]
386  cam_info.D.resize(5);
387  cam_info.D[0] = params.k1;
388  cam_info.D[1] = params.k2;
389  cam_info.D[2] = params.p1;
390  cam_info.D[3] = params.p2;
391  cam_info.D[4] = params.k3;
392 
393  // Intrinsic camera matrix for the raw (distorted) images:
394  // [fx 0 cx]
395  // K = [ 0 fy cy]
396  // [ 0 0 1]
397  cam_info.K[0] = params.fx;
398  cam_info.K[2] = params.cx;
399  cam_info.K[4] = params.fy;
400  cam_info.K[5] = params.cy;
401  cam_info.K[8] = 1.0;
402 
403  // Rectification matrix (stereo cameras only)
404  // [1 0 0]
405  // R = [0 1 0]
406  // [0 0 1]
407  cam_info.R[0] = 1.0;
408  cam_info.R[4] = 1.0;
409  cam_info.R[8] = 1.0;
410 
411  // Projection/camera matrix; we use the same values as in the raw image, as we are not
412  // applying any correction (WARN: is this ok?). For monocular cameras, Tx = Ty = 0.
413  // [fx' 0 cx' Tx]
414  // P = [ 0 fy' cy' Ty]
415  // [ 0 0 1 0]
416  cam_info.P[0] = params.fx;
417  cam_info.P[2] = params.cx;
418  cam_info.P[5] = params.fy;
419  cam_info.P[6] = params.cy;
420  cam_info.P[10] = 1.0;
421 }
422 
423 // New depth sample event
424 void onNewDepthSample(DepthNode node, DepthNode::NewSampleReceivedData data)
425 {
426  // If this is the first sample, we fill all the constant values
427  // on image and camera info messages to increase working rate
428  if (img_depth.data.size() == 0)
429  {
430  FrameFormat_toResolution(data.captureConfiguration.frameFormat,
431  (int32_t*)&img_depth.width, (int32_t*)&img_depth.height);
433  img_depth.is_bigendian = 0;
434  img_depth.step = sizeof(float) * img_depth.width;
435  std::size_t data_size = img_depth.width * img_depth.height;
436  img_depth.data.resize(data_size * sizeof(float));
437 
438  if (rgb_info.D.size() == 0)
439  {
440  // User didn't provide a calibration file for the color camera, so
441  // fill camera info with the parameters provided by the camera itself
442  setupCameraInfo(data.stereoCameraParameters.colorIntrinsics, rgb_info);
443  }
444 
445  if (depth_info.D.size() == 0)
446  {
447  // User didn't provide a calibration file for the depth camera, so
448  // fill camera info with the parameters provided by the camera itself
449  setupCameraInfo(data.stereoCameraParameters.depthIntrinsics, depth_info);
450  }
451  }
452 
453  int32_t w = img_depth.width;
454  int32_t h = img_depth.height;
455 
456  pcl::PointCloud<pcl::PointXYZRGB>::Ptr current_cloud(new pcl::PointCloud<pcl::PointXYZRGB>());
457  current_cloud->header.frame_id = cloud.header.frame_id;
458  current_cloud->width = w;
459  current_cloud->height = h;
460  current_cloud->is_dense = true;
461  current_cloud->points.resize(w * h);
462 
463  ++g_dFrames;
464 
465  // Dump depth map on image message, though we must do some post-processing for saturated pixels
466  std::memcpy(img_depth.data.data(), data.depthMapFloatingPoint, img_depth.data.size());
467 
468  for (int count = 0; count < w * h; count++)
469  {
470  // Saturated pixels on depthMapFloatingPoint have -1 value, but on openni are NaN
471  if (data.depthMapFloatingPoint[count] < 0.0)
472  {
473  *reinterpret_cast<float*>(&img_depth.data[count*sizeof(float)]) =
474  std::numeric_limits<float>::quiet_NaN();
475 
476  // We don't process these pixels as they correspond to all-zero 3D points; but
477  // we keep them in the pointcloud so the downsampling filter can be applied
478  continue;
479  }
480 
481  // Get mapping between depth map and color map, assuming we have a RGB image
482  if (img_rgb.data.size() == 0)
483  {
484  ROS_WARN_THROTTLE(2.0, "Color image is empty; pointcloud will be colorless");
485  continue;
486  }
487  UV uv = data.uvMap[count];
488  if (uv.u != -FLT_MAX && uv.v != -FLT_MAX)
489  {
490  // Within bounds: depth fov is significantly wider than color's
491  // one, so there are black points in the borders of the pointcloud
492  int x_pos = (int)round(uv.u*img_rgb.width);
493  int y_pos = (int)round(uv.v*img_rgb.height);
494  current_cloud->points[count].b = cv_img_rgb.at<cv::Vec3b>(y_pos, x_pos)[0];
495  current_cloud->points[count].g = cv_img_rgb.at<cv::Vec3b>(y_pos, x_pos)[1];
496  current_cloud->points[count].r = cv_img_rgb.at<cv::Vec3b>(y_pos, x_pos)[2];
497  }
498  else
499  {
500  continue;
501  }
502  // Convert softkinetic vertices into a kinect-like coordinates pointcloud
503  current_cloud->points[count].x = data.verticesFloatingPoint[count].x + 0.025;
504  current_cloud->points[count].y = - data.verticesFloatingPoint[count].y;
505  current_cloud->points[count].z = data.verticesFloatingPoint[count].z;
506  }
507 
508  // Check for usage of voxel grid filtering to downsample point cloud
509  // XXX This must be the first filter to be called, as it requires the "squared" point cloud
510  // we create (with proper values for width and height) that any other filter would destroy
512  {
513  downsampleCloud(current_cloud);
514  }
515 
516  // Check for usage of passthrough filtering
518  {
519  filterPassThrough(current_cloud);
520  }
521 
522  // Check for usage of frustum culling filtering
524  {
525  filterFrustumCulling(current_cloud);
526  }
527 
528  // Check for usage of radius outlier filtering
530  {
531  // XXX Use any other filter before this one to remove the large amount of all-zero points the
532  // camera creates for saturated pixels; if not, radius outlier filter takes really, really long
534  filterCloudRadiusBased(current_cloud);
535  else
536  ROS_WARN_THROTTLE(2.0, "Calling radius outlier removal as the only filter would take too long!");
537  }
538 
539  // Convert current_cloud to PointCloud2 and publish
540  pcl::toROSMsg(*current_cloud, cloud);
541 
542  img_depth.header.stamp = ros::Time::now();
543  cloud.header.stamp = ros::Time::now();
544  depth_info.header = img_depth.header;
545 
546  pub_cloud.publish(cloud);
547  pub_depth.publish(img_depth);
548  pub_depth_info.publish(depth_info);
549 }
550 
551 /*----------------------------------------------------------------------------*/
553 {
554  /* g_anode.newSampleReceivedEvent().connect(&onNewAudioSample);
555 
556  AudioNode::Configuration config = g_anode.getConfiguration();
557  config.sampleRate = 44100;
558 
559  try
560  {
561  g_context.requestControl(g_anode, 0);
562 
563  g_anode.setConfiguration(config);
564  g_anode.setInputMixerLevel(0.5f);
565  }
566  catch (ArgumentException& e)
567  {
568  printf("Argument Exception: %s\n", e.what());
569  }
570  catch (UnauthorizedAccessException& e)
571  {
572  printf("Unauthorized Access Exception: %s\n", e.what());
573  }
574  catch (ConfigurationException& e)
575  {
576  printf("Configuration Exception: %s\n", e.what());
577  }
578  catch (StreamingException& e)
579  {
580  printf("Streaming Exception: %s\n", e.what());
581  }
582  catch (TimeoutException&)
583  {
584  printf("TimeoutException\n");
585  } */
586 }
587 
588 /*----------------------------------------------------------------------------*/
590 {
591  g_dnode.newSampleReceivedEvent().connect(&onNewDepthSample);
592 
593  DepthNode::Configuration config = g_dnode.getConfiguration();
594 
595  config.frameFormat = depth_frame_format;
596  config.framerate = depth_frame_rate;
597  config.mode = depth_mode;
598  config.saturation = true;
599 
600  g_context.requestControl(g_dnode, 0);
601 
602  g_dnode.setEnableUvMap(true);
603  g_dnode.setEnableVerticesFloatingPoint(true);
604  g_dnode.setEnableDepthMapFloatingPoint(true);
605 
606  g_dnode.setConfidenceThreshold(confidence_threshold);
607 
608  try
609  {
610  g_context.requestControl(g_dnode, 0);
611 
612  g_dnode.setConfiguration(config);
613  }
614  catch (ArgumentException& e)
615  {
616  printf("Argument Exception: %s\n", e.what());
617  }
618  catch (UnauthorizedAccessException& e)
619  {
620  printf("Unauthorized Access Exception: %s\n", e.what());
621  }
622  catch (IOException& e)
623  {
624  printf("IO Exception: %s\n", e.what());
625  }
626  catch (InvalidOperationException& e)
627  {
628  printf("Invalid Operation Exception: %s\n", e.what());
629  }
630  catch (ConfigurationException& e)
631  {
632  printf("Configuration Exception: %s\n", e.what());
633  }
634  catch (StreamingException& e)
635  {
636  printf("Streaming Exception: %s\n", e.what());
637  }
638  catch (TimeoutException&)
639  {
640  printf("TimeoutException\n");
641  }
642 }
643 
644 /*----------------------------------------------------------------------------*/
646 {
647  // Connect new color sample handler
648  g_cnode.newSampleReceivedEvent().connect(&onNewColorSample);
649 
650  ColorNode::Configuration config = g_cnode.getConfiguration();
651 
652  config.frameFormat = color_frame_format;
653  config.compression = color_compression;
654  config.powerLineFrequency = POWER_LINE_FREQUENCY_50HZ;
655  config.framerate = color_frame_rate;
656 
657  g_cnode.setEnableColorMap(true);
658 
659  try
660  {
661  g_context.requestControl(g_cnode, 0);
662 
663  g_cnode.setConfiguration(config);
664  }
665  catch (ArgumentException& e)
666  {
667  printf("Argument Exception: %s\n", e.what());
668  }
669  catch (UnauthorizedAccessException& e)
670  {
671  printf("Unauthorized Access Exception: %s\n", e.what());
672  }
673  catch (IOException& e)
674  {
675  printf("IO Exception: %s\n", e.what());
676  }
677  catch (InvalidOperationException& e)
678  {
679  printf("Invalid Operation Exception: %s\n", e.what());
680  }
681  catch (ConfigurationException& e)
682  {
683  printf("Configuration Exception: %s\n", e.what());
684  }
685  catch (StreamingException& e)
686  {
687  printf("Streaming Exception: %s\n", e.what());
688  }
689  catch (TimeoutException&)
690  {
691  printf("TimeoutException\n");
692  }
693 }
694 
695 /*----------------------------------------------------------------------------*/
696 void configureNode(Node node)
697 {
698  if ((node.is<DepthNode>()) && (!g_dnode.isSet()) && (depth_enabled))
699  {
700  g_dnode = node.as<DepthNode>();
702  g_context.registerNode(node);
703  }
704 
705  if ((node.is<ColorNode>()) && (!g_cnode.isSet()) && (color_enabled))
706  {
707  g_cnode = node.as<ColorNode>();
709  g_context.registerNode(node);
710  }
711 
712  /* if ((node.is<AudioNode>()) && (!g_anode.isSet()))
713  {
714  g_anode = node.as<AudioNode>();
715  configureAudioNode();
716  g_context.registerNode(node);
717  } */
718 }
719 
720 /*----------------------------------------------------------------------------*/
721 void onNodeConnected(Device device, Device::NodeAddedData data)
722 {
723  configureNode(data.node);
724 }
725 
726 /*----------------------------------------------------------------------------*/
727 void onNodeDisconnected(Device device, Device::NodeRemovedData data)
728 {
729  /* if (data.node.is<AudioNode>() && (data.node.as<AudioNode>() == g_anode))
730  g_anode.unset(); */
731  if (data.node.is<ColorNode>() && (data.node.as<ColorNode>() == g_cnode))
732  g_cnode.unset();
733  if (data.node.is<DepthNode>() && (data.node.as<DepthNode>() == g_dnode))
734  g_dnode.unset();
735  printf("Node disconnected\n");
736 }
737 
738 /*----------------------------------------------------------------------------*/
739 void onDeviceConnected(Context context, Context::DeviceAddedData data)
740 {
741  if (!g_bDeviceFound)
742  {
743  data.device.nodeAddedEvent().connect(&onNodeConnected);
744  data.device.nodeRemovedEvent().connect(&onNodeDisconnected);
745  g_bDeviceFound = true;
746  }
747 }
748 
749 /*----------------------------------------------------------------------------*/
750 void onDeviceDisconnected(Context context, Context::DeviceRemovedData data)
751 {
752  g_bDeviceFound = false;
753  printf("Device disconnected\n");
754 }
755 
756 void sigintHandler(int sig)
757 {
758  g_context.quit();
759  ros::shutdown();
760 }
761 
762 void reconfigure_callback(softkinetic_camera::SoftkineticConfig& config, uint32_t level)
763 {
764  // @todo this one isn't trivial
765  // camera_link = config.camera_link;
766 
767  confidence_threshold = config.confidence_threshold;
768  g_dnode.setConfidenceThreshold(confidence_threshold);
769 
770  use_voxel_grid_filter = config.use_voxel_grid_filter;
771  voxel_grid_size = config.voxel_grid_size;
772 
773  use_radius_outlier_filter = config.use_radius_outlier_filter;
774  search_radius = config.search_radius;
775  min_neighbours = config.min_neighbours;
776 
777  use_passthrough_filter = config.use_passthrough_filter;
778  limit_min = config.limit_min;
779  limit_max = config.limit_max;
780 
781  use_frustum_culling_filter = config.use_frustum_culling_filter;
782  hfov = config.hfov;
783  vfov = config.vfov;
784  near_plane = config.near_plane;
785  far_plane = config.far_plane;
786 
787  depth_enabled = config.enable_depth;
788  depth_mode = depthMode(config.depth_mode);
789  depth_frame_format = depthFrameFormat(config.depth_frame_format);
790  depth_frame_rate = config.depth_frame_rate;
791 
792  color_enabled = config.enable_color;
793  color_compression = colorCompression(config.color_compression);
794  color_frame_format = colorFrameFormat(config.color_frame_format);
795  color_frame_rate = config.color_frame_rate;
796 
797  use_serial = config.use_serial;
798  serial = config.serial;
799 
800  ROS_DEBUG_STREAM("New configuration:\n" <<
801  //"camera_link = " << camera_link << "\n" <<
802 
803  "confidence_threshold = " << confidence_threshold << "\n" <<
804 
805  "use_voxel_grid_filter = " << (use_voxel_grid_filter ? "ON" : "OFF" ) << "\n" <<
806  "voxel_grid_size = " << voxel_grid_size << "\n" <<
807 
808  "use_radius_outlier_filter = " << (use_radius_outlier_filter ? "ON" : "OFF" ) << "\n" <<
809  "search_radius = " << search_radius << "\n" <<
810  "min_neighbours = " << min_neighbours << "\n" <<
811 
812  "use_passthrough_filter = " << (use_passthrough_filter ? "ON" : "OFF" ) << "\n" <<
813  "limit_min = " << limit_min << "\n" <<
814  "limit_max = " << limit_max << "\n" <<
815 
816  "use_frustum_culling_filter = " << (use_frustum_culling_filter ? "ON" : "OFF" ) << "\n" <<
817  "hfov = " << hfov << "\n" <<
818  "vfov = " << vfov << "\n" <<
819  "near_plane = " << near_plane << "\n" <<
820  "far_plane = " << far_plane << "\n" <<
821 
822  "enable_depth = " << (depth_enabled ? "ON" : "OFF" ) << "\n" <<
823  "depth_mode = " << config.depth_mode << "\n" <<
824  "depth_frame_format = " << config.depth_frame_format << "\n" <<
825  "depth_frame_rate = " << depth_frame_rate << "\n" <<
826 
827  "enable_color = " << (color_enabled ? "ON" : "OFF" ) << "\n" <<
828  "color_compression = " << config.color_compression << "\n" <<
829  "color_frame_format = " << config.color_frame_format << "\n" <<
830  "color_frame_rate = " << color_frame_rate << "\n" <<
831 
832  "use_serial = " << use_serial << "\n" <<
833  "serial = " << serial << "\n");
834 }
835 
836 /*----------------------------------------------------------------------------*/
837 int main(int argc, char* argv[])
838 {
839  // Initialize ROS
840  ros::init(argc, argv, "softkinetic_bringup_node");
841  ros::NodeHandle nh("~");
842 
843  // Override the default ROS SIGINT handler to call g_context.quit() and avoid escalating to SIGTERM
844  signal(SIGINT, sigintHandler);
845 
846  // Get frame id from parameter server
847  if (!nh.hasParam("camera_link"))
848  {
849  ROS_ERROR_STREAM("For " << ros::this_node::getName() << ", parameter 'camera_link' is missing.");
850  ros_node_shutdown = true;
851  }
852 
853 
854  // Fill in the color and depth images message header frame id
855  std::string optical_frame;
856  if (nh.getParam("rgb_optical_frame", optical_frame))
857  {
858  cloud.header.frame_id = optical_frame.c_str();
859  img_rgb.header.frame_id = optical_frame.c_str();
860  img_mono.header.frame_id = optical_frame.c_str();
861  }
862  else
863  {
864  img_rgb.header.frame_id = "/softkinetic_rgb_optical_frame";
865  img_mono.header.frame_id = "/softkinetic_rgb_optical_frame";
866  }
867 
868  if (nh.getParam("depth_optical_frame", optical_frame))
869  {
870  img_depth.header.frame_id = optical_frame.c_str();
871  }
872  else
873  {
874  img_depth.header.frame_id = "/softkinetic_depth_optical_frame";
875  }
876 
877  // Get confidence threshold from parameter server
878  if (!nh.hasParam("confidence_threshold"))
879  {
880  ROS_ERROR_STREAM("For " << ros::this_node::getName() << ", parameter 'confidence_threshold' is not set on server.");
881  ros_node_shutdown = true;
882  }
883  nh.param<int>("confidence_threshold", confidence_threshold, 150);
884 
885  // Check for usage of voxel grid filtering to downsample the point cloud
886  nh.param<bool>("use_voxel_grid_filter", use_voxel_grid_filter, false);
887  if (use_voxel_grid_filter)
888  {
889  // Downsampling cloud parameters
890  nh.param<double>("voxel_grid_size", voxel_grid_size, 0.01);
891  }
892 
893  // Check for usage of radius filtering
894  nh.param<bool>("use_radius_outlier_filter", use_radius_outlier_filter, false);
895  if (use_radius_outlier_filter)
896  {
897  if (!nh.hasParam("search_radius"))
898  {
899  ROS_ERROR_STREAM("For " << ros::this_node::getName() << ", parameter 'search_radius' is not set on server.");
900  ros_node_shutdown = true;
901  }
902  nh.param<double>("search_radius", search_radius, 0.5);
903 
904  if (!nh.hasParam("min_neighbours"))
905  {
906  ROS_ERROR_STREAM("For " << ros::this_node::getName() << ", parameter 'min_neighbours' is not set on server.");
907  ros_node_shutdown = true;
908  }
909  nh.param<int>("min_neighbours", min_neighbours, 0);
910  }
911 
912  // Check for usage of passthrough filtering
913  nh.param<bool>("use_passthrough_filter", use_passthrough_filter, false);
914  if(use_passthrough_filter)
915  {
916  if (!nh.hasParam("limit_min"))
917  {
918  ROS_ERROR_STREAM("For " << ros::this_node::getName() << ", parameter 'limit_min' is not set on server.");
919  ros_node_shutdown = true;
920  }
921  nh.param<double>("limit_min", limit_min, 0.0);
922 
923  if (!nh.hasParam("limit_max"))
924  {
925  ROS_ERROR_STREAM("For " << ros::this_node::getName() << ", parameter 'limit_max' is not set on server.");
926  ros_node_shutdown = true;
927  }
928  nh.param<double>("limit_max", limit_max, 0.0);
929  }
930 
931  // Check for usage of frustum culling filtering
932  nh.param<bool>("use_frustum_culling_filter", use_frustum_culling_filter, false);
933  if(use_frustum_culling_filter)
934  {
935  if(!nh.hasParam("hfov"))
936  {
937  ROS_ERROR_STREAM("For " << ros::this_node::getName() << ", parameter 'hfov' is not set on server.");
938  ros_node_shutdown = true;
939  }
940  nh.param<double>("hfov", hfov, 180.0);
941 
942  if(!nh.hasParam("vfov"))
943  {
944  ROS_ERROR_STREAM("For " << ros::this_node::getName() << ", parameter 'vfov' is not set on server.");
945  ros_node_shutdown = true;
946  }
947  nh.param<double>("vfov", vfov, 180.0);
948 
949  if(!nh.hasParam("near_plane"))
950  {
951  ROS_ERROR_STREAM("For " << ros::this_node::getName() << ", parameter 'near_plane' is not set on server.");
952  ros_node_shutdown = true;
953  }
954  nh.param<double>("near_plane", near_plane, 0.0);
955 
956  if(!nh.hasParam("far_plane"))
957  {
958  ROS_ERROR_STREAM("For " << ros::this_node::getName() << ", parameter 'far_plane' is not set on server.");
959  ros_node_shutdown = true;
960  }
961  nh.param<double>("far_plane", far_plane, 100.0);
962  }
963 
964  nh.param<bool>("enable_depth", depth_enabled, true);
965  std::string depth_mode_str;
966  nh.param<std::string>("depth_mode", depth_mode_str, "close");
967  depth_mode = depthMode(depth_mode_str);
968 
969  std::string depth_frame_format_str;
970  nh.param<std::string>("depth_frame_format", depth_frame_format_str, "QVGA");
971  depth_frame_format = depthFrameFormat(depth_frame_format_str);
972 
973  nh.param<int>("depth_frame_rate", depth_frame_rate, 25);
974 
975  nh.param<bool>("enable_color", color_enabled, true);
976  std::string color_compression_str;
977  nh.param<std::string>("color_compression", color_compression_str, "MJPEG");
978  color_compression = colorCompression(color_compression_str);
979 
980  std::string color_frame_format_str;
981  nh.param<std::string>("color_frame_format", color_frame_format_str, "WXGA_H");
982  color_frame_format = colorFrameFormat(color_frame_format_str);
983 
984  nh.param<int>("color_frame_rate", color_frame_rate, 25);
985 
986  // Initialize image transport object
988 
989  // Initialize publishers
990  pub_cloud = nh.advertise<sensor_msgs::PointCloud2>("depth/points", 1);
991  pub_rgb = it.advertise("rgb/image_color", 1);
992  pub_mono = it.advertise("rgb/image_mono", 1);
993  pub_depth = it.advertise("depth/image_raw", 1);
994  pub_depth_info = nh.advertise<sensor_msgs::CameraInfo>("depth/camera_info", 1);
995  pub_rgb_info = nh.advertise<sensor_msgs::CameraInfo>("rgb/camera_info", 1);
996 
997  std::string calibration_file;
998  if (nh.getParam("rgb_calibration_file", calibration_file))
999  {
1000  camera_info_manager::CameraInfoManager camera_info_manager(nh, "senz3d", "file://" + calibration_file);
1001  rgb_info = camera_info_manager.getCameraInfo();
1002  }
1003 
1004  if (nh.getParam("depth_calibration_file", calibration_file))
1005  {
1006  camera_info_manager::CameraInfoManager camera_info_manager(nh, "senz3d", "file://" + calibration_file);
1007  depth_info = camera_info_manager.getCameraInfo();
1008  }
1009 
1010  g_context = Context::create("softkinetic");
1011 
1012  g_context.deviceAddedEvent().connect(&onDeviceConnected);
1013  g_context.deviceRemovedEvent().connect(&onDeviceDisconnected);
1014 
1015  // Get the list of currently connected devices
1016  vector<Device> da = g_context.getDevices();
1017 
1018  // In case there are several devices, index of camera to start ought to come as an argument
1019  // By default, index 0 is taken:
1020  int device_index = 0;
1021  ROS_INFO_STREAM("Number of Devices found: " << da.size());
1022  if (da.size() == 0)
1023  {
1024  ROS_ERROR_STREAM("No devices found!!!!!!");
1025  }
1026 
1027  if (da.size() >= 1)
1028  {
1029  // If camera index comes as argument, device_index will be updated
1030  if (argc > 1)
1031  {
1032  device_index = atoi(argv[1]);
1033  }
1034  else
1035  {
1036  nh.param<bool>("use_serial", use_serial, false);
1037  if (use_serial)
1038  {
1039  nh.getParam("serial", serial);
1040  bool serialDeviceFound = false;
1041  for (int i=0; i < da.size(); i++)
1042  {
1043  if (!da[i].getSerialNumber().compare(serial))
1044  {
1045  device_index = i;
1046  serialDeviceFound = true;
1047  }
1048  }
1049  if (serialDeviceFound)
1050  {
1051  ROS_INFO_STREAM("Serial number device found");
1052  }
1053  else
1054  {
1055  ROS_ERROR_STREAM("Serial number device not found !!");
1056  ROS_ERROR_STREAM("Required Serial Number: " << serial);
1057  }
1058  }
1059  }
1060  ROS_INFO_STREAM("Serial Number: " << da[device_index].getSerialNumber());
1061 
1062  g_bDeviceFound = true;
1063 
1064  da[device_index].nodeAddedEvent().connect(&onNodeConnected);
1065  da[device_index].nodeRemovedEvent().connect(&onNodeDisconnected);
1066 
1067  vector<Node> na = da[device_index].getNodes();
1068 
1069  for (int n = 0; n < (int)na.size(); n++)
1070  configureNode(na[n]);
1071  }
1072 
1073  // Enable dynamic reconfigure
1074  ros::NodeHandle nh_cfg("~");
1075  ros::CallbackQueue callback_queue_cfg;
1076  nh_cfg.setCallbackQueue(&callback_queue_cfg);
1077 
1078  dynamic_reconfigure::Server<softkinetic_camera::SoftkineticConfig> server(nh_cfg);
1079  server.setCallback(boost::bind(&reconfigure_callback, _1, _2));
1080 
1081  // Handle the dynamic reconfigure server callback on a
1082  // separate thread from the g_context.run() called below
1083  ros::AsyncSpinner spinner(1, &callback_queue_cfg);
1084  spinner.start();
1085 
1086  // Loop while ros core is operational or Ctrl-C is used
1087  if (ros_node_shutdown)
1088  {
1089  ros::shutdown();
1090  }
1091  while (ros::ok())
1092  {
1093  g_context.startNodes();
1094  g_context.run();
1095  }
1096 
1097  // Close out all nodes
1098  if (g_cnode.isSet())
1099  g_context.unregisterNode(g_cnode);
1100  if (g_dnode.isSet())
1101  g_context.unregisterNode(g_dnode);
1102  /* if (g_anode.isSet())
1103  g_context.unregisterNode(g_anode);*/
1104 
1105  g_context.stopNodes();
1106 
1107  return 0;
1108 }
bool color_enabled
sensor_msgs::PointCloud2 cloud
double limit_min
void setupCameraInfo(const DepthSense::IntrinsicParameters &params, sensor_msgs::CameraInfo &cam_info)
#define ROS_WARN_THROTTLE(rate,...)
sensor_msgs::CameraInfo getCameraInfo(void)
void onDeviceConnected(Context context, Context::DeviceAddedData data)
DepthSense::DepthNode::CameraMode depth_mode
std_msgs::Int32 test_int
void publish(const boost::shared_ptr< M > &message) const
void sigintHandler(int sig)
ColorNode g_cnode
ros::Publisher pub_cloud
ros::Publisher pub_rgb_info
void filterPassThrough(pcl::PointCloud< pcl::PointXYZRGB >::Ptr cloud_to_filter)
std::string serial
bool ros_node_shutdown
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void onNewColorSample(ColorNode node, ColorNode::NewSampleReceivedData data)
double near_plane
int main(int argc, char *argv[])
void reconfigure_callback(softkinetic_camera::SoftkineticConfig &config, uint32_t level)
DepthSense::FrameFormat color_frame_format
double vfov
ROSCPP_DECL const std::string & getName()
DepthNode g_dnode
bool use_serial
void configureColorNode()
void downsampleCloud(pcl::PointCloud< pcl::PointXYZRGB >::Ptr cloud_to_filter)
DepthSense::FrameFormat depth_frame_format
DepthSense::CompressionType color_compression
ros::Publisher pub_depth_info
cv::Mat cv_img_mono
void spinner()
int depth_frame_rate
image_transport::Publisher pub_depth
cv::Mat cv_img_rgb
cv::Mat cv_img_depth
DepthSense::FrameFormat depthFrameFormat(const std::string &depth_frame_format_str)
double hfov
void onNodeConnected(Device device, Device::NodeAddedData data)
image_transport::Publisher pub_rgb
double search_radius
CvImagePtr cvtColor(const CvImageConstPtr &source, const std::string &encoding)
void configureNode(Node node)
void publish(const sensor_msgs::Image &message) const
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void setCallbackQueue(CallbackQueueInterface *queue)
bool depth_enabled
sensor_msgs::CameraInfo depth_info
const std::string TYPE_32FC1
void onDeviceDisconnected(Context context, Context::DeviceRemovedData data)
ROSCPP_DECL bool ok()
DepthSense::DepthNode::CameraMode depthMode(const std::string &depth_mode_str)
int min_neighbours
double limit_max
bool use_voxel_grid_filter
double voxel_grid_size
void filterCloudRadiusBased(pcl::PointCloud< pcl::PointXYZRGB >::Ptr cloud_to_filter)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
sensor_msgs::CameraInfo rgb_info
uint32_t g_dFrames
#define ROS_DEBUG_STREAM(args)
uint32_t g_cFrames
Context g_context
void configureDepthNode()
DepthSense::FrameFormat colorFrameFormat(const std::string &color_frame_format_str)
sensor_msgs::Image img_rgb
TFSIMD_FORCE_INLINE const tfScalar & w() const
image_transport::Publisher pub_mono
#define ROS_INFO_STREAM(args)
void onNodeDisconnected(Device device, Device::NodeRemovedData data)
bool getParam(const std::string &key, std::string &s) const
void toROSMsg(const sensor_msgs::PointCloud2 &cloud, sensor_msgs::Image &image)
void onNewAudioSample(AudioNode node, AudioNode::NewSampleReceivedData data)
bool use_frustum_culling_filter
static Time now()
int confidence_threshold
ROSCPP_DECL void shutdown()
double far_plane
sensor_msgs::Image img_mono
bool use_passthrough_filter
bool hasParam(const std::string &key) const
void onNewDepthSample(DepthNode node, DepthNode::NewSampleReceivedData data)
#define ROS_ERROR_STREAM(args)
uint32_t g_aFrames
DepthSense::CompressionType colorCompression(const std::string &color_compression_str)
sensor_msgs::Image img_depth
bool use_radius_outlier_filter
void filterFrustumCulling(pcl::PointCloud< pcl::PointXYZRGB >::Ptr cloud_to_filter)
cv::Mat cv_img_yuy2
bool g_bDeviceFound
int color_frame_rate
void configureAudioNode()


softkinetic_camera
Author(s): Felipe Garcia Lopez
autogenerated on Wed Jan 3 2018 03:48:37