kinect2_bridge.cpp
Go to the documentation of this file.
1 
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <iostream>
21 #include <sstream>
22 #include <string>
23 #include <vector>
24 #include <thread>
25 #include <mutex>
26 #include <chrono>
27 #include <sys/stat.h>
28 
29 #if defined(__linux__)
30 #include <sys/prctl.h>
31 #elif defined(__APPLE__)
32 #include <pthread.h>
33 #endif
34 
35 #include <opencv2/opencv.hpp>
36 
37 #include <ros/ros.h>
38 #include <nodelet/nodelet.h>
39 #include <std_msgs/Header.h>
40 #include <sensor_msgs/CameraInfo.h>
41 #include <sensor_msgs/SetCameraInfo.h>
42 #include <sensor_msgs/Image.h>
43 #include <sensor_msgs/CompressedImage.h>
45 
47 
49 
50 #include <libfreenect2/libfreenect2.hpp>
51 #include <libfreenect2/frame_listener_impl.h>
52 #include <libfreenect2/packet_pipeline.h>
53 #include <libfreenect2/config.h>
54 #include <libfreenect2/registration.h>
55 
59 
61 {
62 private:
63  std::vector<int> compressionParams;
65 
67  libfreenect2::Frame color;
71 
72  std::vector<std::thread> threads;
73  std::mutex lockIrDepth, lockColor;
76 
77  bool publishTF;
78  std::thread tfPublisher, mainThread;
79 
80  libfreenect2::Freenect2 freenect2;
81  libfreenect2::Freenect2Device *device;
82  libfreenect2::SyncMultiFrameListener *listenerColor, *listenerIrDepth;
83  libfreenect2::PacketPipeline *packetPipeline;
84  libfreenect2::Registration *registration;
85  libfreenect2::Freenect2Device::ColorCameraParams colorParams;
86  libfreenect2::Freenect2Device::IrCameraParams irParams;
87 
89 
91 
94 
98 
99  enum Image
100  {
101  IR_SD = 0,
103 
108 
114 
119 
121  };
122 
123  enum Status
124  {
129  };
130 
131  std::vector<ros::Publisher> imagePubs, compressedPubs;
133  sensor_msgs::CameraInfo infoHD, infoQHD, infoIR;
134  std::vector<Status> status;
135 
136 public:
138  : sizeColor(1920, 1080), sizeIr(512, 424), sizeLowRes(sizeColor.width / 2, sizeColor.height / 2), color(sizeColor.width, sizeColor.height, 4), nh(nh), priv_nh(priv_nh),
139  frameColor(0), frameIrDepth(0), pubFrameColor(0), pubFrameIrDepth(0), lastColor(0, 0), lastDepth(0, 0), nextColor(false),
140  nextIrDepth(false), depthShift(0), running(false), deviceActive(false), clientConnected(false)
141  {
142  status.resize(COUNT, UNSUBCRIBED);
143  }
144 
145  bool start()
146  {
147  if(running)
148  {
149  OUT_ERROR("kinect2_bridge is already running!");
150  return false;
151  }
152  if(!initialize())
153  {
154  OUT_ERROR("Initialization failed!");
155  return false;
156  }
157  running = true;
158 
159  if(publishTF)
160  {
161  tfPublisher = std::thread(&Kinect2Bridge::publishStaticTF, this);
162  }
163 
164  for(size_t i = 0; i < threads.size(); ++i)
165  {
166  threads[i] = std::thread(&Kinect2Bridge::threadDispatcher, this, i);
167  }
168 
169  mainThread = std::thread(&Kinect2Bridge::main, this);
170  return true;
171  }
172 
173  void stop()
174  {
175  if(!running)
176  {
177  OUT_ERROR("kinect2_bridge is not running!");
178  return;
179  }
180  running = false;
181 
182  mainThread.join();
183 
184  for(size_t i = 0; i < threads.size(); ++i)
185  {
186  threads[i].join();
187  }
188 
189  if(publishTF)
190  {
191  tfPublisher.join();
192  }
193 
194  if(deviceActive && !device->stop())
195  {
196  OUT_ERROR("could not stop device!");
197  }
198 
199  if(!device->close())
200  {
201  OUT_ERROR("could not close device!");
202  }
203 
204  delete listenerIrDepth;
205  delete listenerColor;
206  delete registration;
207 
208  delete depthRegLowRes;
209  delete depthRegHighRes;
210 
211  for(size_t i = 0; i < COUNT; ++i)
212  {
213  imagePubs[i].shutdown();
214  compressedPubs[i].shutdown();
215  infoHDPub.shutdown();
216  infoQHDPub.shutdown();
217  infoIRPub.shutdown();
218  }
219 
220  nh.shutdown();
221  }
222 
223 private:
224  bool initialize()
225  {
226  double fps_limit, maxDepth, minDepth;
227  bool use_png, bilateral_filter, edge_aware_filter;
228  int32_t jpeg_quality, png_level, queueSize, reg_dev, depth_dev, worker_threads;
229  std::string depth_method, reg_method, calib_path, sensor, base_name;
230 
231  std::string depthDefault = "cpu";
232  std::string regDefault = "default";
233 
234 #ifdef LIBFREENECT2_WITH_OPENGL_SUPPORT
235  depthDefault = "opengl";
236 #endif
237 #ifdef LIBFREENECT2_WITH_OPENCL_SUPPORT
238  depthDefault = "opencl";
239 #endif
240 #ifdef LIBFREENECT2_WITH_CUDA_SUPPORT
241  depthDefault = "cuda";
242 #endif
243 #ifdef DEPTH_REG_OPENCL
244  regDefault = "opencl";
245 #endif
246 
247  priv_nh.param("base_name", base_name, std::string(K2_DEFAULT_NS));
248  priv_nh.param("sensor", sensor, std::string(""));
249  priv_nh.param("fps_limit", fps_limit, -1.0);
250  priv_nh.param("calib_path", calib_path, std::string(K2_CALIB_PATH));
251  priv_nh.param("use_png", use_png, false);
252  priv_nh.param("jpeg_quality", jpeg_quality, 90);
253  priv_nh.param("png_level", png_level, 1);
254  priv_nh.param("depth_method", depth_method, depthDefault);
255  priv_nh.param("depth_device", depth_dev, -1);
256  priv_nh.param("reg_method", reg_method, regDefault);
257  priv_nh.param("reg_device", reg_dev, -1);
258  priv_nh.param("max_depth", maxDepth, 12.0);
259  priv_nh.param("min_depth", minDepth, 0.1);
260  priv_nh.param("queue_size", queueSize, 2);
261  priv_nh.param("bilateral_filter", bilateral_filter, true);
262  priv_nh.param("edge_aware_filter", edge_aware_filter, true);
263  priv_nh.param("publish_tf", publishTF, false);
264  priv_nh.param("base_name_tf", baseNameTF, base_name);
265  priv_nh.param("worker_threads", worker_threads, 4);
266 
267  worker_threads = std::max(1, worker_threads);
268  threads.resize(worker_threads);
269 
270  OUT_INFO("parameter:" << std::endl
271  << " base_name: " FG_CYAN << base_name << NO_COLOR << std::endl
272  << " sensor: " FG_CYAN << (sensor.empty() ? "default" : sensor) << NO_COLOR << std::endl
273  << " fps_limit: " FG_CYAN << fps_limit << NO_COLOR << std::endl
274  << " calib_path: " FG_CYAN << calib_path << NO_COLOR << std::endl
275  << " use_png: " FG_CYAN << (use_png ? "true" : "false") << NO_COLOR << std::endl
276  << " jpeg_quality: " FG_CYAN << jpeg_quality << NO_COLOR << std::endl
277  << " png_level: " FG_CYAN << png_level << NO_COLOR << std::endl
278  << " depth_method: " FG_CYAN << depth_method << NO_COLOR << std::endl
279  << " depth_device: " FG_CYAN << depth_dev << NO_COLOR << std::endl
280  << " reg_method: " FG_CYAN << reg_method << NO_COLOR << std::endl
281  << " reg_device: " FG_CYAN << reg_dev << NO_COLOR << std::endl
282  << " max_depth: " FG_CYAN << maxDepth << NO_COLOR << std::endl
283  << " min_depth: " FG_CYAN << minDepth << NO_COLOR << std::endl
284  << " queue_size: " FG_CYAN << queueSize << NO_COLOR << std::endl
285  << " bilateral_filter: " FG_CYAN << (bilateral_filter ? "true" : "false") << NO_COLOR << std::endl
286  << "edge_aware_filter: " FG_CYAN << (edge_aware_filter ? "true" : "false") << NO_COLOR << std::endl
287  << " publish_tf: " FG_CYAN << (publishTF ? "true" : "false") << NO_COLOR << std::endl
288  << " base_name_tf: " FG_CYAN << baseNameTF << NO_COLOR << std::endl
289  << " worker_threads: " FG_CYAN << worker_threads << NO_COLOR);
290 
291  deltaT = fps_limit > 0 ? 1.0 / fps_limit : 0.0;
292 
293  if(calib_path.empty() || calib_path.back() != '/')
294  {
295  calib_path += '/';
296  }
297 
298  initCompression(jpeg_quality, png_level, use_png);
299 
300  if(!initPipeline(depth_method, depth_dev))
301  {
302  return false;
303  }
304 
305  if(!initDevice(sensor))
306  {
307  return false;
308  }
309 
310  initConfig(bilateral_filter, edge_aware_filter, minDepth, maxDepth);
311 
312  initCalibration(calib_path, sensor);
313 
314  if(!initRegistration(reg_method, reg_dev, maxDepth))
315  {
316  if(!device->close())
317  {
318  OUT_ERROR("could not close device!");
319  }
320  delete listenerIrDepth;
321  delete listenerColor;
322  return false;
323  }
324 
326  initTopics(queueSize, base_name);
327 
328  return true;
329  }
330 
331  bool initRegistration(const std::string &method, const int32_t device, const double maxDepth)
332  {
334 
335  if(method == "default")
336  {
338  }
339  else if(method == "cpu")
340  {
341 #ifdef DEPTH_REG_CPU
343 #else
344  OUT_ERROR("CPU registration is not available!");
345  return false;
346 #endif
347  }
348  else if(method == "opencl")
349  {
350 #ifdef DEPTH_REG_OPENCL
352 #else
353  OUT_ERROR("OpenCL registration is not available!");
354  return false;
355 #endif
356  }
357  else
358  {
359  OUT_ERROR("Unknown registration method: " << method);
360  return false;
361  }
362 
363  depthRegLowRes = DepthRegistration::New(reg);
364  depthRegHighRes = DepthRegistration::New(reg);
365 
366  if(!depthRegLowRes->init(cameraMatrixLowRes, sizeLowRes, cameraMatrixDepth, sizeIr, distortionDepth, rotation, translation, 0.5f, maxDepth, device) ||
367  !depthRegHighRes->init(cameraMatrixColor, sizeColor, cameraMatrixDepth, sizeIr, distortionDepth, rotation, translation, 0.5f, maxDepth, device))
368  {
369  delete depthRegLowRes;
370  delete depthRegHighRes;
371  return false;
372  }
373 
374  registration = new libfreenect2::Registration(irParams, colorParams);
375 
376  return true;
377  }
378 
379  bool initPipeline(const std::string &method, const int32_t device)
380  {
381  if(method == "default")
382  {
383 #ifdef LIBFREENECT2_WITH_CUDA_SUPPORT
384  packetPipeline = new libfreenect2::CudaPacketPipeline(device);
385 #elif defined(LIBFREENECT2_WITH_OPENCL_SUPPORT)
386  packetPipeline = new libfreenect2::OpenCLPacketPipeline(device);
387 #elif defined(LIBFREENECT2_WITH_OPENGL_SUPPORT)
388  packetPipeline = new libfreenect2::OpenGLPacketPipeline();
389 #else
390  packetPipeline = new libfreenect2::CpuPacketPipeline();
391 #endif
392  }
393  else if(method == "cpu")
394  {
395  packetPipeline = new libfreenect2::CpuPacketPipeline();
396  }
397  else if(method == "cuda")
398  {
399 #ifdef LIBFREENECT2_WITH_CUDA_SUPPORT
400  packetPipeline = new libfreenect2::CudaPacketPipeline(device);
401 #else
402  OUT_ERROR("Cuda depth processing is not available!");
403  return false;
404 #endif
405  }
406  else if(method == "opencl")
407  {
408 #ifdef LIBFREENECT2_WITH_OPENCL_SUPPORT
409  packetPipeline = new libfreenect2::OpenCLPacketPipeline(device);
410 #else
411  OUT_ERROR("OpenCL depth processing is not available!");
412  return false;
413 #endif
414  }
415  else if(method == "opengl")
416  {
417 #ifdef LIBFREENECT2_WITH_OPENGL_SUPPORT
418  packetPipeline = new libfreenect2::OpenGLPacketPipeline();
419 #else
420  OUT_ERROR("OpenGL depth processing is not available!");
421  return false;
422 #endif
423  }
424  else if(method == "clkde")
425  {
426 #ifdef LIBFREENECT2_WITH_OPENCL_SUPPORT
427  packetPipeline = new libfreenect2::OpenCLKdePacketPipeline(device);
428 #else
429  OUT_ERROR("OpenCL depth processing is not available!");
430  return false;
431 #endif
432  }
433  else if(method == "cudakde")
434  {
435 #ifdef LIBFREENECT2_WITH_CUDA_SUPPORT
436  packetPipeline = new libfreenect2::CudaKdePacketPipeline(device);
437 #else
438  OUT_ERROR("Cuda depth processing is not available!");
439  return false;
440 #endif
441  }
442  else
443  {
444  OUT_ERROR("Unknown depth processing method: " << method);
445  return false;
446  }
447 
448  return true;
449  }
450 
451  void initConfig(const bool bilateral_filter, const bool edge_aware_filter, const double minDepth, const double maxDepth)
452  {
453  libfreenect2::Freenect2Device::Config config;
454  config.EnableBilateralFilter = bilateral_filter;
455  config.EnableEdgeAwareFilter = edge_aware_filter;
456  config.MinDepth = minDepth;
457  config.MaxDepth = maxDepth;
458  device->setConfiguration(config);
459  }
460 
461  void initCompression(const int32_t jpegQuality, const int32_t pngLevel, const bool use_png)
462  {
463  compressionParams.resize(7, 0);
464  compressionParams[0] = CV_IMWRITE_JPEG_QUALITY;
465  compressionParams[1] = jpegQuality;
466  compressionParams[2] = CV_IMWRITE_PNG_COMPRESSION;
467  compressionParams[3] = pngLevel;
468  compressionParams[4] = CV_IMWRITE_PNG_STRATEGY;
469  compressionParams[5] = CV_IMWRITE_PNG_STRATEGY_RLE;
470  compressionParams[6] = 0;
471 
472  if(use_png)
473  {
474  compression16BitExt = ".png";
475  compression16BitString = sensor_msgs::image_encodings::TYPE_16UC1 + "; png compressed";
476  }
477  else
478  {
479  compression16BitExt = ".tif";
480  compression16BitString = sensor_msgs::image_encodings::TYPE_16UC1 + "; tiff compressed";
481  }
482  }
483 
484  void initTopics(const int32_t queueSize, const std::string &base_name)
485  {
486  std::vector<std::string> topics(COUNT);
488  topics[IR_SD_RECT] = K2_TOPIC_SD K2_TOPIC_IMAGE_IR K2_TOPIC_IMAGE_RECT;
489 
491  topics[DEPTH_SD_RECT] = K2_TOPIC_SD K2_TOPIC_IMAGE_DEPTH K2_TOPIC_IMAGE_RECT;
492  topics[DEPTH_HD] = K2_TOPIC_HD K2_TOPIC_IMAGE_DEPTH K2_TOPIC_IMAGE_RECT;
493  topics[DEPTH_QHD] = K2_TOPIC_QHD K2_TOPIC_IMAGE_DEPTH K2_TOPIC_IMAGE_RECT;
494 
496 
498  topics[COLOR_HD_RECT] = K2_TOPIC_HD K2_TOPIC_IMAGE_COLOR K2_TOPIC_IMAGE_RECT;
500  topics[COLOR_QHD_RECT] = K2_TOPIC_QHD K2_TOPIC_IMAGE_COLOR K2_TOPIC_IMAGE_RECT;
501 
503  topics[MONO_HD_RECT] = K2_TOPIC_HD K2_TOPIC_IMAGE_MONO K2_TOPIC_IMAGE_RECT;
505  topics[MONO_QHD_RECT] = K2_TOPIC_QHD K2_TOPIC_IMAGE_MONO K2_TOPIC_IMAGE_RECT;
506 
507  imagePubs.resize(COUNT);
508  compressedPubs.resize(COUNT);
510 
511  for(size_t i = 0; i < COUNT; ++i)
512  {
513  imagePubs[i] = nh.advertise<sensor_msgs::Image>(base_name + topics[i], queueSize, cb, cb);
514  compressedPubs[i] = nh.advertise<sensor_msgs::CompressedImage>(base_name + topics[i] + K2_TOPIC_COMPRESSED, queueSize, cb, cb);
515  }
516  infoHDPub = nh.advertise<sensor_msgs::CameraInfo>(base_name + K2_TOPIC_HD + K2_TOPIC_INFO, queueSize, cb, cb);
517  infoQHDPub = nh.advertise<sensor_msgs::CameraInfo>(base_name + K2_TOPIC_QHD + K2_TOPIC_INFO, queueSize, cb, cb);
518  infoIRPub = nh.advertise<sensor_msgs::CameraInfo>(base_name + K2_TOPIC_SD + K2_TOPIC_INFO, queueSize, cb, cb);
519  }
520 
521  bool initDevice(std::string &sensor)
522  {
523  bool deviceFound = false;
524  const int numOfDevs = freenect2.enumerateDevices();
525 
526  if(numOfDevs <= 0)
527  {
528  OUT_ERROR("no Kinect2 devices found!");
529  delete packetPipeline;
530  return false;
531  }
532 
533  if(sensor.empty())
534  {
535  sensor = freenect2.getDefaultDeviceSerialNumber();
536  }
537 
538  OUT_INFO("Kinect2 devices found: ");
539  for(int i = 0; i < numOfDevs; ++i)
540  {
541  const std::string &s = freenect2.getDeviceSerialNumber(i);
542  deviceFound = deviceFound || s == sensor;
543  OUT_INFO(" " << i << ": " FG_CYAN << s << (s == sensor ? FG_YELLOW " (selected)" : "") << NO_COLOR);
544  }
545 
546  if(!deviceFound)
547  {
548  OUT_ERROR("Device with serial '" << sensor << "' not found!");
549  delete packetPipeline;
550  return false;
551  }
552 
553  device = freenect2.openDevice(sensor, packetPipeline);
554 
555  if(device == 0)
556  {
557  OUT_INFO("no device connected or failure opening the default one!");
558  return false;
559  }
560 
561  listenerColor = new libfreenect2::SyncMultiFrameListener(libfreenect2::Frame::Color);
562  listenerIrDepth = new libfreenect2::SyncMultiFrameListener(libfreenect2::Frame::Ir | libfreenect2::Frame::Depth);
563 
564  device->setColorFrameListener(listenerColor);
565  device->setIrAndDepthFrameListener(listenerIrDepth);
566 
567  OUT_INFO("starting kinect2");
568  if(!device->start())
569  {
570  OUT_ERROR("could not start device!");
571  delete listenerIrDepth;
572  delete listenerColor;
573  return false;
574  }
575 
576  OUT_INFO("device serial: " FG_CYAN << sensor << NO_COLOR);
577  OUT_INFO("device firmware: " FG_CYAN << device->getFirmwareVersion() << NO_COLOR);
578 
579  colorParams = device->getColorCameraParams();
580  irParams = device->getIrCameraParams();
581 
582  if(!device->stop())
583  {
584  OUT_ERROR("could not stop device!");
585  delete listenerIrDepth;
586  delete listenerColor;
587  return false;
588  }
589 
590  OUT_DEBUG("default ir camera parameters: ");
591  OUT_DEBUG("fx: " FG_CYAN << irParams.fx << NO_COLOR ", fy: " FG_CYAN << irParams.fy << NO_COLOR ", cx: " FG_CYAN << irParams.cx << NO_COLOR ", cy: " FG_CYAN << irParams.cy << NO_COLOR);
592  OUT_DEBUG("k1: " FG_CYAN << irParams.k1 << NO_COLOR ", k2: " FG_CYAN << irParams.k2 << NO_COLOR ", p1: " FG_CYAN << irParams.p1 << NO_COLOR ", p2: " FG_CYAN << irParams.p2 << NO_COLOR ", k3: " FG_CYAN << irParams.k3 << NO_COLOR);
593 
594  OUT_DEBUG("default color camera parameters: ");
595  OUT_DEBUG("fx: " FG_CYAN << colorParams.fx << NO_COLOR ", fy: " FG_CYAN << colorParams.fy << NO_COLOR ", cx: " FG_CYAN << colorParams.cx << NO_COLOR ", cy: " FG_CYAN << colorParams.cy << NO_COLOR);
596 
597  cameraMatrixColor = cv::Mat::eye(3, 3, CV_64F);
598  distortionColor = cv::Mat::zeros(1, 5, CV_64F);
599 
600  cameraMatrixColor.at<double>(0, 0) = colorParams.fx;
601  cameraMatrixColor.at<double>(1, 1) = colorParams.fy;
602  cameraMatrixColor.at<double>(0, 2) = colorParams.cx;
603  cameraMatrixColor.at<double>(1, 2) = colorParams.cy;
604  cameraMatrixColor.at<double>(2, 2) = 1;
605 
606  cameraMatrixIr = cv::Mat::eye(3, 3, CV_64F);
607  distortionIr = cv::Mat::zeros(1, 5, CV_64F);
608 
609  cameraMatrixIr.at<double>(0, 0) = irParams.fx;
610  cameraMatrixIr.at<double>(1, 1) = irParams.fy;
611  cameraMatrixIr.at<double>(0, 2) = irParams.cx;
612  cameraMatrixIr.at<double>(1, 2) = irParams.cy;
613  cameraMatrixIr.at<double>(2, 2) = 1;
614 
615  distortionIr.at<double>(0, 0) = irParams.k1;
616  distortionIr.at<double>(0, 1) = irParams.k2;
617  distortionIr.at<double>(0, 2) = irParams.p1;
618  distortionIr.at<double>(0, 3) = irParams.p2;
619  distortionIr.at<double>(0, 4) = irParams.k3;
620 
621  cameraMatrixDepth = cameraMatrixIr.clone();
622  distortionDepth = distortionIr.clone();
623 
624  rotation = cv::Mat::eye(3, 3, CV_64F);
625  translation = cv::Mat::zeros(3, 1, CV_64F);
626  return true;
627  }
628 
629  void initCalibration(const std::string &calib_path, const std::string &sensor)
630  {
631  std::string calibPath = calib_path + sensor + '/';
632 
633  struct stat fileStat;
634  bool calibDirNotFound = stat(calibPath.c_str(), &fileStat) != 0 || !S_ISDIR(fileStat.st_mode);
635  if(calibDirNotFound || !loadCalibrationFile(calibPath + K2_CALIB_COLOR, cameraMatrixColor, distortionColor))
636  {
637  OUT_WARN("using sensor defaults for color intrinsic parameters.");
638  }
639 
640  if(calibDirNotFound || !loadCalibrationFile(calibPath + K2_CALIB_IR, cameraMatrixDepth, distortionDepth))
641  {
642  OUT_WARN("using sensor defaults for ir intrinsic parameters.");
643  }
644 
645  if(calibDirNotFound || !loadCalibrationPoseFile(calibPath + K2_CALIB_POSE, rotation, translation))
646  {
647  OUT_WARN("using defaults for rotation and translation.");
648  }
649 
650  if(calibDirNotFound || !loadCalibrationDepthFile(calibPath + K2_CALIB_DEPTH, depthShift))
651  {
652  OUT_WARN("using defaults for depth shift.");
653  depthShift = 0.0;
654  }
655 
656  cameraMatrixLowRes = cameraMatrixColor.clone();
657  cameraMatrixLowRes.at<double>(0, 0) /= 2;
658  cameraMatrixLowRes.at<double>(1, 1) /= 2;
659  cameraMatrixLowRes.at<double>(0, 2) /= 2;
660  cameraMatrixLowRes.at<double>(1, 2) /= 2;
661 
662  const int mapType = CV_16SC2;
663  cv::initUndistortRectifyMap(cameraMatrixColor, distortionColor, cv::Mat(), cameraMatrixColor, sizeColor, mapType, map1Color, map2Color);
664  cv::initUndistortRectifyMap(cameraMatrixIr, distortionIr, cv::Mat(), cameraMatrixIr, sizeIr, mapType, map1Ir, map2Ir);
665  cv::initUndistortRectifyMap(cameraMatrixColor, distortionColor, cv::Mat(), cameraMatrixLowRes, sizeLowRes, mapType, map1LowRes, map2LowRes);
666 
667  OUT_DEBUG("camera parameters used:");
668  OUT_DEBUG("camera matrix color:" FG_CYAN << std::endl << cameraMatrixColor << NO_COLOR);
669  OUT_DEBUG("distortion coefficients color:" FG_CYAN << std::endl << distortionColor << NO_COLOR);
670  OUT_DEBUG("camera matrix ir:" FG_CYAN << std::endl << cameraMatrixIr << NO_COLOR);
671  OUT_DEBUG("distortion coefficients ir:" FG_CYAN << std::endl << distortionIr << NO_COLOR);
672  OUT_DEBUG("camera matrix depth:" FG_CYAN << std::endl << cameraMatrixDepth << NO_COLOR);
673  OUT_DEBUG("distortion coefficients depth:" FG_CYAN << std::endl << distortionDepth << NO_COLOR);
674  OUT_DEBUG("rotation:" FG_CYAN << std::endl << rotation << NO_COLOR);
675  OUT_DEBUG("translation:" FG_CYAN << std::endl << translation << NO_COLOR);
676  OUT_DEBUG("depth shift:" FG_CYAN << std::endl << depthShift << NO_COLOR);
677  }
678 
679  bool loadCalibrationFile(const std::string &filename, cv::Mat &cameraMatrix, cv::Mat &distortion) const
680  {
681  cv::FileStorage fs;
682  if(fs.open(filename, cv::FileStorage::READ))
683  {
684  fs[K2_CALIB_CAMERA_MATRIX] >> cameraMatrix;
685  fs[K2_CALIB_DISTORTION] >> distortion;
686  fs.release();
687  }
688  else
689  {
690  OUT_ERROR("can't open calibration file: " << filename);
691  return false;
692  }
693  return true;
694  }
695 
696  bool loadCalibrationPoseFile(const std::string &filename, cv::Mat &rotation, cv::Mat &translation) const
697  {
698  cv::FileStorage fs;
699  if(fs.open(filename, cv::FileStorage::READ))
700  {
703  fs.release();
704  }
705  else
706  {
707  OUT_ERROR("can't open calibration pose file: " << filename);
708  return false;
709  }
710  return true;
711  }
712 
713  bool loadCalibrationDepthFile(const std::string &filename, double &depthShift) const
714  {
715  cv::FileStorage fs;
716  if(fs.open(filename, cv::FileStorage::READ))
717  {
719  fs.release();
720  }
721  else
722  {
723  OUT_ERROR("can't open calibration depth file: " << filename);
724  return false;
725  }
726  return true;
727  }
728 
730  {
731  cv::Mat projColor = cv::Mat::zeros(3, 4, CV_64F);
732  cv::Mat projIr = cv::Mat::zeros(3, 4, CV_64F);
733  cv::Mat projLowRes = cv::Mat::zeros(3, 4, CV_64F);
734 
735  cameraMatrixColor.copyTo(projColor(cv::Rect(0, 0, 3, 3)));
736  cameraMatrixIr.copyTo(projIr(cv::Rect(0, 0, 3, 3)));
737  cameraMatrixLowRes.copyTo(projLowRes(cv::Rect(0, 0, 3, 3)));
738 
739  createCameraInfo(sizeColor, cameraMatrixColor, distortionColor, cv::Mat::eye(3, 3, CV_64F), projColor, infoHD);
740  createCameraInfo(sizeIr, cameraMatrixIr, distortionIr, cv::Mat::eye(3, 3, CV_64F), projIr, infoIR);
741  createCameraInfo(sizeLowRes, cameraMatrixLowRes, distortionColor, cv::Mat::eye(3, 3, CV_64F), projLowRes, infoQHD);
742  }
743 
744  void createCameraInfo(const cv::Size &size, const cv::Mat &cameraMatrix, const cv::Mat &distortion, const cv::Mat &rotation, const cv::Mat &projection, sensor_msgs::CameraInfo &cameraInfo) const
745  {
746  cameraInfo.height = size.height;
747  cameraInfo.width = size.width;
748 
749  const double *itC = cameraMatrix.ptr<double>(0, 0);
750  for(size_t i = 0; i < 9; ++i, ++itC)
751  {
752  cameraInfo.K[i] = *itC;
753  }
754 
755  const double *itR = rotation.ptr<double>(0, 0);
756  for(size_t i = 0; i < 9; ++i, ++itR)
757  {
758  cameraInfo.R[i] = *itR;
759  }
760 
761  const double *itP = projection.ptr<double>(0, 0);
762  for(size_t i = 0; i < 12; ++i, ++itP)
763  {
764  cameraInfo.P[i] = *itP;
765  }
766 
767  cameraInfo.distortion_model = "plumb_bob";
768  cameraInfo.D.resize(distortion.cols);
769  const double *itD = distortion.ptr<double>(0, 0);
770  for(size_t i = 0; i < (size_t)distortion.cols; ++i, ++itD)
771  {
772  cameraInfo.D[i] = *itD;
773  }
774  }
775 
777  {
778  bool isSubscribedDepth = false;
779  bool isSubscribedColor = false;
780 
781  lockStatus.lock();
782  clientConnected = updateStatus(isSubscribedColor, isSubscribedDepth);
783  bool error = false;
784 
785  if(clientConnected && !deviceActive)
786  {
787  OUT_INFO("client connected. starting device...");
788  if(!device->startStreams(isSubscribedColor, isSubscribedDepth))
789  {
790  OUT_ERROR("could not start device!");
791  error = true;
792  }
793  else
794  {
795  deviceActive = true;
796  }
797  }
798  else if(!clientConnected && deviceActive)
799  {
800  OUT_INFO("no clients connected. stopping device...");
801  if(!device->stop())
802  {
803  OUT_ERROR("could not stop device!");
804  error = true;
805  }
806  else
807  {
808  deviceActive = false;
809  }
810  }
811  else if(deviceActive && (isSubscribedColor != this->isSubscribedColor || isSubscribedDepth != this->isSubscribedDepth))
812  {
813  if(!device->stop())
814  {
815  OUT_ERROR("could not stop device!");
816  error = true;
817  }
818  else if(!device->startStreams(isSubscribedColor, isSubscribedDepth))
819  {
820  OUT_ERROR("could not start device!");
821  error = true;
822  deviceActive = false;
823  }
824  }
825  this->isSubscribedColor = isSubscribedColor;
826  this->isSubscribedDepth = isSubscribedDepth;
827  lockStatus.unlock();
828 
829  if(error)
830  {
831  stop();
832  }
833  }
834 
835  bool updateStatus(bool &isSubscribedColor, bool &isSubscribedDepth)
836  {
837  isSubscribedDepth = false;
838  isSubscribedColor = false;
839 
840  for(size_t i = 0; i < COUNT; ++i)
841  {
842  Status s = UNSUBCRIBED;
843  if(imagePubs[i].getNumSubscribers() > 0)
844  {
845  s = RAW;
846  }
847  if(compressedPubs[i].getNumSubscribers() > 0)
848  {
849  s = s == RAW ? BOTH : COMPRESSED;
850  }
851 
852  if(i <= COLOR_SD_RECT && s != UNSUBCRIBED)
853  {
854  isSubscribedDepth = true;
855  }
856  if(i >= COLOR_SD_RECT && s != UNSUBCRIBED)
857  {
858  isSubscribedColor = true;
859  }
860 
861  status[i] = s;
862  }
863  if(infoHDPub.getNumSubscribers() > 0 || infoQHDPub.getNumSubscribers() > 0)
864  {
865  isSubscribedColor = true;
866  }
867  if(infoIRPub.getNumSubscribers() > 0)
868  {
869  isSubscribedDepth = true;
870  }
871 
872  return isSubscribedColor || isSubscribedDepth;
873  }
874 
875  void main()
876  {
877  setThreadName("Controll");
878  OUT_INFO("waiting for clients to connect");
879  double nextFrame = ros::Time::now().toSec() + deltaT;
880  double fpsTime = ros::Time::now().toSec();
881  size_t oldFrameIrDepth = 0, oldFrameColor = 0;
882  nextColor = true;
883  nextIrDepth = true;
884 
885  for(; running && ros::ok();)
886  {
887  if(!deviceActive)
888  {
889  std::this_thread::sleep_for(std::chrono::milliseconds(10));
890  fpsTime = ros::Time::now().toSec();
891  nextFrame = fpsTime + deltaT;
892  continue;
893  }
894 
895  double now = ros::Time::now().toSec();
896 
897  if(now - fpsTime >= 3.0)
898  {
899  fpsTime = now - fpsTime;
900  size_t framesIrDepth = frameIrDepth - oldFrameIrDepth;
901  size_t framesColor = frameColor - oldFrameColor;
902  oldFrameIrDepth = frameIrDepth;
903  oldFrameColor = frameColor;
904 
905  lockTime.lock();
906  double tColor = elapsedTimeColor;
907  double tDepth = elapsedTimeIrDepth;
908  elapsedTimeColor = 0;
909  elapsedTimeIrDepth = 0;
910  lockTime.unlock();
911 
912  if(isSubscribedDepth)
913  {
914  OUT_INFO("depth processing: " FG_YELLOW "~" << (tDepth / framesIrDepth) * 1000 << "ms" NO_COLOR " (~" << framesIrDepth / tDepth << "Hz) publishing rate: " FG_YELLOW "~" << framesIrDepth / fpsTime << "Hz" NO_COLOR);
915  }
916  if(isSubscribedColor)
917  {
918  OUT_INFO("color processing: " FG_YELLOW "~" << (tColor / framesColor) * 1000 << "ms" NO_COLOR " (~" << framesColor / tColor << "Hz) publishing rate: " FG_YELLOW "~" << framesColor / fpsTime << "Hz" NO_COLOR);
919  }
920  fpsTime = now;
921  }
922 
923  if(now >= nextFrame)
924  {
925  nextColor = true;
926  nextIrDepth = true;
927  nextFrame += deltaT;
928  }
929 
930  std::this_thread::sleep_for(std::chrono::milliseconds(10));
931 
932  if(!deviceActive)
933  {
934  oldFrameIrDepth = frameIrDepth;
935  oldFrameColor = frameColor;
936  lockTime.lock();
937  elapsedTimeColor = 0;
938  elapsedTimeIrDepth = 0;
939  lockTime.unlock();
940  continue;
941  }
942  }
943  }
944 
945  void threadDispatcher(const size_t id)
946  {
947  setThreadName("Worker" + std::to_string(id));
948  const size_t checkFirst = id % 2;
949  bool processedFrame = false;
950  int oldNice = nice(0);
951  oldNice = nice(19 - oldNice);
952 
953  for(; running && ros::ok();)
954  {
955  processedFrame = false;
956 
957  for(size_t i = 0; i < 2; ++i)
958  {
959  if(i == checkFirst)
960  {
961  if(nextIrDepth && lockIrDepth.try_lock())
962  {
963  nextIrDepth = false;
964  receiveIrDepth();
965  processedFrame = true;
966  }
967  }
968  else
969  {
970  if(nextColor && lockColor.try_lock())
971  {
972  nextColor = false;
973  receiveColor();
974  processedFrame = true;
975  }
976  }
977  }
978 
979  if(!processedFrame)
980  {
981  std::this_thread::sleep_for(std::chrono::milliseconds(1));
982  }
983  }
984  }
985 
987  {
988  libfreenect2::FrameMap frames;
989  cv::Mat depth, ir;
990  std_msgs::Header header;
991  std::vector<cv::Mat> images(COUNT);
992  std::vector<Status> status = this->status;
993  size_t frame;
994 
995  if(!receiveFrames(listenerIrDepth, frames))
996  {
997  lockIrDepth.unlock();
998  return;
999  }
1000  double now = ros::Time::now().toSec();
1001 
1002  header = createHeader(lastDepth, lastColor);
1003 
1004  libfreenect2::Frame *irFrame = frames[libfreenect2::Frame::Ir];
1005  libfreenect2::Frame *depthFrame = frames[libfreenect2::Frame::Depth];
1006 
1007  if(irFrame->status != 0 || depthFrame->status != 0)
1008  {
1009  listenerIrDepth->release(frames);
1010  lockIrDepth.unlock();
1011  running = false;
1012  OUT_ERROR("failure in depth packet processor from libfreenect2");
1013  return;
1014  }
1015  if(irFrame->format != libfreenect2::Frame::Float || depthFrame->format != libfreenect2::Frame::Float)
1016  {
1017  listenerIrDepth->release(frames);
1018  lockIrDepth.unlock();
1019  running = false;
1020  OUT_ERROR("received invalid frame format");
1021  return;
1022  }
1023 
1024  frame = frameIrDepth++;
1025 
1026  if(status[COLOR_SD_RECT] || status[DEPTH_SD] || status[DEPTH_SD_RECT] || status[DEPTH_QHD] || status[DEPTH_HD])
1027  {
1028  cv::Mat(depthFrame->height, depthFrame->width, CV_32FC1, depthFrame->data).copyTo(depth);
1029  }
1030 
1031  if(status[IR_SD] || status[IR_SD_RECT])
1032  {
1033  ir = cv::Mat(irFrame->height, irFrame->width, CV_32FC1, irFrame->data);
1034  ir.convertTo(images[IR_SD], CV_16U);
1035  }
1036 
1037  listenerIrDepth->release(frames);
1038  lockIrDepth.unlock();
1039 
1040  processIrDepth(depth, images, status);
1041 
1042  publishImages(images, header, status, frame, pubFrameIrDepth, IR_SD, COLOR_HD);
1043 
1044  double elapsed = ros::Time::now().toSec() - now;
1045  lockTime.lock();
1046  elapsedTimeIrDepth += elapsed;
1047  lockTime.unlock();
1048  }
1049 
1051  {
1052  libfreenect2::FrameMap frames;
1053  std_msgs::Header header;
1054  std::vector<cv::Mat> images(COUNT);
1055  std::vector<Status> status = this->status;
1056  size_t frame;
1057 
1058  if(!receiveFrames(listenerColor, frames))
1059  {
1060  lockColor.unlock();
1061  return;
1062  }
1063  double now = ros::Time::now().toSec();
1064 
1065  header = createHeader(lastColor, lastDepth);
1066 
1067  libfreenect2::Frame *colorFrame = frames[libfreenect2::Frame::Color];
1068 
1069  if(colorFrame->status != 0)
1070  {
1071  listenerColor->release(frames);
1072  lockIrDepth.unlock();
1073  running = false;
1074  OUT_ERROR("failure in rgb packet processor from libfreenect2");
1075  return;
1076  }
1077  if(colorFrame->format != libfreenect2::Frame::BGRX && colorFrame->format != libfreenect2::Frame::RGBX)
1078  {
1079  listenerColor->release(frames);
1080  lockIrDepth.unlock();
1081  running = false;
1082  OUT_ERROR("received invalid frame format");
1083  return;
1084  }
1085 
1086  frame = frameColor++;
1087 
1088  cv::Mat color = cv::Mat(colorFrame->height, colorFrame->width, CV_8UC4, colorFrame->data);
1089  if(status[COLOR_SD_RECT])
1090  {
1091  lockRegSD.lock();
1092  memcpy(this->color.data, colorFrame->data, sizeColor.width * sizeColor.height * 4);
1093  this->color.format = colorFrame->format;
1094  lockRegSD.unlock();
1095  }
1096  if(status[COLOR_HD] || status[COLOR_HD_RECT] || status[COLOR_QHD] || status[COLOR_QHD_RECT] ||
1097  status[MONO_HD] || status[MONO_HD_RECT] || status[MONO_QHD] || status[MONO_QHD_RECT])
1098  {
1099  cv::Mat tmp;
1100  cv::flip(color, tmp, 1);
1101  if(colorFrame->format == libfreenect2::Frame::BGRX)
1102  {
1103  cv::cvtColor(tmp, images[COLOR_HD], CV_BGRA2BGR);
1104  }
1105  else
1106  {
1107  cv::cvtColor(tmp, images[COLOR_HD], CV_RGBA2BGR);
1108  }
1109  }
1110 
1111  listenerColor->release(frames);
1112  lockColor.unlock();
1113 
1114  processColor(images, status);
1115 
1116  publishImages(images, header, status, frame, pubFrameColor, COLOR_HD, COUNT);
1117 
1118  double elapsed = ros::Time::now().toSec() - now;
1119  lockTime.lock();
1120  elapsedTimeColor += elapsed;
1121  lockTime.unlock();
1122  }
1123 
1124  bool receiveFrames(libfreenect2::SyncMultiFrameListener *listener, libfreenect2::FrameMap &frames)
1125  {
1126  bool newFrames = false;
1127  for(; !newFrames;)
1128  {
1129 #ifdef LIBFREENECT2_THREADING_STDLIB
1130  newFrames = listener->waitForNewFrame(frames, 1000);
1131 #else
1132  newFrames = true;
1133  listener->waitForNewFrame(frames);
1134 #endif
1135  if(!deviceActive || !running || !ros::ok())
1136  {
1137  if(newFrames)
1138  {
1139  listener->release(frames);
1140  }
1141  return false;
1142  }
1143  }
1144  return newFrames;
1145  }
1146 
1147  std_msgs::Header createHeader(ros::Time &last, ros::Time &other)
1148  {
1149  ros::Time timestamp = ros::Time::now();
1150  lockSync.lock();
1151  if(other.isZero())
1152  {
1153  last = timestamp;
1154  }
1155  else
1156  {
1157  timestamp = other;
1158  other = ros::Time(0, 0);
1159  }
1160  lockSync.unlock();
1161 
1162  std_msgs::Header header;
1163  header.seq = 0;
1164  header.stamp = timestamp;
1165  return header;
1166  }
1167 
1168  void processIrDepth(const cv::Mat &depth, std::vector<cv::Mat> &images, const std::vector<Status> &status)
1169  {
1170  // COLOR registered to depth
1171  if(status[COLOR_SD_RECT])
1172  {
1173  cv::Mat tmp;
1174  libfreenect2::Frame depthFrame(sizeIr.width, sizeIr.height, 4, depth.data);
1175  libfreenect2::Frame undistorted(sizeIr.width, sizeIr.height, 4);
1176  libfreenect2::Frame registered(sizeIr.width, sizeIr.height, 4);
1177  lockRegSD.lock();
1178  registration->apply(&color, &depthFrame, &undistorted, &registered);
1179  lockRegSD.unlock();
1180  cv::flip(cv::Mat(sizeIr, CV_8UC4, registered.data), tmp, 1);
1181  if(color.format == libfreenect2::Frame::BGRX)
1182  {
1183  cv::cvtColor(tmp, images[COLOR_SD_RECT], CV_BGRA2BGR);
1184  }
1185  else
1186  {
1187  cv::cvtColor(tmp, images[COLOR_SD_RECT], CV_RGBA2BGR);
1188  }
1189  }
1190 
1191  // IR
1192  if(status[IR_SD] || status[IR_SD_RECT])
1193  {
1194  cv::flip(images[IR_SD], images[IR_SD], 1);
1195  }
1196  if(status[IR_SD_RECT])
1197  {
1198  cv::remap(images[IR_SD], images[IR_SD_RECT], map1Ir, map2Ir, cv::INTER_AREA);
1199  }
1200 
1201  // DEPTH
1202  cv::Mat depthShifted;
1203  if(status[DEPTH_SD])
1204  {
1205  depth.convertTo(images[DEPTH_SD], CV_16U, 1);
1206  cv::flip(images[DEPTH_SD], images[DEPTH_SD], 1);
1207  }
1208  if(status[DEPTH_SD_RECT] || status[DEPTH_QHD] || status[DEPTH_HD])
1209  {
1210  depth.convertTo(depthShifted, CV_16U, 1, depthShift);
1211  cv::flip(depthShifted, depthShifted, 1);
1212  }
1213  if(status[DEPTH_SD_RECT])
1214  {
1215  cv::remap(depthShifted, images[DEPTH_SD_RECT], map1Ir, map2Ir, cv::INTER_NEAREST);
1216  }
1217  if(status[DEPTH_QHD])
1218  {
1219  lockRegLowRes.lock();
1220  depthRegLowRes->registerDepth(depthShifted, images[DEPTH_QHD]);
1221  lockRegLowRes.unlock();
1222  }
1223  if(status[DEPTH_HD])
1224  {
1225  lockRegHighRes.lock();
1226  depthRegHighRes->registerDepth(depthShifted, images[DEPTH_HD]);
1227  lockRegHighRes.unlock();
1228  }
1229  }
1230 
1231  void processColor(std::vector<cv::Mat> &images, const std::vector<Status> &status)
1232  {
1233  // COLOR
1234  if(status[COLOR_HD_RECT] || status[MONO_HD_RECT])
1235  {
1236  cv::remap(images[COLOR_HD], images[COLOR_HD_RECT], map1Color, map2Color, cv::INTER_AREA);
1237  }
1238  if(status[COLOR_QHD] || status[MONO_QHD])
1239  {
1240  cv::resize(images[COLOR_HD], images[COLOR_QHD], sizeLowRes, 0, 0, cv::INTER_AREA);
1241  }
1242  if(status[COLOR_QHD_RECT] || status[MONO_QHD_RECT])
1243  {
1244  cv::remap(images[COLOR_HD], images[COLOR_QHD_RECT], map1LowRes, map2LowRes, cv::INTER_AREA);
1245  }
1246 
1247  // MONO
1248  if(status[MONO_HD])
1249  {
1250  cv::cvtColor(images[COLOR_HD], images[MONO_HD], CV_BGR2GRAY);
1251  }
1252  if(status[MONO_HD_RECT])
1253  {
1254  cv::cvtColor(images[COLOR_HD_RECT], images[MONO_HD_RECT], CV_BGR2GRAY);
1255  }
1256  if(status[MONO_QHD])
1257  {
1258  cv::cvtColor(images[COLOR_QHD], images[MONO_QHD], CV_BGR2GRAY);
1259  }
1260  if(status[MONO_QHD_RECT])
1261  {
1262  cv::cvtColor(images[COLOR_QHD_RECT], images[MONO_QHD_RECT], CV_BGR2GRAY);
1263  }
1264  }
1265 
1266  void publishImages(const std::vector<cv::Mat> &images, const std_msgs::Header &header, const std::vector<Status> &status, const size_t frame, size_t &pubFrame, const size_t begin, const size_t end)
1267  {
1268  std::vector<sensor_msgs::ImagePtr> imageMsgs(COUNT);
1269  std::vector<sensor_msgs::CompressedImagePtr> compressedMsgs(COUNT);
1270  sensor_msgs::CameraInfoPtr infoHDMsg, infoQHDMsg, infoIRMsg;
1271  std_msgs::Header _header = header;
1272 
1273  if(begin < COLOR_HD)
1274  {
1275  _header.frame_id = baseNameTF + K2_TF_IR_OPT_FRAME;
1276 
1277  infoIRMsg = sensor_msgs::CameraInfoPtr(new sensor_msgs::CameraInfo);
1278  *infoIRMsg = infoIR;
1279  infoIRMsg->header = _header;
1280  }
1281  else
1282  {
1283  _header.frame_id = baseNameTF + K2_TF_RGB_OPT_FRAME;
1284 
1285  infoHDMsg = sensor_msgs::CameraInfoPtr(new sensor_msgs::CameraInfo);
1286  *infoHDMsg = infoHD;
1287  infoHDMsg->header = _header;
1288 
1289  infoQHDMsg = sensor_msgs::CameraInfoPtr(new sensor_msgs::CameraInfo);
1290  *infoQHDMsg = infoQHD;
1291  infoQHDMsg->header = _header;
1292 
1293  }
1294 
1295  for(size_t i = begin; i < end; ++i)
1296  {
1297  if(i < DEPTH_HD || i == COLOR_SD_RECT)
1298  {
1299  _header.frame_id = baseNameTF + K2_TF_IR_OPT_FRAME;
1300  }
1301  else
1302  {
1303  _header.frame_id = baseNameTF + K2_TF_RGB_OPT_FRAME;
1304  }
1305 
1306  switch(status[i])
1307  {
1308  case UNSUBCRIBED:
1309  break;
1310  case RAW:
1311  imageMsgs[i] = sensor_msgs::ImagePtr(new sensor_msgs::Image);
1312  createImage(images[i], _header, Image(i), *imageMsgs[i]);
1313  break;
1314  case COMPRESSED:
1315  compressedMsgs[i] = sensor_msgs::CompressedImagePtr(new sensor_msgs::CompressedImage);
1316  createCompressed(images[i], _header, Image(i), *compressedMsgs[i]);
1317  break;
1318  case BOTH:
1319  imageMsgs[i] = sensor_msgs::ImagePtr(new sensor_msgs::Image);
1320  compressedMsgs[i] = sensor_msgs::CompressedImagePtr(new sensor_msgs::CompressedImage);
1321  createImage(images[i], _header, Image(i), *imageMsgs[i]);
1322  createCompressed(images[i], _header, Image(i), *compressedMsgs[i]);
1323  break;
1324  }
1325  }
1326 
1327  while(frame != pubFrame)
1328  {
1329  std::this_thread::sleep_for(std::chrono::microseconds(100));
1330  }
1331  lockPub.lock();
1332  for(size_t i = begin; i < end; ++i)
1333  {
1334  switch(status[i])
1335  {
1336  case UNSUBCRIBED:
1337  break;
1338  case RAW:
1339  imagePubs[i].publish(imageMsgs[i]);
1340  break;
1341  case COMPRESSED:
1342  compressedPubs[i].publish(compressedMsgs[i]);
1343  break;
1344  case BOTH:
1345  imagePubs[i].publish(imageMsgs[i]);
1346  compressedPubs[i].publish(compressedMsgs[i]);
1347  break;
1348  }
1349  }
1350 
1351  if(begin < COLOR_HD)
1352  {
1353  if(infoIRPub.getNumSubscribers() > 0)
1354  {
1355  infoIRPub.publish(infoIRMsg);
1356  }
1357  }
1358  else
1359  {
1360  if(infoHDPub.getNumSubscribers() > 0)
1361  {
1362  infoHDPub.publish(infoHDMsg);
1363  }
1364  if(infoQHDPub.getNumSubscribers() > 0)
1365  {
1366  infoQHDPub.publish(infoQHDMsg);
1367  }
1368  }
1369 
1370  ++pubFrame;
1371  lockPub.unlock();
1372  }
1373 
1374  void createImage(const cv::Mat &image, const std_msgs::Header &header, const Image type, sensor_msgs::Image &msgImage) const
1375  {
1376  size_t step, size;
1377  step = image.cols * image.elemSize();
1378  size = image.rows * step;
1379 
1380  switch(type)
1381  {
1382  case IR_SD:
1383  case IR_SD_RECT:
1384  case DEPTH_SD:
1385  case DEPTH_SD_RECT:
1386  case DEPTH_HD:
1387  case DEPTH_QHD:
1388  msgImage.encoding = sensor_msgs::image_encodings::TYPE_16UC1;
1389  break;
1390  case COLOR_SD_RECT:
1391  case COLOR_HD:
1392  case COLOR_HD_RECT:
1393  case COLOR_QHD:
1394  case COLOR_QHD_RECT:
1395  msgImage.encoding = sensor_msgs::image_encodings::BGR8;
1396  break;
1397  case MONO_HD:
1398  case MONO_HD_RECT:
1399  case MONO_QHD:
1400  case MONO_QHD_RECT:
1401  msgImage.encoding = sensor_msgs::image_encodings::TYPE_8UC1;
1402  break;
1403  case COUNT:
1404  return;
1405  }
1406 
1407  msgImage.header = header;
1408  msgImage.height = image.rows;
1409  msgImage.width = image.cols;
1410  msgImage.is_bigendian = false;
1411  msgImage.step = step;
1412  msgImage.data.resize(size);
1413  memcpy(msgImage.data.data(), image.data, size);
1414  }
1415 
1416  void createCompressed(const cv::Mat &image, const std_msgs::Header &header, const Image type, sensor_msgs::CompressedImage &msgImage) const
1417  {
1418  msgImage.header = header;
1419 
1420  switch(type)
1421  {
1422  case IR_SD:
1423  case IR_SD_RECT:
1424  case DEPTH_SD:
1425  case DEPTH_SD_RECT:
1426  case DEPTH_HD:
1427  case DEPTH_QHD:
1428  msgImage.format = compression16BitString;
1429  cv::imencode(compression16BitExt, image, msgImage.data, compressionParams);
1430  break;
1431  case COLOR_SD_RECT:
1432  case COLOR_HD:
1433  case COLOR_HD_RECT:
1434  case COLOR_QHD:
1435  case COLOR_QHD_RECT:
1436  msgImage.format = sensor_msgs::image_encodings::BGR8 + "; jpeg compressed bgr8";
1437  cv::imencode(".jpg", image, msgImage.data, compressionParams);
1438  break;
1439  case MONO_HD:
1440  case MONO_HD_RECT:
1441  case MONO_QHD:
1442  case MONO_QHD_RECT:
1443  msgImage.format = sensor_msgs::image_encodings::TYPE_8UC1 + "; jpeg compressed ";
1444  cv::imencode(".jpg", image, msgImage.data, compressionParams);
1445  break;
1446  case COUNT:
1447  return;
1448  }
1449  }
1450 
1452  {
1453  setThreadName("TFPublisher");
1454  tf::TransformBroadcaster broadcaster;
1455  tf::StampedTransform stColorOpt, stIrOpt;
1456  ros::Time now = ros::Time::now();
1457 
1458  tf::Matrix3x3 rot(rotation.at<double>(0, 0), rotation.at<double>(0, 1), rotation.at<double>(0, 2),
1459  rotation.at<double>(1, 0), rotation.at<double>(1, 1), rotation.at<double>(1, 2),
1460  rotation.at<double>(2, 0), rotation.at<double>(2, 1), rotation.at<double>(2, 2));
1461 
1462  tf::Quaternion qZero;
1463  qZero.setRPY(0, 0, 0);
1464  tf::Vector3 trans(translation.at<double>(0), translation.at<double>(1), translation.at<double>(2));
1465  tf::Vector3 vZero(0, 0, 0);
1466  tf::Transform tIr(rot, trans), tZero(qZero, vZero);
1467 
1468  stColorOpt = tf::StampedTransform(tZero, now, baseNameTF + K2_TF_LINK, baseNameTF + K2_TF_RGB_OPT_FRAME);
1469  stIrOpt = tf::StampedTransform(tIr, now, baseNameTF + K2_TF_RGB_OPT_FRAME, baseNameTF + K2_TF_IR_OPT_FRAME);
1470 
1471  for(; running && ros::ok();)
1472  {
1473  now = ros::Time::now();
1474  stColorOpt.stamp_ = now;
1475  stIrOpt.stamp_ = now;
1476 
1477  broadcaster.sendTransform(stColorOpt);
1478  broadcaster.sendTransform(stIrOpt);
1479 
1480  std::this_thread::sleep_for(std::chrono::milliseconds(10));
1481  }
1482  }
1483 
1484  static inline void setThreadName(const std::string &name)
1485  {
1486 #if defined(__linux__)
1487  prctl(PR_SET_NAME, name.c_str());
1488 #elif defined(__APPLE__)
1489  pthread_setname_np(name.c_str());
1490 #endif
1491  }
1492 };
1493 
1495 {
1496 private:
1498 
1499 public:
1500  Kinect2BridgeNodelet() : Nodelet(), pKinect2Bridge(NULL)
1501  {
1502  }
1503 
1505  {
1506  if(pKinect2Bridge)
1507  {
1508  pKinect2Bridge->stop();
1509  delete pKinect2Bridge;
1510  }
1511  }
1512 
1513  virtual void onInit()
1514  {
1515  pKinect2Bridge = new Kinect2Bridge(getNodeHandle(), getPrivateNodeHandle());
1516  if(!pKinect2Bridge->start())
1517  {
1518  delete pKinect2Bridge;
1519  pKinect2Bridge = NULL;
1520  throw nodelet::Exception("Could not start kinect2_bridge!");
1521  }
1522  }
1523 };
1524 
1527 
1528 void helpOption(const std::string &name, const std::string &stype, const std::string &value, const std::string &desc)
1529 {
1530  std::cout << FG_GREEN "_" << name << NO_COLOR ":=" FG_YELLOW "<" << stype << ">" NO_COLOR << std::endl
1531  << " default: " FG_CYAN << value << NO_COLOR << std::endl
1532  << " info: " << desc << std::endl;
1533 }
1534 
1535 void help(const std::string &path)
1536 {
1537  std::string depthMethods = "cpu";
1538  std::string depthDefault = "cpu";
1539  std::string regMethods = "default";
1540  std::string regDefault = "default";
1541 
1542 #ifdef LIBFREENECT2_WITH_OPENGL_SUPPORT
1543  depthMethods += ", opengl";
1544  depthDefault = "opengl";
1545 #endif
1546 #ifdef LIBFREENECT2_WITH_OPENCL_SUPPORT
1547  depthMethods += ", opencl";
1548  depthDefault = "opencl";
1549 #endif
1550 #ifdef LIBFREENECT2_WITH_CUDA_SUPPORT
1551  depthMethods += ", cuda";
1552  depthMethods += ", cudakde";
1553  depthDefault = "cuda";
1554 #endif
1555 #ifdef DEPTH_REG_CPU
1556  regMethods += ", cpu";
1557 #endif
1558 #ifdef DEPTH_REG_OPENCL
1559  regMethods += ", opencl";
1560  regMethods += ", clkde";
1561  regDefault = "opencl";
1562 #endif
1563 
1564  std::cout << path << FG_BLUE " [_options:=value]" << std::endl;
1565  helpOption("base_name", "string", K2_DEFAULT_NS, "set base name for all topics");
1566  helpOption("sensor", "double", "-1.0", "serial of the sensor to use");
1567  helpOption("fps_limit", "double", "-1.0", "limit the frames per second");
1568  helpOption("calib_path", "string", K2_CALIB_PATH, "path to the calibration files");
1569  helpOption("use_png", "bool", "false", "Use PNG compression instead of TIFF");
1570  helpOption("jpeg_quality", "int", "90", "JPEG quality level from 0 to 100");
1571  helpOption("png_level", "int", "1", "PNG compression level from 0 to 9");
1572  helpOption("depth_method", "string", depthDefault, "Use specific depth processing: " + depthMethods);
1573  helpOption("depth_device", "int", "-1", "openCL device to use for depth processing");
1574  helpOption("reg_method", "string", regDefault, "Use specific depth registration: " + regMethods);
1575  helpOption("reg_device", "int", "-1", "openCL device to use for depth registration");
1576  helpOption("max_depth", "double", "12.0", "max depth value");
1577  helpOption("min_depth", "double", "0.1", "min depth value");
1578  helpOption("queue_size", "int", "2", "queue size of publisher");
1579  helpOption("bilateral_filter", "bool", "true", "enable bilateral filtering of depth images");
1580  helpOption("edge_aware_filter", "bool", "true", "enable edge aware filtering of depth images");
1581  helpOption("publish_tf", "bool", "false", "publish static tf transforms for camera");
1582  helpOption("base_name_tf", "string", "as base_name", "base name for the tf frames");
1583  helpOption("worker_threads", "int", "4", "number of threads used for processing the images");
1584 }
1585 
1586 int main(int argc, char **argv)
1587 {
1588 #if EXTENDED_OUTPUT
1590  if(!getenv("ROSCONSOLE_FORMAT"))
1591  {
1593  ros::console::g_formatter.init("[${severity}] ${message}");
1594  }
1595 #endif
1596 
1597  ros::init(argc, argv, "kinect2_bridge", ros::init_options::AnonymousName);
1598 
1599  for(int argI = 1; argI < argc; ++argI)
1600  {
1601  std::string arg(argv[argI]);
1602 
1603  if(arg == "--help" || arg == "--h" || arg == "-h" || arg == "-?" || arg == "--?")
1604  {
1605  help(argv[0]);
1606  ros::shutdown();
1607  return 0;
1608  }
1609  else
1610  {
1611  OUT_ERROR("Unknown argument: " << arg);
1612  return -1;
1613  }
1614  }
1615 
1616  if(!ros::ok())
1617  {
1618  OUT_ERROR("ros::ok failed!");
1619  return -1;
1620  }
1621 
1622  Kinect2Bridge kinect2;
1623  if(kinect2.start())
1624  {
1625  ros::spin();
1626 
1627  kinect2.stop();
1628  }
1629 
1630  ros::shutdown();
1631  return 0;
1632 }
void initConfig(const bool bilateral_filter, const bool edge_aware_filter, const double minDepth, const double maxDepth)
double elapsedTimeIrDepth
cv::Mat cameraMatrixIr
cv::Mat distortionIr
#define OUT_WARN(msg)
sensor_msgs::CameraInfo infoHD
boost::function< void(const SingleSubscriberPublisher &)> SubscriberStatusCallback
ros::Time lastDepth
#define K2_TOPIC_SD
#define K2_TOPIC_IMAGE_COLOR
std::string compression16BitString
void processIrDepth(const cv::Mat &depth, std::vector< cv::Mat > &images, const std::vector< Status > &status)
std::mutex lockSync
cv::Size sizeColor
std::thread tfPublisher
void publish(const boost::shared_ptr< M > &message) const
#define K2_TOPIC_IMAGE_IR
void createCompressed(const cv::Mat &image, const std_msgs::Header &header, const Image type, sensor_msgs::CompressedImage &msgImage) const
DepthRegistration * depthRegLowRes
std::vector< ros::Publisher > compressedPubs
#define FG_GREEN
#define K2_DEFAULT_NS
f
#define FG_YELLOW
cv::Mat distortionDepth
std::string baseNameTF
#define K2_CALIB_CAMERA_MATRIX
std::string compression16BitExt
ros::Publisher infoHDPub
#define K2_CALIB_DEPTH_SHIFT
void threadDispatcher(const size_t id)
std_msgs::Header createHeader(ros::Time &last, ros::Time &other)
void initCompression(const int32_t jpegQuality, const int32_t pngLevel, const bool use_png)
#define K2_CALIB_POSE
XmlRpcServer s
#define OUT_ERROR(msg)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
PLUGINLIB_EXPORT_CLASS(depth_image_proc::ConvertMetricNodelet, nodelet::Nodelet)
cv::Mat cameraMatrixLowRes
const std::string TYPE_8UC1
std::mutex lockRegSD
ros::NodeHandle priv_nh
void processColor(std::vector< cv::Mat > &images, const std::vector< Status > &status)
#define OUT_INFO(msg)
std::thread mainThread
#define ROSCONSOLE_AUTOINIT
#define K2_TF_IR_OPT_FRAME
std::vector< Status > status
#define K2_TOPIC_COMPRESSED
cv::Mat cameraMatrixColor
ROSCPP_DECL void spin(Spinner &spinner)
bool receiveFrames(libfreenect2::SyncMultiFrameListener *listener, libfreenect2::FrameMap &frames)
ros::Time lastColor
std::mutex lockRegHighRes
std::vector< std::thread > threads
#define K2_TOPIC_QHD
std::mutex lockRegLowRes
libfreenect2::Registration * registration
#define K2_CALIB_DEPTH
void initCalibration(const std::string &calib_path, const std::string &sensor)
cv::Size sizeLowRes
void init(const char *fmt)
libfreenect2::SyncMultiFrameListener * listenerIrDepth
#define K2_CALIB_TRANSLATION
ros::Publisher infoIRPub
static DepthRegistration * New(Method method=DEFAULT)
bool updateStatus(bool &isSubscribedColor, bool &isSubscribedDepth)
void setRPY(const tfScalar &roll, const tfScalar &pitch, const tfScalar &yaw)
virtual bool registerDepth(const cv::Mat &depth, cv::Mat &registered)=0
std::mutex lockStatus
bool param(const std::string &param_name, T &param_val, const T &default_val) const
double elapsedTimeColor
std::mutex lockPub
#define K2_TOPIC_IMAGE_MONO
ROSCPP_DECL bool ok()
const std::string TYPE_16UC1
void createCameraInfo(const cv::Size &size, const cv::Mat &cameraMatrix, const cv::Mat &distortion, const cv::Mat &rotation, const cv::Mat &projection, sensor_msgs::CameraInfo &cameraInfo) const
void sendTransform(const StampedTransform &transform)
std::mutex lockColor
libfreenect2::Freenect2Device::ColorCameraParams colorParams
#define K2_CALIB_IR
Kinect2Bridge(const ros::NodeHandle &nh=ros::NodeHandle(), const ros::NodeHandle &priv_nh=ros::NodeHandle("~"))
#define K2_CALIB_DISTORTION
libfreenect2::Freenect2 freenect2
libfreenect2::Frame color
std::vector< ros::Publisher > imagePubs
Kinect2Bridge * pKinect2Bridge
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
#define K2_TOPIC_IMAGE_DEPTH
bool loadCalibrationDepthFile(const std::string &filename, double &depthShift) const
ros::Publisher infoQHDPub
libfreenect2::Freenect2Device * device
#define FG_BLUE
bool initDevice(std::string &sensor)
libfreenect2::PacketPipeline * packetPipeline
static void setThreadName(const std::string &name)
sensor_msgs::CameraInfo infoQHD
void helpOption(const std::string &name, const std::string &stype, const std::string &value, const std::string &desc)
unsigned int step
bool initPipeline(const std::string &method, const int32_t device)
#define K2_CALIB_ROTATION
cv::Mat distortionColor
bool loadCalibrationFile(const std::string &filename, cv::Mat &cameraMatrix, cv::Mat &distortion) const
uint32_t getNumSubscribers() const
bool init(const cv::Mat &cameraMatrixRegistered, const cv::Size &sizeRegistered, const cv::Mat &cameraMatrixDepth, const cv::Size &sizeDepth, const cv::Mat &distortionDepth, const cv::Mat &rotation, const cv::Mat &translation, const float zNear=0.5f, const float zFar=12.0f, const int deviceId=-1)
void publishImages(const std::vector< cv::Mat > &images, const std_msgs::Header &header, const std::vector< Status > &status, const size_t frame, size_t &pubFrame, const size_t begin, const size_t end)
#define FG_CYAN
std::vector< int > compressionParams
size_t pubFrameIrDepth
#define K2_TOPIC_INFO
std::mutex lockTime
void initTopics(const int32_t queueSize, const std::string &base_name)
#define NO_COLOR
static Time now()
ROSCPP_DECL void shutdown()
DepthRegistration * depthRegHighRes
cv::Mat cameraMatrixDepth
#define OUT_DEBUG(msg)
void createImage(const cv::Mat &image, const std_msgs::Header &header, const Image type, sensor_msgs::Image &msgImage) const
bool initRegistration(const std::string &method, const int32_t device, const double maxDepth)
ROSCONSOLE_DECL Formatter g_formatter
sensor_msgs::CameraInfo infoIR
libfreenect2::SyncMultiFrameListener * listenerColor
libfreenect2::Freenect2Device::IrCameraParams irParams
ros::NodeHandle nh
#define K2_CALIB_COLOR
#define K2_TF_LINK
void help(const std::string &path)
#define K2_TOPIC_HD
#define K2_TOPIC_IMAGE_RECT
#define K2_TF_RGB_OPT_FRAME
std::mutex lockIrDepth
bool loadCalibrationPoseFile(const std::string &filename, cv::Mat &rotation, cv::Mat &translation) const


kinect2_bridge
Author(s):
autogenerated on Wed Jan 3 2018 03:48:08