42 #include <sensor_msgs/Image.h>
47 #include <rtabmap_msgs/RGBDImages.h>
109 bool approxSync =
true;
110 bool subscribeRGBD =
false;
111 double approxSyncMaxInterval = 0.0;
112 pnh.
param(
"approx_sync", approxSync, approxSync);
113 pnh.
param(
"approx_sync_max_interval", approxSyncMaxInterval, approxSyncMaxInterval);
114 pnh.
param(
"topic_queue_size", topicQueueSize_, topicQueueSize_);
117 pnh.
param(
"queue_size", syncQueueSize_, syncQueueSize_);
118 ROS_WARN(
"Parameter \"queue_size\" has been renamed "
119 "to \"sync_queue_size\" and will be removed "
120 "in future versions! The value (%d) is still copied to "
121 "\"sync_queue_size\".", syncQueueSize_);
125 pnh.
param(
"sync_queue_size", syncQueueSize_, syncQueueSize_);
127 pnh.
param(
"subscribe_rgbd", subscribeRGBD, subscribeRGBD);
130 ROS_ERROR(
"\"depth_cameras\" parameter doesn't exist anymore. It is replaced by \"rgbd_cameras\" with the \"rgbd_image\" input topics. \"subscribe_rgbd\" should be also set to true.");
132 pnh.
param(
"rgbd_cameras", rgbdCameras, rgbdCameras);
137 pnh.
param(
"keep_color", keepColor_, keepColor_);
139 NODELET_INFO(
"RGBDOdometry: approx_sync = %s", approxSync?
"true":
"false");
141 NODELET_INFO(
"RGBDOdometry: approx_sync_max_interval = %f", approxSyncMaxInterval);
142 NODELET_INFO(
"RGBDOdometry: topic_queue_size = %d", topicQueueSize_);
143 NODELET_INFO(
"RGBDOdometry: sync_queue_size = %d", syncQueueSize_);
144 NODELET_INFO(
"RGBDOdometry: subscribe_rgbd = %s", subscribeRGBD?
"true":
"false");
145 NODELET_INFO(
"RGBDOdometry: rgbd_cameras = %d", rgbdCameras);
146 NODELET_INFO(
"RGBDOdometry: keep_color = %s", keepColor_?
"true":
"false");
148 std::string subscribedTopic;
149 std::string subscribedTopicsMsg;
154 rgbd_image1_sub_.subscribe(nh,
"rgbd_image0", topicQueueSize_);
155 rgbd_image2_sub_.subscribe(nh,
"rgbd_image1", topicQueueSize_);
158 rgbd_image3_sub_.subscribe(nh,
"rgbd_image2", topicQueueSize_);
162 rgbd_image4_sub_.subscribe(nh,
"rgbd_image3", topicQueueSize_);
166 rgbd_image5_sub_.subscribe(nh,
"rgbd_image4", topicQueueSize_);
170 rgbd_image6_sub_.subscribe(nh,
"rgbd_image5", topicQueueSize_);
181 if(approxSyncMaxInterval > 0.0)
182 approxSync2_->setMaxIntervalDuration(
ros::Duration(approxSyncMaxInterval));
183 approxSync2_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD2,
this, boost::placeholders::_1, boost::placeholders::_2));
191 exactSync2_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD2,
this, boost::placeholders::_1, boost::placeholders::_2));
193 subscribedTopicsMsg =
uFormat(
"\n%s subscribed to (%s sync%s):\n %s \\\n %s",
195 approxSync?
"approx":
"exact",
196 approxSync&&approxSyncMaxInterval!=0.0?
uFormat(
", max interval=%fs", approxSyncMaxInterval).
c_str():
"",
197 rgbd_image1_sub_.getTopic().c_str(),
198 rgbd_image2_sub_.getTopic().c_str());
200 else if(rgbdCameras == 3)
209 if(approxSyncMaxInterval > 0.0)
210 approxSync3_->setMaxIntervalDuration(
ros::Duration(approxSyncMaxInterval));
211 approxSync3_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD3,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3));
220 exactSync3_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD3,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3));
222 subscribedTopicsMsg =
uFormat(
"\n%s subscribed to (%s sync%s):\n %s \\\n %s \\\n %s",
224 approxSync?
"approx":
"exact",
225 approxSync&&approxSyncMaxInterval!=0.0?
uFormat(
", max interval=%fs", approxSyncMaxInterval).
c_str():
"",
226 rgbd_image1_sub_.getTopic().c_str(),
227 rgbd_image2_sub_.getTopic().c_str(),
228 rgbd_image3_sub_.getTopic().c_str());
230 else if(rgbdCameras == 4)
240 if(approxSyncMaxInterval > 0.0)
241 approxSync4_->setMaxIntervalDuration(
ros::Duration(approxSyncMaxInterval));
242 approxSync4_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD4,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4));
252 exactSync4_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD4,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4));
254 subscribedTopicsMsg =
uFormat(
"\n%s subscribed to (%s sync%s):\n %s \\\n %s \\\n %s \\\n %s",
256 approxSync?
"approx":
"exact",
257 approxSync&&approxSyncMaxInterval!=0.0?
uFormat(
", max interval=%fs", approxSyncMaxInterval).
c_str():
"",
258 rgbd_image1_sub_.getTopic().c_str(),
259 rgbd_image2_sub_.getTopic().c_str(),
260 rgbd_image3_sub_.getTopic().c_str(),
261 rgbd_image4_sub_.getTopic().c_str());
263 else if(rgbdCameras == 5)
274 if(approxSyncMaxInterval > 0.0)
275 approxSync5_->setMaxIntervalDuration(
ros::Duration(approxSyncMaxInterval));
276 approxSync5_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD5,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5));
287 exactSync5_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD5,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5));
289 subscribedTopicsMsg =
uFormat(
"\n%s subscribed to (%s sync%s):\n %s \\\n %s \\\n %s \\\n %s \\\n %s",
291 approxSync?
"approx":
"exact",
292 approxSync&&approxSyncMaxInterval!=0.0?
uFormat(
", max interval=%fs", approxSyncMaxInterval).
c_str():
"",
293 rgbd_image1_sub_.getTopic().c_str(),
294 rgbd_image2_sub_.getTopic().c_str(),
295 rgbd_image3_sub_.getTopic().c_str(),
296 rgbd_image4_sub_.getTopic().c_str(),
297 rgbd_image5_sub_.getTopic().c_str());
299 else if(rgbdCameras == 6)
311 if(approxSyncMaxInterval > 0.0)
312 approxSync6_->setMaxIntervalDuration(
ros::Duration(approxSyncMaxInterval));
313 approxSync6_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD6,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5, boost::placeholders::_6));
325 exactSync6_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD6,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5, boost::placeholders::_6));
327 subscribedTopicsMsg =
uFormat(
"\n%s subscribed to (%s sync%s):\n %s \\\n %s \\\n %s \\\n %s \\\n %s \\\n %s",
329 approxSync?
"approx":
"exact",
330 approxSync&&approxSyncMaxInterval!=0.0?
uFormat(
", max interval=%fs", approxSyncMaxInterval).
c_str():
"",
331 rgbd_image1_sub_.getTopic().c_str(),
332 rgbd_image2_sub_.getTopic().c_str(),
333 rgbd_image3_sub_.getTopic().c_str(),
334 rgbd_image4_sub_.getTopic().c_str(),
335 rgbd_image5_sub_.getTopic().c_str(),
336 rgbd_image6_sub_.getTopic().c_str());
340 NODELET_FATAL(
"%s doesn't support more than 6 cameras (rgbd_cameras=%d) with "
341 "internal synchronization interface, set rgbd_cameras=0 and use "
342 "rgbd_images input topic instead for more cameras (for which "
343 "rgbdx_sync node can sync up to 8 cameras).",
348 else if(rgbdCameras == 0)
350 rgbdxSub_ = nh.
subscribe(
"rgbd_images", topicQueueSize_, &RGBDOdometry::callbackRGBDX,
this);
352 subscribedTopicsMsg =
353 uFormat(
"\n%s subscribed to:\n %s",
355 rgbdxSub_.getTopic().c_str());
359 rgbdSub_ = nh.
subscribe(
"rgbd_image", topicQueueSize_, &RGBDOdometry::callbackRGBD,
this);
361 subscribedTopicsMsg =
362 uFormat(
"\n%s subscribed to:\n %s",
364 rgbdSub_.getTopic().c_str());
378 image_mono_sub_.subscribe(rgb_it, rgb_nh.
resolveName(
"image"), topicQueueSize_, hintsRgb);
379 image_depth_sub_.subscribe(depth_it, depth_nh.
resolveName(
"image"), topicQueueSize_, hintsDepth);
380 info_sub_.subscribe(rgb_nh,
"camera_info", topicQueueSize_);
385 if(approxSyncMaxInterval > 0.0)
386 approxSync_->setMaxIntervalDuration(
ros::Duration(approxSyncMaxInterval));
387 approxSync_->registerCallback(boost::bind(&RGBDOdometry::callback,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3));
392 exactSync_->registerCallback(boost::bind(&RGBDOdometry::callback,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3));
396 subscribedTopicsMsg =
uFormat(
"\n%s subscribed to (%s sync%s):\n %s \\\n %s \\\n %s",
398 approxSync?
"approx":
"exact",
399 approxSync&&approxSyncMaxInterval!=0.0?
uFormat(
", max interval=%fs", approxSyncMaxInterval).
c_str():
"",
400 image_mono_sub_.getTopic().c_str(),
401 image_depth_sub_.getTopic().c_str(),
402 info_sub_.getTopic().c_str());
404 initDiagnosticMsg(subscribedTopicsMsg, approxSync, subscribedTopic);
410 ParametersMap::iterator
iter = parameters.find(Parameters::kRegStrategy());
411 if(
iter != parameters.end() &&
iter->second.compare(
"0") != 0)
413 ROS_WARN(
"RGBD odometry works only with \"Reg/Strategy\"=0. Ignoring value %s.",
iter->second.c_str());
417 int estimationType = Parameters::defaultVisEstimationType();
421 bool subscribeRGBD =
false;
422 pnh.
param(
"subscribe_rgbd", subscribeRGBD, subscribeRGBD);
423 pnh.
param(
"rgbd_cameras", rgbdCameras, rgbdCameras);
427 const std::vector<cv_bridge::CvImageConstPtr> & rgbImages,
428 const std::vector<cv_bridge::CvImageConstPtr> & depthImages,
429 const std::vector<sensor_msgs::CameraInfo>& cameraInfos)
431 ROS_ASSERT(rgbImages.size() > 0 && rgbImages.size() == depthImages.size() && rgbImages.size() == cameraInfos.size());
433 int imageWidth = rgbImages[0]->image.cols;
434 int imageHeight = rgbImages[0]->image.rows;
435 int depthWidth = depthImages[0]->image.cols;
436 int depthHeight = depthImages[0]->image.rows;
439 imageWidth/depthWidth == imageHeight/depthHeight,
440 uFormat(
"rgb=%dx%d depth=%dx%d", imageWidth, imageHeight, depthWidth, depthHeight).
c_str());
442 int cameraCount = rgbImages.size();
445 std::vector<rtabmap::CameraModel> cameraModels;
446 for(
unsigned int i=0;
i<rgbImages.size(); ++
i)
460 NODELET_ERROR(
"Input type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8 and "
461 "image_depth=32FC1,16UC1,mono16. Current rgb=%s and depth=%s",
463 depthImages[
i]->encoding.c_str());
466 UASSERT_MSG(rgbImages[
i]->image.cols == imageWidth && rgbImages[
i]->image.rows == imageHeight,
467 uFormat(
"imageWidth=%d vs %d imageHeight=%d vs %d",
469 rgbImages[
i]->image.cols,
471 rgbImages[
i]->image.rows).c_str());
472 UASSERT_MSG(depthImages[
i]->image.cols == depthWidth && depthImages[
i]->image.rows == depthHeight,
473 uFormat(
"depthWidth=%d vs %d depthHeight=%d vs %d",
475 depthImages[
i]->image.cols,
477 depthImages[
i]->image.rows).c_str());
479 ros::Time stamp = rgbImages[
i]->header.stamp>depthImages[
i]->header.stamp?rgbImages[
i]->header.stamp:depthImages[
i]->header.stamp;
485 else if(stamp > higherStamp)
491 if(localTransform.
isNull())
498 double stampDiff =
fabs(rgbImages[
i]->
header.stamp.toSec() - rgbImages[
i-1]->header.stamp.toSec());
499 if(stampDiff > 1.0/60.0)
501 static bool warningShown =
false;
504 NODELET_WARN(
"The time difference between cameras %d and %d is "
505 "high (diff=%fs, cam%d=%fs, cam%d=%fs). You may want "
506 "to set approx_sync_max_interval to reject bad synchronizations or use "
507 "approx_sync=false if streams have all the exact same timestamp. This "
508 "message is only printed once.",
511 i-1, rgbImages[
i-1]->
header.stamp.toSec(),
512 i, rgbImages[
i]->header.stamp.toSec());
538 rgb = cv::Mat(imageHeight, imageWidth*cameraCount, ptrImage->image.type());
542 depth = cv::Mat(depthHeight, depthWidth*cameraCount, ptrDepth->image.type());
545 if(ptrImage->image.type() == rgb.type())
547 ptrImage->image.copyTo(cv::Mat(rgb, cv::Rect(
i*imageWidth, 0, imageWidth, imageHeight)));
551 NODELET_ERROR(
"Some RGB images are not the same type! %d vs %d", ptrImage->image.type(), rgb.type());
555 if(ptrDepth->image.type() == depth.type())
557 ptrDepth->image.copyTo(cv::Mat(depth, cv::Rect(
i*depthWidth, 0, depthWidth, depthHeight)));
561 NODELET_ERROR(
"Some Depth images are not the same type! %d vs %d", ptrDepth->image.type(), depth.type());
576 header.stamp = higherStamp;
577 header.frame_id = rgbImages.size()==1?rgbImages[0]->header.frame_id:
"";
582 const sensor_msgs::ImageConstPtr& image,
583 const sensor_msgs::ImageConstPtr& depth,
584 const sensor_msgs::CameraInfoConstPtr& cameraInfo)
586 if(!this->isPaused())
588 std::vector<cv_bridge::CvImageConstPtr> imageMsgs(1);
589 std::vector<cv_bridge::CvImageConstPtr> depthMsgs(1);
590 std::vector<sensor_msgs::CameraInfo> infoMsgs;
593 infoMsgs.push_back(*cameraInfo);
595 double stampDiff =
fabs(image->header.stamp.toSec() - depth->header.stamp.toSec());
596 if(stampDiff > 0.020)
598 NODELET_WARN(
"The time difference between rgb and depth frames is "
599 "high (diff=%fs, rgb=%fs, depth=%fs). You may want "
600 "to set approx_sync_max_interval lower than 0.02s to reject spurious bad synchronizations or use "
601 "approx_sync=false if streams have all the exact same timestamp.",
603 image->header.stamp.toSec(),
604 depth->header.stamp.toSec());
607 this->commonCallback(imageMsgs, depthMsgs, infoMsgs);
612 const rtabmap_msgs::RGBDImageConstPtr& image)
614 if(!this->isPaused())
616 std::vector<cv_bridge::CvImageConstPtr> imageMsgs(1);
617 std::vector<cv_bridge::CvImageConstPtr> depthMsgs(1);
618 std::vector<sensor_msgs::CameraInfo> infoMsgs;
620 infoMsgs.push_back(image->rgb_camera_info);
622 this->commonCallback(imageMsgs, depthMsgs, infoMsgs);
627 const rtabmap_msgs::RGBDImagesConstPtr& images)
629 if(!this->isPaused())
631 if(images->rgbd_images.empty())
633 NODELET_ERROR(
"Input topic \"%s\" doesn't contain any image(s)!", rgbdxSub_.getTopic().c_str());
636 std::vector<cv_bridge::CvImageConstPtr> imageMsgs(images->rgbd_images.size());
637 std::vector<cv_bridge::CvImageConstPtr> depthMsgs(images->rgbd_images.size());
638 std::vector<sensor_msgs::CameraInfo> infoMsgs;
639 for(
size_t i=0;
i<images->rgbd_images.size(); ++
i)
642 infoMsgs.push_back(images->rgbd_images[
i].rgb_camera_info);
645 this->commonCallback(imageMsgs, depthMsgs, infoMsgs);
650 const rtabmap_msgs::RGBDImageConstPtr& image,
651 const rtabmap_msgs::RGBDImageConstPtr& image2)
653 if(!this->isPaused())
655 std::vector<cv_bridge::CvImageConstPtr> imageMsgs(2);
656 std::vector<cv_bridge::CvImageConstPtr> depthMsgs(2);
657 std::vector<sensor_msgs::CameraInfo> infoMsgs;
660 infoMsgs.push_back(image->rgb_camera_info);
661 infoMsgs.push_back(image2->rgb_camera_info);
663 this->commonCallback(imageMsgs, depthMsgs, infoMsgs);
668 const rtabmap_msgs::RGBDImageConstPtr& image,
669 const rtabmap_msgs::RGBDImageConstPtr& image2,
670 const rtabmap_msgs::RGBDImageConstPtr& image3)
672 if(!this->isPaused())
674 std::vector<cv_bridge::CvImageConstPtr> imageMsgs(3);
675 std::vector<cv_bridge::CvImageConstPtr> depthMsgs(3);
676 std::vector<sensor_msgs::CameraInfo> infoMsgs;
680 infoMsgs.push_back(image->rgb_camera_info);
681 infoMsgs.push_back(image2->rgb_camera_info);
682 infoMsgs.push_back(image3->rgb_camera_info);
684 this->commonCallback(imageMsgs, depthMsgs, infoMsgs);
689 const rtabmap_msgs::RGBDImageConstPtr& image,
690 const rtabmap_msgs::RGBDImageConstPtr& image2,
691 const rtabmap_msgs::RGBDImageConstPtr& image3,
692 const rtabmap_msgs::RGBDImageConstPtr& image4)
694 if(!this->isPaused())
696 std::vector<cv_bridge::CvImageConstPtr> imageMsgs(4);
697 std::vector<cv_bridge::CvImageConstPtr> depthMsgs(4);
698 std::vector<sensor_msgs::CameraInfo> infoMsgs;
703 infoMsgs.push_back(image->rgb_camera_info);
704 infoMsgs.push_back(image2->rgb_camera_info);
705 infoMsgs.push_back(image3->rgb_camera_info);
706 infoMsgs.push_back(image4->rgb_camera_info);
708 this->commonCallback(imageMsgs, depthMsgs, infoMsgs);
713 const rtabmap_msgs::RGBDImageConstPtr& image,
714 const rtabmap_msgs::RGBDImageConstPtr& image2,
715 const rtabmap_msgs::RGBDImageConstPtr& image3,
716 const rtabmap_msgs::RGBDImageConstPtr& image4,
717 const rtabmap_msgs::RGBDImageConstPtr& image5)
719 if(!this->isPaused())
721 std::vector<cv_bridge::CvImageConstPtr> imageMsgs(5);
722 std::vector<cv_bridge::CvImageConstPtr> depthMsgs(5);
723 std::vector<sensor_msgs::CameraInfo> infoMsgs;
729 infoMsgs.push_back(image->rgb_camera_info);
730 infoMsgs.push_back(image2->rgb_camera_info);
731 infoMsgs.push_back(image3->rgb_camera_info);
732 infoMsgs.push_back(image4->rgb_camera_info);
733 infoMsgs.push_back(image5->rgb_camera_info);
735 this->commonCallback(imageMsgs, depthMsgs, infoMsgs);
739 const rtabmap_msgs::RGBDImageConstPtr& image,
740 const rtabmap_msgs::RGBDImageConstPtr& image2,
741 const rtabmap_msgs::RGBDImageConstPtr& image3,
742 const rtabmap_msgs::RGBDImageConstPtr& image4,
743 const rtabmap_msgs::RGBDImageConstPtr& image5,
744 const rtabmap_msgs::RGBDImageConstPtr& image6)
746 if(!this->isPaused())
748 std::vector<cv_bridge::CvImageConstPtr> imageMsgs(6);
749 std::vector<cv_bridge::CvImageConstPtr> depthMsgs(6);
750 std::vector<sensor_msgs::CameraInfo> infoMsgs;
757 infoMsgs.push_back(image->rgb_camera_info);
758 infoMsgs.push_back(image2->rgb_camera_info);
759 infoMsgs.push_back(image3->rgb_camera_info);
760 infoMsgs.push_back(image4->rgb_camera_info);
761 infoMsgs.push_back(image5->rgb_camera_info);
762 infoMsgs.push_back(image6->rgb_camera_info);
764 this->commonCallback(imageMsgs, depthMsgs, infoMsgs);
776 approxSync_->registerCallback(boost::bind(&RGBDOdometry::callback,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3));
782 exactSync_->registerCallback(boost::bind(&RGBDOdometry::callback,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3));
791 approxSync2_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD2,
this, boost::placeholders::_1, boost::placeholders::_2));
800 exactSync2_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD2,
this, boost::placeholders::_1, boost::placeholders::_2));
810 approxSync3_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD3,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3));
820 exactSync3_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD3,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3));
831 approxSync4_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD4,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4));
842 exactSync4_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD4,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4));
854 approxSync5_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD5,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5));
866 exactSync5_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD5,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5));
879 approxSync6_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD6,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5, boost::placeholders::_6));
892 exactSync6_->registerCallback(boost::bind(&RGBDOdometry::callbackRGBD6,
this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4, boost::placeholders::_5, boost::placeholders::_6));