30 #include <opencv2/highgui/highgui.hpp>
78 long double recipNorm = 1.0 /
sqrt(
msg.rotation.x *
msg.rotation.x +
msg.rotation.y *
msg.rotation.y +
msg.rotation.z *
msg.rotation.z +
msg.rotation.w *
msg.rotation.w);
79 msg.rotation.x *= recipNorm;
80 msg.rotation.y *= recipNorm;
81 msg.rotation.z *= recipNorm;
82 msg.rotation.w *= recipNorm;
86 msg = geometry_msgs::Transform();
93 if(
msg.rotation.w == 0 &&
94 msg.rotation.x == 0 &&
95 msg.rotation.y == 0 &&
114 msg = geometry_msgs::Pose();
120 if(
msg.orientation.w == 0 &&
121 msg.orientation.x == 0 &&
122 msg.orientation.y == 0 &&
123 msg.orientation.z == 0)
125 if(ignoreRotationIfNotSet)
138 if(!image.rgb.data.empty())
142 else if(!image.rgb_compressed.data.empty())
144 #ifdef CV_BRIDGE_HYDRO
145 ROS_ERROR(
"Unsupported compressed image copy, please upgrade at least to ROS Indigo to use this.");
151 if(!image.depth.data.empty())
155 else if(!image.depth_compressed.data.empty())
158 ptr->header = image.depth_compressed.header;
160 ROS_ASSERT(ptr->image.empty() || ptr->image.type() == CV_32FC1 || ptr->image.type() == CV_16UC1);
173 if(!image.rgb.data.empty())
177 else if(!image.rgb_compressed.data.empty())
179 #ifdef CV_BRIDGE_HYDRO
180 ROS_ERROR(
"Unsupported compressed image copy, please upgrade at least to ROS Indigo to use this.");
186 if(!image.depth.data.empty())
190 else if(!image.depth_compressed.data.empty())
192 if(image.depth_compressed.format.compare(
"jpg")==0)
194 #ifdef CV_BRIDGE_HYDRO
195 ROS_ERROR(
"Unsupported compressed image copy, please upgrade at least to ROS Indigo to use this.");
203 ptr->header = image.depth_compressed.header;
205 ROS_ASSERT(ptr->image.empty() || ptr->image.type() == CV_32FC1 || ptr->image.type() == CV_16UC1);
215 header.frame_id = sensorFrameId;
218 if(
data.cameraModels().size()>1)
220 UERROR(
"Cannot convert multi-camera data to rgbd image");
223 if(
data.cameraModels().size() == 1)
228 localTransform =
data.cameraModels().front().localTransform();
230 else if(
data.stereoCameraModels().size() == 1)
237 localTransform =
data.stereoCameraModels()[0].localTransform();
240 if(!
data.imageRaw().empty())
245 UASSERT(
data.imageRaw().type()==CV_8UC1 ||
data.imageRaw().type()==CV_8UC3);
249 else if(!
data.imageCompressed().empty())
251 ROS_ERROR(
"Conversion of compressed SensorData to RGBDImage is not implemented...");
254 if(!
data.depthOrRightRaw().empty())
259 UASSERT(
data.depthOrRightRaw().type()==CV_8UC1 ||
data.depthOrRightRaw().type()==CV_16UC1 ||
data.depthOrRightRaw().type()==CV_32FC1);
263 else if(!
data.depthOrRightCompressed().empty())
265 ROS_ERROR(
"Conversion of compressed SensorData to RGBDImage is not implemented...");
269 if(!
data.keypoints().empty())
273 if(!
data.keypoints3D().empty())
277 if(!
data.descriptors().empty())
281 if(!
data.globalDescriptors().empty())
312 ROS_ERROR(
"Input type must be image=mono8,mono16,rgb8,bgr8 (mono8 recommended), received types are %s (left) and %s (right)",
313 imageRectLeft->encoding.c_str(), imageRectRight->encoding.c_str());
317 if(!imageRectLeft->image.empty() && !imageRectRight->image.empty())
321 static bool shown =
false;
324 ROS_WARN(
"Detected baseline (%f m) is quite large! Is your "
325 "right camera_info P(0,3) correctly set? Note that "
326 "baseline=-P(0,3)/P(0,0). This warning is printed only once.",
336 left = imageRectLeft->image;
349 right = imageRectRight->image;
367 ROS_WARN(
"Odom: input images empty?!?");
373 int imageWidth = imageMsg->image.cols;
374 int imageHeight = imageMsg->image.rows;
375 int depthWidth = depthMsg->image.cols;
376 int depthHeight = depthMsg->image.rows;
379 imageWidth/depthWidth == imageHeight/depthHeight,
380 uFormat(
"rgb=%dx%d depth=%dx%d", imageWidth, imageHeight, depthWidth, depthHeight).
c_str());
398 ROS_ERROR(
"Input type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8 and "
399 "image_depth=32FC1,16UC1,mono16. Current rgb=%s and depth=%s",
400 imageMsg->encoding.c_str(),
401 depthMsg->encoding.c_str());
435 UASSERT(compressed.empty() || compressed.type() == CV_8UC1);
437 if(!compressed.empty())
439 bytes.resize(compressed.cols * compressed.rows);
440 memcpy(
bytes.data(), compressed.data,
bytes.size());
449 out = cv::Mat(1,
bytes.size(), CV_8UC1, (
void*)
bytes.data());
474 std::map<int, float> mapIntFloat;
475 for(
unsigned int i=0;
i<
info.posteriorKeys.size() &&
i<
info.posteriorValues.size(); ++
i)
477 mapIntFloat.insert(std::pair<int, float>(
info.posteriorKeys.at(
i),
info.posteriorValues.at(
i)));
482 for(
unsigned int i=0;
i<
info.likelihoodKeys.size() &&
i<
info.likelihoodValues.size(); ++
i)
484 mapIntFloat.insert(std::pair<int, float>(
info.likelihoodKeys.at(
i),
info.likelihoodValues.at(
i)));
489 for(
unsigned int i=0;
i<
info.rawLikelihoodKeys.size() &&
i<
info.rawLikelihoodValues.size(); ++
i)
491 mapIntFloat.insert(std::pair<int, float>(
info.rawLikelihoodKeys.at(
i),
info.rawLikelihoodValues.at(
i)));
495 std::map<int, int> mapIntInt;
496 for(
unsigned int i=0;
i<
info.weightsKeys.size() &&
i<
info.weightsValues.size(); ++
i)
498 mapIntInt.insert(std::pair<int, int>(
info.weightsKeys.at(
i),
info.weightsValues.at(
i)));
502 std::map<int, std::string> mapIntStr;
503 for(
unsigned int i=0;
i<
info.labelsKeys.size() &&
i<
info.labelsValues.size(); ++
i)
505 mapIntStr.insert(std::pair<int, std::string>(
info.labelsKeys.at(
i),
info.labelsValues.at(
i)));
512 std::map<int, rtabmap::Transform> poses;
513 std::multimap<int, rtabmap::Link> constraints;
520 for(
unsigned int i=0;
i<
info.statsKeys.size() &&
i<
info.statsValues.size();
i++)
529 info.loopClosureId =
stats.loopClosureId();
530 info.proximityDetectionId =
stats.proximityDetectionId();
531 info.landmarkId =
static_cast<int>(
uValue(
stats.data(), rtabmap::Statistics::kLoopLandmark_detected(), 0.0f));
553 info.currentGoalId =
stats.currentGoalId();
564 cv::Mat information = cv::Mat(6,6,CV_64FC1, (
void*)
msg.information.data()).clone();
571 msg.toId = link.
to();
575 memcpy(
msg.information.data(), link.
infMatrix().data, 36*
sizeof(
double));
582 return cv::KeyPoint(
msg.pt.x,
msg.pt.y,
msg.size,
msg.angle,
msg.response,
msg.octave,
msg.class_id);
587 msg.angle = kpt.angle;
588 msg.class_id = kpt.class_id;
589 msg.octave = kpt.octave;
592 msg.response = kpt.response;
596 std::vector<cv::KeyPoint>
keypointsFromROS(
const std::vector<rtabmap_msgs::KeyPoint> & msg)
598 std::vector<cv::KeyPoint>
v(
msg.size());
599 for(
unsigned int i=0;
i<
msg.size(); ++
i)
606 void keypointsFromROS(
const std::vector<rtabmap_msgs::KeyPoint> & msg, std::vector<cv::KeyPoint> & kpts,
int xShift)
608 size_t outCurrentIndex = kpts.size();
609 kpts.resize(kpts.size()+
msg.size());
610 for(
unsigned int i=0;
i<
msg.size(); ++
i)
613 kpts[outCurrentIndex+
i].pt.x += xShift;
617 void keypointsToROS(
const std::vector<cv::KeyPoint> & kpts, std::vector<rtabmap_msgs::KeyPoint> & msg)
619 msg.resize(kpts.size());
620 for(
unsigned int i=0;
i<
msg.size(); ++
i)
642 std::vector<rtabmap::GlobalDescriptor>
v(
msg.size());
643 for(
unsigned int i=0;
i<
msg.size(); ++
i)
649 return std::vector<rtabmap::GlobalDescriptor>();
652 void globalDescriptorsToROS(
const std::vector<rtabmap::GlobalDescriptor> & desc, std::vector<rtabmap_msgs::GlobalDescriptor> & msg)
658 for(
unsigned int i=0;
i<
msg.size(); ++
i)
682 for(
unsigned int i=0;
i<
msg.size(); ++
i)
696 msg.resize(sensors.size());
698 for(rtabmap::EnvSensors::const_iterator
iter=sensors.begin();
iter!=sensors.end(); ++
iter)
707 return cv::Point2f(
msg.x,
msg.y);
710 void point2fToROS(
const cv::Point2f & kpt, rtabmap_msgs::Point2f & msg)
716 std::vector<cv::Point2f>
points2fFromROS(
const std::vector<rtabmap_msgs::Point2f> & msg)
718 std::vector<cv::Point2f>
v(
msg.size());
719 for(
unsigned int i=0;
i<
msg.size(); ++
i)
726 void points2fToROS(
const std::vector<cv::Point2f> & kpts, std::vector<rtabmap_msgs::Point2f> & msg)
728 msg.resize(kpts.size());
729 for(
unsigned int i=0;
i<
msg.size(); ++
i)
750 std::vector<cv::Point3f>
v(
msg.size());
751 for(
unsigned int i=0;
i<
msg.size(); ++
i)
764 size_t currentIndex = points3.size();
765 points3.resize(points3.size()+
msg.size());
767 for(
unsigned int i=0;
i<
msg.size(); ++
i)
779 msg.resize(pts.size());
781 for(
unsigned int i=0;
i<
msg.size(); ++
i)
796 const sensor_msgs::CameraInfo & camInfo,
800 UASSERT(camInfo.K.empty() || camInfo.K.size() == 9);
801 if(!camInfo.K.empty())
803 K = cv::Mat(3, 3, CV_64FC1);
804 memcpy(
K.data, camInfo.K.elems, 9*
sizeof(
double));
810 if(camInfo.D.size()>=4 &&
812 uStrContains(camInfo.distortion_model,
"equidistant") ||
813 uStrContains(camInfo.distortion_model,
"Kannala Brandt4")))
815 D = cv::Mat::zeros(1, 6, CV_64FC1);
816 D.at<
double>(0,0) = camInfo.D[0];
817 D.at<
double>(0,1) = camInfo.D[1];
818 D.at<
double>(0,4) = camInfo.D[2];
819 D.at<
double>(0,5) = camInfo.D[3];
821 else if(camInfo.D.size()>8)
823 bool zerosAfter8 =
true;
824 for(
size_t i=8;
i<camInfo.D.size() && zerosAfter8; ++
i)
826 if(camInfo.D[
i] != 0.0)
831 static bool warned =
false;
832 if(!zerosAfter8 && !warned)
834 ROS_WARN(
"Camera info conversion: Distortion model is larger than 8, coefficients after 8 are ignored. This message is only shown once.");
837 D = cv::Mat(1, 8, CV_64FC1);
838 memcpy(
D.data, camInfo.D.data(),
D.cols*
sizeof(
double));
842 D = cv::Mat(1, camInfo.D.size(), CV_64FC1);
843 memcpy(
D.data, camInfo.D.data(),
D.cols*
sizeof(
double));
848 UASSERT(camInfo.R.empty() || camInfo.R.size() == 9);
849 if(!camInfo.R.empty())
851 R = cv::Mat(3, 3, CV_64FC1);
852 memcpy(
R.data, camInfo.R.elems, 9*
sizeof(
double));
856 UASSERT(camInfo.P.empty() || camInfo.P.size() == 12);
857 if(!camInfo.P.empty())
859 P = cv::Mat(3, 4, CV_64FC1);
860 memcpy(
P.data, camInfo.P.elems, 12*
sizeof(
double));
865 cv::Size(camInfo.width, camInfo.height),
871 sensor_msgs::CameraInfo & camInfo)
874 if(
model.K_raw().empty())
876 memset(camInfo.K.elems, 0.0, 9*
sizeof(
double));
880 memcpy(camInfo.K.elems,
model.K_raw().data, 9*
sizeof(
double));
883 if(
model.D_raw().total() == 6)
885 camInfo.D = std::vector<double>(4);
886 camInfo.D[0] =
model.D_raw().at<
double>(0,0);
887 camInfo.D[1] =
model.D_raw().at<
double>(0,1);
888 camInfo.D[2] =
model.D_raw().at<
double>(0,4);
889 camInfo.D[3] =
model.D_raw().at<
double>(0,5);
890 camInfo.distortion_model =
"equidistant";
894 camInfo.D = std::vector<double>(
model.D_raw().cols);
895 memcpy(camInfo.D.data(),
model.D_raw().data,
model.D_raw().cols*
sizeof(
double));
896 if(camInfo.D.size() > 5)
898 camInfo.distortion_model =
"rational_polynomial";
902 camInfo.distortion_model =
"plumb_bob";
907 if(
model.R().empty())
909 memset(camInfo.R.elems, 0.0, 9*
sizeof(
double));
913 memcpy(camInfo.R.elems,
model.R().data, 9*
sizeof(
double));
917 if(
model.P().empty())
919 memset(camInfo.P.elems, 0.0, 12*
sizeof(
double));
923 memcpy(camInfo.P.elems,
model.P().data, 12*
sizeof(
double));
926 camInfo.binning_x = 1;
927 camInfo.binning_y = 1;
928 camInfo.roi.width =
model.imageWidth();
929 camInfo.roi.height =
model.imageHeight();
931 camInfo.width =
model.imageWidth();
932 camInfo.height =
model.imageHeight();
935 const sensor_msgs::CameraInfo & leftCamInfo,
936 const sensor_msgs::CameraInfo & rightCamInfo,
947 const sensor_msgs::CameraInfo & leftCamInfo,
948 const sensor_msgs::CameraInfo & rightCamInfo,
949 const std::string & frameId,
951 double waitForTransform)
955 leftCamInfo.header.frame_id,
956 leftCamInfo.header.stamp,
959 if(localTransform.
isNull())
965 leftCamInfo.header.frame_id,
966 rightCamInfo.header.frame_id,
967 leftCamInfo.header.stamp,
970 if(stereoTransform.
isNull())
978 const rtabmap_msgs::MapData & msg,
979 std::map<int, rtabmap::Transform> & poses,
980 std::multimap<int, rtabmap::Link> & links,
981 std::map<int, rtabmap::Signature> & signatures,
988 for(
unsigned int i=0;
i<
msg.nodes.size(); ++
i)
994 const std::map<int, rtabmap::Transform> & poses,
995 const std::multimap<int, rtabmap::Link> & links,
996 const std::map<int, rtabmap::Signature> & signatures,
998 rtabmap_msgs::MapData & msg)
1004 msg.nodes.resize(signatures.size());
1006 for(std::multimap<int, rtabmap::Signature>::const_iterator
iter = signatures.begin();
1007 iter!=signatures.end();
1015 const rtabmap_msgs::MapGraph & msg,
1016 std::map<int, rtabmap::Transform> & poses,
1017 std::multimap<int, rtabmap::Link> & links,
1022 for(
unsigned int i=0;
i<
msg.posesId.size(); ++
i)
1026 for(
unsigned int i=0;
i<
msg.links.size(); ++
i)
1034 const std::map<int, rtabmap::Transform> & poses,
1035 const std::multimap<int, rtabmap::Link> & links,
1037 rtabmap_msgs::MapGraph & msg)
1040 msg.posesId.resize(poses.size());
1041 msg.poses.resize(poses.size());
1043 for(std::map<int, rtabmap::Transform>::const_iterator
iter = poses.begin();
1044 iter != poses.end();
1047 msg.posesId[index] =
iter->first;
1052 msg.links.resize(links.size());
1054 for(std::multimap<int, rtabmap::Link>::const_iterator
iter = links.begin();
1069 msg.header.stamp.toSec(),
1072 std::vector<rtabmap::StereoCameraModel> stereoModels;
1073 std::vector<rtabmap::CameraModel> models;
1074 bool isStereo = !
msg.right_camera_info.empty();
1078 if(
msg.left_camera_info.size() ==
msg.right_camera_info.size() &&
1079 msg.local_transform.size() ==
msg.right_camera_info.size())
1081 for(
unsigned int i=0;
i<
msg.right_camera_info.size(); ++
i)
1084 msg.left_camera_info[
i],
1085 msg.right_camera_info[
i],
1094 if(
msg.left_camera_info.size() &&
1095 msg.local_transform.size() ==
msg.left_camera_info.size())
1097 for(
unsigned int i=0;
i<
msg.left_camera_info.size(); ++
i)
1100 msg.left_camera_info[
i],
1107 cv::Mat left, right;
1108 if(!
msg.left.data.empty())
1122 ROS_ERROR(
"Input type must be image=mono8,mono16,rgb8,bgr8 (mono8 recommended), received type is %s. Will return data without left/rgb raw image.",
1123 leftRawPtr->encoding.c_str());
1130 left = leftRawPtr->image.clone();
1142 if(!
msg.right.data.empty())
1155 ROS_ERROR(
"Input type must be image=mono8,mono16,rgb8,bgr8,32FC1,16UC1, received type is %s. Will return data without right/depth raw image.",
1156 rightRawPtr->encoding.c_str());
1167 right = rightRawPtr->image.clone();
1182 if(!left.empty() && !right.empty())
1184 s.setStereoImage(left, right, stereoModels,
false);
1193 if(!left.empty() && !right.empty())
1195 s.setRGBDImage(left, right, models,
false);
1200 if(!
msg.laser_scan_compressed.empty())
1204 msg.laser_scan_max_pts,
1205 msg.laser_scan_max_range,
1209 if(!
msg.laser_scan.data.empty())
1211 pcl::PCLPointCloud2 cloud;
1215 msg.laser_scan_max_pts,
1216 msg.laser_scan_max_range,
1223 std::vector<cv::KeyPoint> keypoints;
1224 std::vector<cv::Point3f> keypoints3D;
1225 cv::Mat descriptors;
1226 if(!
msg.key_points.empty())
1230 if(!
msg.points.empty())
1234 if(!
msg.descriptors.empty())
1238 s.setFeatures(keypoints, keypoints3D, descriptors);
1259 msg.gps.stamp =
data.gps().stamp();
1260 msg.gps.longitude =
data.gps().longitude();
1261 msg.gps.latitude =
data.gps().latitude();
1262 msg.gps.altitude =
data.gps().altitude();
1263 msg.gps.error =
data.gps().error();
1264 msg.gps.bearing =
data.gps().bearing();
1267 if(
data.cameraModels().size())
1269 msg.left_camera_info.resize(
data.cameraModels().size());
1270 msg.local_transform.resize(
data.cameraModels().size());
1271 for(
unsigned int i=0;
i<
data.cameraModels().
size(); ++
i)
1277 else if(
data.stereoCameraModels().size())
1279 msg.left_camera_info.resize(
data.stereoCameraModels().size());
1280 msg.right_camera_info.resize(
data.stereoCameraModels().size());
1281 msg.local_transform.resize(
data.stereoCameraModels().size());
1282 for(
unsigned int i=0;
i<
data.stereoCameraModels().
size(); ++
i)
1293 if(!
data.imageRaw().empty())
1297 UASSERT(
data.imageRaw().type()==CV_8UC1 ||
data.imageRaw().type()==CV_8UC3);
1301 if(!
data.depthOrRightRaw().empty())
1305 UASSERT(
data.depthOrRightRaw().type()==CV_8UC1 ||
data.depthOrRightRaw().type()==CV_16UC1 ||
data.depthOrRightRaw().type()==CV_32FC1);
1314 if(copyRawData && !
data.laserScanRaw().empty())
1318 msg.laser_scan_max_pts =
data.laserScanCompressed().maxPoints();
1319 msg.laser_scan_max_range =
data.laserScanCompressed().rangeMax();
1320 msg.laser_scan_format =
data.laserScanCompressed().format();
1323 if(!
data.laserScanCompressed().empty())
1326 msg.laser_scan_max_pts =
data.laserScanCompressed().maxPoints();
1327 msg.laser_scan_max_range =
data.laserScanCompressed().rangeMax();
1328 msg.laser_scan_format =
data.laserScanCompressed().format();
1333 if(!
data.userDataCompressed().empty())
1338 else if(copyRawData && !
data.userDataRaw().empty())
1344 if(!
data.gridGroundCellsCompressed().empty())
1349 else if(copyRawData && !
data.gridGroundCellsRaw().empty())
1353 if(!
data.gridObstacleCellsCompressed().empty())
1358 else if(copyRawData && !
data.gridObstacleCellsRaw().empty())
1362 if(!
data.gridEmptyCellsCompressed().empty())
1367 else if(copyRawData && !
data.gridEmptyCellsRaw().empty())
1373 msg.grid_cell_size =
data.gridCellSize();
1376 if(!
data.keypoints().empty())
1380 if(!
data.keypoints3D().empty())
1384 if(!
data.descriptors().empty())
1388 if(!
data.globalDescriptors().empty())
1402 std::multimap<int, int> words;
1403 std::vector<cv::KeyPoint> wordsKpts;
1404 std::vector<cv::Point3f> words3D;
1408 if(
msg.word_id_keys.size() !=
msg.word_id_values.size())
1410 ROS_ERROR(
"Word ID keys and values should be the same size (%d, %d)!", (
int)
msg.word_id_keys.size(), (
int)
msg.word_id_values.size());
1412 if(!
msg.word_kpts.empty() &&
msg.word_kpts.size() !=
msg.word_id_keys.size())
1414 ROS_ERROR(
"Word IDs and 2D keypoints should be the same size (%d, %d)!", (
int)
msg.word_id_keys.size(), (
int)
msg.word_kpts.size());
1416 if(!
msg.word_pts.empty() &&
msg.word_pts.size() !=
msg.word_id_keys.size())
1418 ROS_ERROR(
"Word IDs and 3D points should be the same size (%d, %d)!", (
int)
msg.word_id_keys.size(), (
int)
msg.word_pts.size());
1420 if(!wordsDescriptors.empty() && wordsDescriptors.rows != (
int)
msg.word_id_keys.size())
1422 ROS_ERROR(
"Word IDs and descriptors should be the same size (%d, %d)!", (
int)
msg.word_id_keys.size(), wordsDescriptors.rows);
1423 wordsDescriptors = cv::Mat();
1435 if(
msg.word_id_keys.size() ==
msg.word_id_values.size())
1437 for(
unsigned int i=0;
i<
msg.word_id_keys.size(); ++
i)
1439 words.insert(std::make_pair(
msg.word_id_keys.at(
i),
msg.word_id_values.at(
i)));
1440 if(
msg.word_id_keys.size() ==
msg.word_kpts.size())
1442 if(wordsKpts.empty())
1444 wordsKpts.reserve(
msg.word_kpts.size());
1448 if(
msg.word_id_keys.size() ==
msg.word_pts.size())
1452 words3D.reserve(
msg.word_pts.size());
1458 s.setWords(words, wordsKpts, words3D, wordsDescriptors);
1460 s.sensorData().setId(
msg.id);
1466 msg.id = signature.
id();
1477 ROS_ERROR(
"Word IDs and 2D keypoints must have the same size (%d vs %d)!",
1485 ROS_ERROR(
"Word IDs and 3D points must have the same size (%d vs %d)!",
1490 msg.word_id_keys.resize(signature.
getWords().size());
1491 msg.word_id_values.resize(signature.
getWords().size());
1492 for(std::multimap<int, int>::const_iterator
iter=signature.
getWords().begin();
1496 msg.word_id_keys.at(
i) =
iter->first;
1497 msg.word_id_values.at(
i) =
iter->second;
1500 if(
msg.word_kpts.empty())
1502 msg.word_kpts.resize(signature.
getWords().size());
1508 if(
msg.word_pts.empty())
1525 ROS_ERROR(
"Word IDs and descriptors must have the same size (%d vs %d)!",
1559 msg.id = signature.
id();
1570 std::map<std::string, float>
stats;
1572 stats.insert(std::make_pair(
"Odometry/TimeRegistration/ms",
info.reg.totalTime*1000.0f));
1573 stats.insert(std::make_pair(
"Odometry/RAM_usage/MB",
info.memoryUsage));
1576 stats.insert(std::make_pair(
"Odometry/Features/",
info.features));
1577 stats.insert(std::make_pair(
"Odometry/Matches/",
info.reg.matches));
1578 stats.insert(std::make_pair(
"Odometry/MatchesRatio/",
info.features<=0?0.0f:
float(
info.reg.inliers)/
float(
info.features)));
1579 stats.insert(std::make_pair(
"Odometry/Inliers/",
info.reg.inliers));
1580 stats.insert(std::make_pair(
"Odometry/InliersMeanDistance/m",
info.reg.inliersMeanDistance));
1581 stats.insert(std::make_pair(
"Odometry/InliersDistribution/",
info.reg.inliersDistribution));
1582 stats.insert(std::make_pair(
"Odometry/InliersRatio/",
info.reg.inliers));
1583 stats.insert(std::make_pair(
"Odometry/ICPInliersRatio/",
info.reg.icpInliersRatio));
1584 stats.insert(std::make_pair(
"Odometry/ICPRotation/rad",
info.reg.icpRotation));
1585 stats.insert(std::make_pair(
"Odometry/ICPTranslation/m",
info.reg.icpTranslation));
1586 stats.insert(std::make_pair(
"Odometry/ICPStructuralComplexity/",
info.reg.icpStructuralComplexity));
1587 stats.insert(std::make_pair(
"Odometry/ICPStructuralDistribution/",
info.reg.icpStructuralDistribution));
1588 stats.insert(std::make_pair(
"Odometry/ICPCorrespondences/",
info.reg.icpCorrespondences));
1589 stats.insert(std::make_pair(
"Odometry/StdDevLin/",
sqrt((
float)
info.reg.covariance.at<
double>(0,0))));
1590 stats.insert(std::make_pair(
"Odometry/StdDevAng/",
sqrt((
float)
info.reg.covariance.at<
double>(5,5))));
1591 stats.insert(std::make_pair(
"Odometry/VarianceLin/", (
float)
info.reg.covariance.at<
double>(0,0)));
1592 stats.insert(std::make_pair(
"Odometry/VarianceAng/", (
float)
info.reg.covariance.at<
double>(5,5)));
1593 stats.insert(std::make_pair(
"Odometry/TimeEstimation/ms",
info.timeEstimation*1000.0f));
1594 stats.insert(std::make_pair(
"Odometry/TimeFiltering/ms",
info.timeParticleFiltering*1000.0f));
1595 stats.insert(std::make_pair(
"Odometry/LocalMapSize/",
info.localMapSize));
1596 stats.insert(std::make_pair(
"Odometry/LocalScanMapSize/",
info.localScanMapSize));
1597 stats.insert(std::make_pair(
"Odometry/LocalKeyFrames/",
info.localKeyFrames));
1598 stats.insert(std::make_pair(
"Odometry/LocalBundleOutliers/",
info.localBundleOutliers));
1599 stats.insert(std::make_pair(
"Odometry/LocalBundleConstraints/",
info.localBundleConstraints));
1600 stats.insert(std::make_pair(
"Odometry/LocalBundleTime/ms",
info.localBundleTime*1000.0f));
1601 stats.insert(std::make_pair(
"Odometry/localBundleAvgInlierDistance/pix",
info.localBundleAvgInlierDistance));
1602 stats.insert(std::make_pair(
"Odometry/localBundleMaxKeyFramesForInlier/",
info.localBundleMaxKeyFramesForInlier));
1603 stats.insert(std::make_pair(
"Odometry/KeyFrameAdded/",
info.keyFrameAdded?1.0f:0.0f));
1604 stats.insert(std::make_pair(
"Odometry/Interval/ms", (
float)
info.interval));
1605 stats.insert(std::make_pair(
"Odometry/Distance/m",
info.distanceTravelled));
1608 float dist = 0.0f, speed=0.0f;
1609 if(!
info.transform.isNull())
1613 stats.insert(std::make_pair(
"Odometry/T/m",
dist));
1614 stats.insert(std::make_pair(
"Odometry/Tx/m",
x));
1615 stats.insert(std::make_pair(
"Odometry/Ty/m",
y));
1616 stats.insert(std::make_pair(
"Odometry/Tz/m",
z));
1617 stats.insert(std::make_pair(
"Odometry/Troll/deg",
roll*180.0/CV_PI));
1618 stats.insert(std::make_pair(
"Odometry/Tpitch/deg",
pitch*180.0/CV_PI));
1619 stats.insert(std::make_pair(
"Odometry/Tyaw/deg",
yaw*180.0/CV_PI));
1621 if(
info.interval>0.0)
1624 stats.insert(std::make_pair(
"Odometry/Speed/kph", speed*3.6));
1625 stats.insert(std::make_pair(
"Odometry/Speed/mph", speed*2.237));
1626 stats.insert(std::make_pair(
"Odometry/Speed/mps", speed));
1629 if(!
info.transformGroundTruth.isNull())
1631 if(!
info.transform.isNull())
1634 stats.insert(std::make_pair(
"Odometry/TG_error_lin/m",
diff.getNorm()));
1635 stats.insert(std::make_pair(
"Odometry/TG_error_ang/deg",
diff.getAngle()*180.0/CV_PI));
1639 dist =
info.transformGroundTruth.getNorm();
1640 stats.insert(std::make_pair(
"Odometry/TG/m",
dist));
1641 stats.insert(std::make_pair(
"Odometry/TGx/m",
x));
1642 stats.insert(std::make_pair(
"Odometry/TGy/m",
y));
1643 stats.insert(std::make_pair(
"Odometry/TGz/m",
z));
1644 stats.insert(std::make_pair(
"Odometry/TGroll/deg",
roll*180.0/CV_PI));
1645 stats.insert(std::make_pair(
"Odometry/TGpitch/deg",
pitch*180.0/CV_PI));
1646 stats.insert(std::make_pair(
"Odometry/TGyaw/deg",
yaw*180.0/CV_PI));
1648 if(
info.interval>0.0)
1651 stats.insert(std::make_pair(
"Odometry/SpeedG/kph", speed*3.6));
1652 stats.insert(std::make_pair(
"Odometry/SpeedG/mph", speed*2.237));
1653 stats.insert(std::make_pair(
"Odometry/SpeedG/mps", speed));
1663 info.reg.matches =
msg.matches;
1664 info.reg.inliers =
msg.inliers;
1665 info.reg.icpInliersRatio =
msg.icpInliersRatio;
1666 info.reg.icpRotation =
msg.icpRotation;
1667 info.reg.icpTranslation =
msg.icpTranslation;
1668 info.reg.icpStructuralComplexity =
msg.icpStructuralComplexity;
1669 info.reg.icpStructuralDistribution =
msg.icpStructuralDistribution;
1670 info.reg.icpCorrespondences =
msg.icpCorrespondences;
1671 info.reg.covariance = cv::Mat(6,6,CV_64FC1, (
void*)
msg.covariance.data()).clone();
1673 info.localMapSize =
msg.localMapSize;
1674 info.localScanMapSize =
msg.localScanMapSize;
1675 info.localKeyFrames =
msg.localKeyFrames;
1676 info.localBundleOutliers =
msg.localBundleOutliers;
1677 info.localBundleConstraints =
msg.localBundleConstraints;
1678 info.localBundleTime =
msg.localBundleTime;
1679 info.localBundleAvgInlierDistance =
msg.localBundleAvgInlierDistance;
1680 info.localBundleMaxKeyFramesForInlier =
msg.localBundleMaxKeyFramesForInlier;
1681 UASSERT(
msg.localBundleModels.size() ==
msg.localBundleIds.size());
1682 UASSERT(
msg.localBundleModels.size() ==
msg.localBundlePoses.size());
1683 for(
size_t i=0;
i<
msg.localBundleIds.size(); ++
i)
1685 std::vector<rtabmap::CameraModel> models;
1686 for(
size_t j=0;
j<
msg.localBundleModels[
i].models.size(); ++
j)
1690 info.localBundleModels.insert(std::make_pair(
msg.localBundleIds[
i], models));
1693 info.keyFrameAdded =
msg.keyFrameAdded;
1694 info.timeEstimation =
msg.timeEstimation;
1695 info.timeParticleFiltering =
msg.timeParticleFiltering;
1698 info.distanceTravelled =
msg.distanceTravelled;
1699 info.memoryUsage =
msg.memoryUsage;
1700 info.gravityRollError =
msg.gravityRollError;
1701 info.gravityPitchError =
msg.gravityPitchError;
1705 info.reg.matchesIDs =
msg.wordMatches;
1706 info.reg.inliersIDs =
msg.wordInliers;
1711 for(
unsigned int i=0;
i<
msg.wordsKeys.size(); ++
i)
1718 info.cornerInliers =
msg.cornerInliers;
1725 UASSERT(
msg.localMapKeys.size() ==
msg.localMapValues.size());
1726 for(
unsigned int i=0;
i<
msg.localMapKeys.size(); ++
i)
1731 pcl::PCLPointCloud2 cloud;
1741 msg.matches =
info.reg.matches;
1742 msg.inliers =
info.reg.inliers;
1743 msg.icpInliersRatio =
info.reg.icpInliersRatio;
1744 msg.icpRotation =
info.reg.icpRotation;
1745 msg.icpTranslation =
info.reg.icpTranslation;
1746 msg.icpStructuralComplexity =
info.reg.icpStructuralComplexity;
1747 msg.icpStructuralDistribution =
info.reg.icpStructuralDistribution;
1748 msg.icpCorrespondences =
info.reg.icpCorrespondences;
1749 if(
info.reg.covariance.type() == CV_64FC1 &&
info.reg.covariance.cols == 6 &&
info.reg.covariance.rows == 6)
1751 memcpy(
msg.covariance.data(),
info.reg.covariance.data, 36*
sizeof(
double));
1754 msg.localMapSize =
info.localMapSize;
1755 msg.localScanMapSize =
info.localScanMapSize;
1756 msg.localKeyFrames =
info.localKeyFrames;
1757 msg.localBundleOutliers =
info.localBundleOutliers;
1758 msg.localBundleConstraints =
info.localBundleConstraints;
1759 msg.localBundleTime =
info.localBundleTime;
1760 msg.localBundleAvgInlierDistance =
info.localBundleAvgInlierDistance;
1761 msg.localBundleMaxKeyFramesForInlier =
info.localBundleMaxKeyFramesForInlier;
1762 UASSERT(
info.localBundleModels.size() ==
info.localBundlePoses.size());
1763 for(std::map<
int, std::vector<rtabmap::CameraModel> >::const_iterator
iter=
info.localBundleModels.begin();
1764 iter!=
info.localBundleModels.end();
1767 msg.localBundleIds.push_back(
iter->first);
1770 geometry_msgs::Pose pose;
1772 msg.localBundlePoses.push_back(pose);
1774 rtabmap_msgs::CameraModels models;
1775 for(
size_t i=0;
i<
iter->second.size(); ++
i)
1777 rtabmap_msgs::CameraModel modelMsg;
1780 models.models.push_back(modelMsg);
1782 msg.localBundleModels.push_back(models);
1784 msg.keyFrameAdded =
info.keyFrameAdded;
1785 msg.timeEstimation =
info.timeEstimation;
1786 msg.timeParticleFiltering =
info.timeParticleFiltering;
1789 msg.distanceTravelled =
info.distanceTravelled;
1790 msg.memoryUsage =
info.memoryUsage;
1791 msg.gravityRollError =
info.gravityRollError;
1792 msg.gravityPitchError =
info.gravityPitchError;
1806 msg.wordMatches =
info.reg.matchesIDs;
1807 msg.wordInliers =
info.reg.inliersIDs;
1811 msg.cornerInliers =
info.cornerInliers;
1823 if(!dataMsg.data.empty())
1825 if(dataMsg.cols > 0 && dataMsg.rows > 0 && dataMsg.type >= 0)
1827 data = cv::Mat(dataMsg.rows, dataMsg.cols, dataMsg.type, (
void*)dataMsg.data.data()).clone();
1831 if(dataMsg.cols != (
int)dataMsg.data.size() || dataMsg.rows != 1 || dataMsg.type != CV_8UC1)
1833 ROS_ERROR(
"cols, rows and type fields of the UserData msg "
1834 "are not correctly set (cols=%d, rows=%d, type=%d)! We assume that the data "
1835 "is compressed (cols=%d, rows=1, type=%d(CV_8UC1)).",
1836 dataMsg.cols, dataMsg.rows, dataMsg.type, (
int)dataMsg.data.size(), CV_8UC1);
1839 data = cv::Mat(1, dataMsg.data.size(), CV_8UC1, (
void*)dataMsg.data.data()).clone();
1844 void userDataToROS(
const cv::Mat & data, rtabmap_msgs::UserData & dataMsg,
bool compress)
1852 dataMsg.cols = dataMsg.data.size();
1853 dataMsg.type = CV_8UC1;
1857 dataMsg.data.resize(
data.step[0] *
data.rows);
1858 memcpy(dataMsg.data.data(),
data.data, dataMsg.data.size());
1859 dataMsg.rows =
data.rows;
1860 dataMsg.cols =
data.cols;
1861 dataMsg.type =
data.type();
1869 cv::Vec4d(
msg.orientation.x,
msg.orientation.y,
msg.orientation.z,
msg.orientation.w),
1870 cv::Mat(3,3,CV_64FC1,(
void*)
msg.orientation_covariance.data()).clone(),
1871 cv::Vec3d(
msg.angular_velocity.x,
msg.angular_velocity.y,
msg.angular_velocity.z),
1872 cv::Mat(3,3,CV_64FC1,(
void*)
msg.angular_velocity_covariance.data()).clone(),
1873 cv::Vec3d(
msg.linear_acceleration.x,
msg.linear_acceleration.y,
msg.linear_acceleration.z),
1874 cv::Mat(3,3,CV_64FC1,(
void*)
msg.linear_acceleration_covariance.data()).clone(),
1904 const std::map<
int, std::pair<geometry_msgs::PoseWithCovarianceStamped, float> > & tags,
1905 const std::string & frameId,
1906 const std::string & odomFrameId,
1909 double waitForTransform,
1910 double defaultLinVariance,
1911 double defaultAngVariance)
1915 for(std::map<
int, std::pair<geometry_msgs::PoseWithCovarianceStamped, float> >::const_iterator
iter=tags.begin();
iter!=tags.end(); ++
iter)
1919 ROS_ERROR(
"Invalid landmark received! IDs should be > 0 (it is %d). Ignoring this landmark.",
iter->first);
1924 iter->second.first.header.frame_id,
1925 iter->second.first.header.stamp,
1929 if(baseToCamera.
isNull())
1931 ROS_ERROR(
"Cannot transform tag pose from \"%s\" frame to \"%s\" frame!",
1932 iter->second.first.header.frame_id.c_str(),
frameId.c_str());
1945 iter->second.first.header.stamp,
1950 baseToTag = correction * baseToTag;
1954 ROS_WARN(
"Could not adjust tag pose accordingly to latest odometry pose. "
1955 "If odometry is small since it received the tag pose and "
1956 "covariance is large, this should not be a problem.");
1958 cv::Mat covariance = cv::Mat(6,6, CV_64FC1, (
void*)
iter->second.first.pose.covariance.data()).clone();
1959 if(covariance.empty() || !
uIsFinite(covariance.at<
double>(0,0)) || covariance.at<
double>(0,0)<=0.0f)
1961 covariance = cv::Mat::eye(6,6,CV_64FC1);
1962 covariance(cv::Range(0,3), cv::Range(0,3)) *= defaultLinVariance;
1963 covariance(cv::Range(3,6), cv::Range(3,6)) *= defaultAngVariance;
1972 const std::string & fromFrameId,
1973 const std::string & toFrameId,
1976 double waitForTransform)
1982 if(waitForTransform > 0.0 && !stamp.
isZero())
1985 std::string errorMsg;
1988 ROS_WARN(
"Could not get transform from %s to %s after %f seconds (for stamp=%f)! Error=\"%s\".",
1989 fromFrameId.c_str(), toFrameId.c_str(), waitForTransform, stamp.
toSec(), errorMsg.c_str());
2000 ROS_WARN(
"(getting transform %s -> %s) %s", fromFrameId.c_str(), toFrameId.c_str(), ex.what());
2008 const std::string & movingFrame,
2009 const std::string & fixedFrame,
2013 double waitForTransform)
2019 ros::Time stamp = stampTo>stampFrom?stampTo:stampFrom;
2020 if(waitForTransform > 0.0 && !stamp.
isZero())
2022 std::string errorMsg;
2025 ROS_WARN(
"Could not get transform from %s to %s accordingly to %s after %f seconds (for stamps=%f -> %f)! Error=\"%s\".",
2026 movingFrame.c_str(), movingFrame.c_str(), fixedFrame.c_str(), waitForTransform, stampTo.
toSec(), stampFrom.
toSec(), errorMsg.c_str());
2032 listener.
lookupTransform(movingFrame, stampFrom, movingFrame, stampTo, fixedFrame, tmp);
2037 ROS_WARN(
"(getting transform movement of %s according to fixed %s) %s", movingFrame.c_str(), fixedFrame.c_str(), ex.what());
2043 const std::vector<cv_bridge::CvImageConstPtr> & imageMsgs,
2044 const std::vector<cv_bridge::CvImageConstPtr> & depthMsgs,
2045 const std::vector<sensor_msgs::CameraInfo> & cameraInfoMsgs,
2046 const std::vector<sensor_msgs::CameraInfo> & depthCameraInfoMsgs,
2047 const std::string & frameId,
2048 const std::string & odomFrameId,
2052 std::vector<rtabmap::CameraModel> & cameraModels,
2053 std::vector<rtabmap::StereoCameraModel> & stereoCameraModels,
2055 double waitForTransform,
2056 bool alreadRectifiedImages,
2057 const std::vector<std::vector<rtabmap_msgs::KeyPoint> > & localKeyPointsMsgs,
2058 const std::vector<std::vector<rtabmap_msgs::Point3f> > & localPoints3dMsgs,
2059 const std::vector<cv::Mat> & localDescriptorsMsgs,
2060 std::vector<cv::KeyPoint> * localKeyPoints,
2061 std::vector<cv::Point3f> * localPoints3d,
2062 cv::Mat * localDescriptors)
2064 UASSERT(!cameraInfoMsgs.empty() &&
2065 (cameraInfoMsgs.size() == imageMsgs.size() || imageMsgs.empty()) &&
2066 (cameraInfoMsgs.size() == depthMsgs.size() || depthMsgs.empty()) &&
2067 (cameraInfoMsgs.size() == depthCameraInfoMsgs.size() || depthCameraInfoMsgs.empty()));
2069 int imageWidth = imageMsgs.size()?imageMsgs[0]->image.cols:cameraInfoMsgs[0].width;
2070 int imageHeight = imageMsgs.size()?imageMsgs[0]->image.rows:cameraInfoMsgs[0].height;
2071 int depthWidth = depthMsgs.size()?depthMsgs[0]->image.cols:0;
2072 int depthHeight = depthMsgs.size()?depthMsgs[0]->image.rows:0;
2074 bool isDepth = depthMsgs.empty() || (depthMsgs[0].get() != 0 && (
2081 !depthMsgs.empty() &&
2083 cameraInfoMsgs.size() == depthCameraInfoMsgs.size())
2085 isDepth = cameraInfoMsgs[0].P.elems[3] == 0.0 && depthCameraInfoMsgs[0].P.elems[3] == 0.0;
2086 static bool warned =
false;
2087 if(!warned && isDepth)
2089 ROS_WARN(
"Input depth/left image has encoding \"mono16\" and "
2090 "camera info P[3] is null for both cameras, thus image is "
2091 "considered a depth image. If the depth image is in "
2092 "fact the right image, please convert the right image to "
2093 "\"mono8\". This warning is shown only once.");
2098 if(isDepth && !depthMsgs.empty())
2101 imageWidth/depthWidth == imageHeight/depthHeight,
2102 uFormat(
"rgb=%dx%d depth=%dx%d", imageWidth, imageHeight, depthWidth, depthHeight).
c_str());
2105 int cameraCount = cameraInfoMsgs.size();
2106 for(
unsigned int i=0;
i<cameraInfoMsgs.size(); ++
i)
2108 if(!imageMsgs.empty())
2120 ROS_ERROR(
"Input rgb/left type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8. Current rgb/left=%s",
2125 UASSERT_MSG(imageMsgs[
i]->image.cols == imageWidth && imageMsgs[
i]->image.rows == imageHeight,
2126 uFormat(
"imageWidth=%d vs %d imageHeight=%d vs %d",
2128 imageMsgs[
i]->image.cols,
2130 imageMsgs[
i]->image.rows).c_str());
2132 if(!depthMsgs.empty())
2139 ROS_ERROR(
"Input depth type must be image_depth=32FC1,16UC1,mono16. Current depth=%s",
2152 ROS_ERROR(
"Input right type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8. Current right=%s",
2160 if(isDepth && !depthMsgs.empty())
2162 UASSERT_MSG(depthMsgs[
i]->image.cols == depthWidth && depthMsgs[
i]->image.rows == depthHeight,
2163 uFormat(
"depthWidth=%d vs %d imageHeight=%d vs %d",
2165 depthMsgs[
i]->image.cols,
2167 depthMsgs[
i]->image.rows).c_str());
2168 stamp = depthMsgs[
i]->header.stamp;
2170 else if(!imageMsgs.empty())
2172 stamp = imageMsgs[
i]->header.stamp;
2176 stamp = cameraInfoMsgs[
i].header.stamp;
2181 if(localTransform.
isNull())
2183 ROS_ERROR(
"TF of received image %d at time %fs is not set!",
i, stamp.
toSec());
2187 if(!odomFrameId.empty() && odomStamp != stamp)
2198 ROS_WARN(
"Could not get odometry value for image stamp (%fs). Latest odometry "
2199 "stamp is %fs. The image pose will not be synchronized with odometry.", stamp.
toSec(), odomStamp.
toSec());
2204 localTransform = sensorT * localTransform;
2208 if(!imageMsgs.empty())
2229 rgb = cv::Mat(imageHeight, imageWidth*cameraCount, ptrImage->image.type());
2231 if(ptrImage->image.type() == rgb.type())
2233 ptrImage->image.copyTo(cv::Mat(rgb, cv::Rect(
i*imageWidth, 0, imageWidth, imageHeight)));
2237 ROS_ERROR(
"Some RGB/left images are not the same type!");
2242 if(!depthMsgs.empty())
2247 cv::Mat subDepth = ptrDepth->image;
2251 depth = cv::Mat(depthHeight, depthWidth*cameraCount, subDepth.type());
2254 if(subDepth.type() == depth.type())
2256 subDepth.copyTo(cv::Mat(depth, cv::Rect(
i*depthWidth, 0, depthWidth, depthHeight)));
2260 ROS_ERROR(
"Some Depth images are not the same type!");
2280 depth = cv::Mat(depthHeight, depthWidth*cameraCount, ptrImage->image.type());
2282 if(ptrImage->image.type() == depth.type())
2284 ptrImage->image.copyTo(cv::Mat(depth, cv::Rect(
i*depthWidth, 0, depthWidth, depthHeight)));
2288 ROS_ERROR(
"Some right images are not the same type!");
2300 UASSERT(cameraInfoMsgs.size() == depthCameraInfoMsgs.size());
2302 if(!alreadRectifiedImages)
2304 if(depthCameraInfoMsgs[
i].
header.frame_id.empty() || cameraInfoMsgs[
i].header.frame_id.empty())
2306 if(depthCameraInfoMsgs[
i].
P[3] == 0.0 && cameraInfoMsgs[
i].
P[3] == 0)
2308 ROS_ERROR(
"Parameter %s is false but the frame_id in one of the camera_info "
2309 "topic is empty, so TF between the cameras cannot be computed!",
2310 rtabmap::Parameters::kRtabmapImagesAlreadyRectified().
c_str());
2315 static bool warned =
false;
2318 ROS_WARN(
"Parameter %s is false but the frame_id in one of the "
2319 "camera_info topic is empty, so TF between the cameras cannot be "
2320 "computed! However, the baseline can be computed from the calibration, "
2321 "we will use this one instead of TF. This message is only printed once...",
2322 rtabmap::Parameters::kRtabmapImagesAlreadyRectified().
c_str());
2330 depthCameraInfoMsgs[
i].
header.frame_id,
2331 cameraInfoMsgs[
i].header.frame_id,
2332 cameraInfoMsgs[
i].header.stamp,
2335 if(stereoTransform.
isNull())
2337 ROS_ERROR(
"Parameter %s is false but we cannot get TF between the two cameras!", rtabmap::Parameters::kRtabmapImagesAlreadyRectified().
c_str());
2342 ROS_ERROR(
"Parameter %s is false but we cannot get a valid TF between the two cameras! "
2343 "Identity transform returned between left and right cameras. Verify that if TF between "
2344 "the cameras is valid: \"rosrun tf tf_echo %s %s\".",
2345 rtabmap::Parameters::kRtabmapImagesAlreadyRectified().
c_str(),
2346 depthCameraInfoMsgs[
i].
header.frame_id.c_str(),
2347 cameraInfoMsgs[
i].header.frame_id.c_str());
2357 static bool shown =
false;
2360 ROS_WARN(
"Detected baseline (%f m) is quite large! Is your "
2361 "right camera_info P(0,3) correctly set? Note that "
2362 "baseline=-P(0,3)/P(0,0). You may need to calibrate your camera. "
2363 "This warning is printed only once.",
2368 else if(stereoModel.
baseline() == 0 && alreadRectifiedImages)
2371 if( !cameraInfoMsgs[
i].
header.frame_id.empty() &&
2372 !depthCameraInfoMsgs[
i].header.frame_id.empty())
2375 cameraInfoMsgs[
i].
header.frame_id,
2376 depthCameraInfoMsgs[
i].header.frame_id,
2377 cameraInfoMsgs[
i].header.stamp,
2381 if(stereoTransform.
isNull() || stereoTransform.
x()<=0)
2383 if(cameraInfoMsgs[
i].
header.frame_id.empty() || depthCameraInfoMsgs[
i].header.frame_id.empty())
2385 ROS_WARN(
"We cannot estimated the baseline of the rectified images with tf! (camera_info topics have empty frame_id)");
2389 ROS_WARN(
"We cannot estimated the baseline of the rectified images with tf! (%s->%s = %s)",
2390 depthCameraInfoMsgs[
i].
header.frame_id.c_str(), cameraInfoMsgs[
i].header.frame_id.c_str(), stereoTransform.
prettyPrint().c_str());
2395 static bool warned =
false;
2398 ROS_WARN(
"Right camera info doesn't have Tx set but we are assuming that stereo images are already rectified (see %s parameter). While not "
2399 "recommended, we used TF to get the baseline (%s->%s = %fm) for convenience (e.g., D400 ir stereo issue). It is preferred to feed "
2400 "a valid right camera info if stereo images are already rectified. This message is only printed once...",
2401 rtabmap::Parameters::kRtabmapImagesAlreadyRectified().
c_str(),
2402 depthCameraInfoMsgs[
i].
header.frame_id.c_str(), cameraInfoMsgs[
i].header.frame_id.c_str(), stereoTransform.
x());
2410 stereoTransform.
x(),
2415 stereoCameraModels.push_back(stereoModel);
2418 if(localKeyPoints && localKeyPointsMsgs.size() == cameraInfoMsgs.size())
2422 if(localPoints3d && localPoints3dMsgs.size() == cameraInfoMsgs.size())
2427 if(localDescriptors && localDescriptorsMsgs.size() == cameraInfoMsgs.size())
2429 localDescriptors->push_back(localDescriptorsMsgs[
i]);
2438 const sensor_msgs::CameraInfo& leftCamInfoMsg,
2439 const sensor_msgs::CameraInfo& rightCamInfoMsg,
2440 const std::string & frameId,
2441 const std::string & odomFrameId,
2447 double waitForTransform,
2448 bool alreadyRectified)
2450 UASSERT(leftImageMsg.get() && rightImageMsg.get());
2467 ROS_ERROR(
"Input type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8");
2468 ROS_ERROR(
"Input type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8 Current left=%s and right=%s",
2469 leftImageMsg->encoding.c_str(),
2470 rightImageMsg->encoding.c_str());
2477 left = leftImageMsg->image.clone();
2490 right = rightImageMsg->image.clone();
2498 if(localTransform.
isNull())
2503 if(!odomFrameId.empty() && odomStamp != leftImageMsg->header.stamp)
2509 leftImageMsg->header.stamp,
2514 ROS_WARN(
"Could not get odometry value for stereo msg stamp (%fs). Latest odometry "
2515 "stamp is %fs. The stereo image pose will not be synchronized with odometry.", leftImageMsg->header.stamp.toSec(), odomStamp.
toSec());
2519 localTransform = sensorT * localTransform;
2524 if(!alreadyRectified)
2527 rightCamInfoMsg.header.frame_id,
2528 leftCamInfoMsg.header.frame_id,
2529 leftCamInfoMsg.header.stamp,
2532 if(stereoTransform.
isNull())
2534 ROS_ERROR(
"Parameter %s is false but we cannot get TF between the two cameras!", rtabmap::Parameters::kRtabmapImagesAlreadyRectified().
c_str());
2543 static bool shown =
false;
2546 ROS_WARN(
"Detected baseline (%f m) is quite large! Is your "
2547 "right camera_info P(0,3) correctly set? Note that "
2548 "baseline=-P(0,3)/P(0,0). You may need to calibrate your camera. "
2549 "This warning is printed only once.",
2554 else if(stereoModel.
baseline() == 0 && alreadyRectified)
2557 leftCamInfoMsg.header.frame_id,
2558 rightCamInfoMsg.header.frame_id,
2559 leftCamInfoMsg.header.stamp,
2562 if(stereoTransform.
isNull() || stereoTransform.
x()<=0)
2564 ROS_WARN(
"We cannot estimated the baseline of the rectified images with tf! (%s->%s = %s)",
2565 rightCamInfoMsg.header.frame_id.c_str(), leftCamInfoMsg.header.frame_id.c_str(), stereoTransform.
prettyPrint().c_str());
2569 static bool warned =
false;
2572 ROS_WARN(
"Right camera info doesn't have Tx set but we are assuming that stereo images are already rectified (see %s parameter). While not "
2573 "recommended, we used TF to get the baseline (%s->%s = %fm) for convenience (e.g., D400 ir stereo issue). It is preferred to feed "
2574 "a valid right camera info if stereo images are already rectified. This message is only printed once...",
2575 rtabmap::Parameters::kRtabmapImagesAlreadyRectified().
c_str(),
2576 rightCamInfoMsg.header.frame_id.c_str(), leftCamInfoMsg.header.frame_id.c_str(), stereoTransform.
x());
2584 stereoTransform.
x(),
2593 const sensor_msgs::LaserScan & scan2dMsg,
2594 const std::string & frameId,
2595 const std::string & odomFrameId,
2599 double waitForTransform,
2600 bool outputInFrameId)
2603 if(scan2dMsg.angle_increment == 0.0f) {
2604 ROS_ERROR(
"convertScanMsg: angle_increment should not be 0!");
2607 if(scan2dMsg.range_min > scan2dMsg.range_max) {
2608 ROS_ERROR(
"convertScanMsg: range_min (%f) should be smaller than range_max (%f)!", scan2dMsg.range_min, scan2dMsg.range_max);
2611 if(scan2dMsg.angle_increment > 0 && scan2dMsg.angle_max < scan2dMsg.angle_min) {
2612 ROS_ERROR(
"convertScanMsg: Angle increment (%f) should be negative if angle_min(%f) > angle_max(%f)!", scan2dMsg.angle_increment, scan2dMsg.angle_min, scan2dMsg.angle_max);
2615 else if (scan2dMsg.angle_increment < 0 && scan2dMsg.angle_max > scan2dMsg.angle_min) {
2616 ROS_ERROR(
"convertScanMsg: Angle increment (%f) should positive if angle_min(%f) < angle_max(%f)!", scan2dMsg.angle_increment, scan2dMsg.angle_min, scan2dMsg.angle_max);
2622 scan2dMsg.header.frame_id,
2623 odomFrameId.empty()?
frameId:odomFrameId,
2624 scan2dMsg.header.stamp,
2625 scan2dMsg.header.stamp +
ros::Duration().
fromSec(scan2dMsg.ranges.size()*scan2dMsg.time_increment),
2635 scan2dMsg.header.frame_id,
2636 scan2dMsg.header.stamp,
2639 if(scanLocalTransform.
isNull())
2645 sensor_msgs::PointCloud2 scanOut;
2647 projection.transformLaserScanToPointCloud(odomFrameId.empty()?
frameId:odomFrameId, scan2dMsg, scanOut, listener);
2651 scan2dMsg.header.frame_id,
2652 odomFrameId.empty()?
frameId:odomFrameId,
2653 scan2dMsg.header.stamp,
2662 if(!odomFrameId.empty() && odomStamp != scan2dMsg.header.stamp)
2668 scan2dMsg.header.stamp,
2673 ROS_WARN(
"Could not get odometry value for laser scan stamp (%fs). Latest odometry "
2674 "stamp is %fs. The laser scan pose will not be synchronized with odometry.", scan2dMsg.header.stamp.toSec(), odomStamp.
toSec());
2679 scanLocalTransform = sensorT * scanLocalTransform;
2685 laserToOdom *= scanLocalTransform;
2688 bool hasIntensity =
false;
2689 for(
unsigned int i=0;
i<scanOut.fields.size(); ++
i)
2691 if(scanOut.fields[
i].name.compare(
"intensity") == 0)
2693 if(scanOut.fields[
i].datatype == sensor_msgs::PointField::FLOAT32)
2695 hasIntensity =
true;
2699 static bool warningShown =
false;
2702 ROS_WARN(
"The input scan cloud has an \"intensity\" field "
2703 "but the datatype (%d) is not supported. Intensity will be ignored. "
2704 "This message is only shown once.", scanOut.fields[
i].datatype);
2705 warningShown =
true;
2715 pcl::PointCloud<pcl::PointXYZI>::Ptr pclScan(
new pcl::PointCloud<pcl::PointXYZI>);
2717 pclScan->is_dense =
true;
2723 pcl::PointCloud<pcl::PointXYZ>::Ptr pclScan(
new pcl::PointCloud<pcl::PointXYZ>);
2725 pclScan->is_dense =
true;
2731 if((scanLocalTransform.
rotation()*zAxis).z() < 0)
2734 cv::flip(
data, flipScan, 1);
2741 scan2dMsg.range_min,
2742 scan2dMsg.range_max,
2743 scan2dMsg.angle_min,
2744 scan2dMsg.angle_max,
2745 scan2dMsg.angle_increment,
2752 const sensor_msgs::PointCloud2 & scan3dMsg,
2753 const std::string & frameId,
2754 const std::string & odomFrameId,
2758 double waitForTransform,
2763 UASSERT_MSG(scan3dMsg.data.size() == scan3dMsg.row_step*scan3dMsg.height,
2764 uFormat(
"data=%d row_step=%d height=%d", scan3dMsg.data.size(), scan3dMsg.row_step, scan3dMsg.height).c_str());
2767 if(scanLocalTransform.
isNull())
2769 ROS_ERROR(
"TF of received scan cloud at time %fs is not set, aborting rtabmap update.", scan3dMsg.header.stamp.toSec());
2774 if(!odomFrameId.empty() && odomStamp != scan3dMsg.header.stamp)
2780 scan3dMsg.header.stamp,
2785 ROS_WARN(
"Could not get odometry value for laser scan stamp (%fs). Latest odometry "
2786 "stamp is %fs. The 3d laser scan pose will not be synchronized with odometry.", scan3dMsg.header.stamp.toSec(), odomStamp.
toSec());
2790 scanLocalTransform = sensorT * scanLocalTransform;
2799 const sensor_msgs::PointCloud2 & input,
2800 sensor_msgs::PointCloud2 & output,
2801 const std::string & fixedFrameId,
2803 double waitForTransform,
2806 double previousStamp)
2810 if(input.header.frame_id.empty())
2812 ROS_ERROR(
"Input cloud has empty frame_id!");
2816 if(fixedFrameId.empty())
2818 ROS_ERROR(
"fixedFrameId parameter should be set!");
2826 ROS_ERROR(
"slerp should be true when constant velocity model is used!");
2830 if(previousStamp <= 0.0)
2832 ROS_ERROR(
"previousStamp should be >0 when constant velocity model is used!");
2838 ROS_ERROR(
"velocity should be valid when constant velocity model is used!");
2843 int offsetTime = -1;
2847 int timeDatatype = 6;
2848 for(
size_t i=0;
i<input.fields.size(); ++
i)
2850 if(input.fields[
i].name.compare(
"t") == 0 ||
2851 input.fields[
i].name.compare(
"time") == 0 ||
2852 input.fields[
i].name.compare(
"stamps") == 0 ||
2853 input.fields[
i].name.compare(
"timestamp") == 0)
2855 if(offsetTime != -1)
2857 ROS_WARN(
"The input cloud should have only one of these fields: t, time, stamps or timestamp. Overriding with %s.", input.fields[
i].name.c_str());
2859 offsetTime = input.fields[
i].offset;
2860 timeDatatype = input.fields[
i].datatype;
2862 else if(input.fields[
i].name.compare(
"x") == 0)
2865 offsetX = input.fields[
i].offset;
2867 else if(input.fields[
i].name.compare(
"y") == 0)
2870 offsetY = input.fields[
i].offset;
2872 else if(input.fields[
i].name.compare(
"z") == 0)
2875 offsetZ = input.fields[
i].offset;
2881 ROS_ERROR(
"Input cloud doesn't have \"t\", \"time\", \"stamps\" or \"timestamp\" field!");
2882 std::string fieldsReceived;
2883 for(
size_t i=0;
i<input.fields.size(); ++
i)
2885 fieldsReceived += input.fields[
i].name +
" ";
2887 ROS_ERROR(
"Input cloud has these fields: %s", fieldsReceived.c_str());
2892 ROS_ERROR(
"Input cloud doesn't have \"x\" field!");
2897 ROS_ERROR(
"Input cloud doesn't have \"y\" field!");
2902 ROS_ERROR(
"Input cloud doesn't have \"z\" field!");
2905 if(input.height == 0)
2907 ROS_ERROR(
"Input cloud height is zero!");
2910 if(input.width == 0)
2912 ROS_ERROR(
"Input cloud width is zero!");
2916 bool timeOnColumns = input.width > input.height;
2921 if(timeDatatype == 6)
2923 unsigned int nsecFirst = *((
const unsigned int*)(&input.data[0]+offsetTime));
2924 unsigned int nsecLast = *((
const unsigned int*)(&input.data[(input.width-1)*input.point_step + input.row_step*(input.height-1)]+offsetTime));
2926 if(nsecFirst > nsecLast)
2929 static bool warned =
false;
2931 ROS_WARN(
"Timestamp channel is not ordered, we will have to parse every scans to "
2932 "determinate first and last time offsets. This will add slightly computation "
2933 "time. This warning is only shown once.");
2938 for(
size_t i=0;
i<input.width; ++
i)
2940 unsigned int nsec = *((
const unsigned int*)(&input.data[(
i)*input.point_step]+offsetTime));
2941 if(nsec < nsecFirst)
2945 else if(nsec > nsecLast)
2953 for(
size_t i=0;
i<input.height; ++
i)
2955 unsigned int nsec = *((
const unsigned int*)(&input.data[input.row_step*(
i)]+offsetTime));
2956 if(nsec < nsecFirst)
2960 else if(nsec > nsecLast)
2968 firstStamp = input.header.stamp+
ros::Duration(0, nsecFirst);
2971 else if(timeDatatype == 7)
2973 float secFirst = *((
const float*)(&input.data[0]+offsetTime));
2974 float secLast = *((
const float*)(&input.data[(input.width-1)*input.point_step + input.row_step*(input.height-1)]+offsetTime));
2976 if(secFirst > secLast)
2979 static bool warned =
false;
2981 ROS_WARN(
"Timestamp channel is not ordered, we will have to parse every scans to "
2982 "determinate first and last time offsets. This will add slightly computation "
2983 "time. This warning is only shown once.");
2988 for(
size_t i=0;
i<input.width; ++
i)
2990 float sec = *((
const float*)(&input.data[(
i)*input.point_step]+offsetTime));
2995 else if(
sec > secLast)
3003 for(
size_t i=0;
i<input.height; ++
i)
3005 float sec = *((
const float*)(&input.data[input.row_step*(
i)]+offsetTime));
3010 else if(
sec > secLast)
3021 else if(timeDatatype == 8)
3023 double secFirst = *((
const double*)(&input.data[0]+offsetTime));
3024 double secLast = *((
const double*)(&input.data[(input.width-1)*input.point_step + input.row_step*(input.height-1)]+offsetTime));
3025 if(secFirst > secLast)
3028 static bool warned =
false;
3030 ROS_WARN(
"Timestamp channel is not ordered, we will have to parse every scans to "
3031 "determinate first and last time offsets. This will add slightly computation "
3032 "time. This warning is only shown once.");
3037 for(
size_t i=0;
i<input.width; ++
i)
3039 double sec = *((
const double*)(&input.data[(
i)*input.point_step]+offsetTime));
3044 else if(
sec > secLast)
3052 for(
size_t i=0;
i<input.height; ++
i)
3054 double sec = *((
const double*)(&input.data[input.row_step*(
i)]+offsetTime));
3059 else if(
sec > secLast)
3067 if(secFirst > 1.e18)
3073 else if(secFirst > 1.e15)
3079 else if(secFirst > 1.e12)
3091 ROS_ERROR(
"Not supported time datatype %d!", timeDatatype);
3094 if(!(timeDatatype >=6 && timeDatatype<=8))
3096 ROS_ERROR(
"Only lidar timestamp channel data type 6, 7 or 8 is supported! (received %d)", timeDatatype);
3099 if(lastStamp < firstStamp)
3101 ROS_ERROR(
"Last stamp (%f) is smaller than first stamp (%f) (header=%f)!", lastStamp.
toSec(), firstStamp.
toSec(), input.header.stamp.toSec());
3104 else if(lastStamp == firstStamp)
3106 ROS_ERROR(
"First and last stamps in the scan are the same (%f) (header=%f)!", lastStamp.
toSec(), input.header.stamp.toSec());
3110 std::string errorMsg;
3112 waitForTransform>0.0 &&
3114 input.header.frame_id,
3116 input.header.frame_id,
3123 ROS_ERROR(
"Could not estimate motion of %s accordingly to fixed frame %s between stamps %f and %f! (%s)",
3124 input.header.frame_id.c_str(),
3125 fixedFrameId.c_str(),
3134 double scanTime = 0;
3140 input.header.frame_id,
3147 input.header.frame_id,
3156 float vx,
vy,vz, vroll,vpitch,vyaw;
3157 velocity.getTranslationAndEulerAngles(
vx,
vy,vz, vroll,vpitch,vyaw);
3165 double dt1 = firstStamp.
toSec() - previousStamp;
3166 double dt2 = input.header.stamp.toSec() - previousStamp;
3167 double dt3 = lastStamp.
toSec() - previousStamp;
3174 firstPose =
p2.inverse() *
p1;
3175 lastPose =
p2.inverse() *
p3;
3180 ROS_ERROR(
"Could not get transform of %s accordingly to %s between stamps %f and %f!",
3181 input.header.frame_id.c_str(),
3182 fixedFrameId.empty()?
"velocity":fixedFrameId.c_str(),
3184 input.header.stamp.toSec());
3189 ROS_ERROR(
"Could not get transform of %s accordingly to %s between stamps %f and %f!",
3190 input.header.frame_id.c_str(),
3191 fixedFrameId.empty()?
"velocity":fixedFrameId.c_str(),
3193 input.header.stamp.toSec());
3196 scanTime = lastStamp.
toSec() - firstStamp.
toSec();
3211 for(
size_t u=0; u<output.width; ++u)
3213 if(timeDatatype == 6)
3215 unsigned int nsec = *((
const unsigned int*)(&output.data[u*output.point_step]+offsetTime));
3218 else if(timeDatatype == 7)
3220 float sec = *((
const float*)(&output.data[u*output.point_step]+offsetTime));
3223 else if(timeDatatype == 8)
3225 double sec = *((
const double*)(&output.data[u*output.point_step]+offsetTime));
3231 else if(
sec > 1.e15)
3236 else if(
sec > 1.e12)
3252 output.header.frame_id,
3254 output.header.stamp,
3260 ROS_ERROR(
"Could not get transform of %s accordingly to %s between stamps %f and %f!",
3261 output.header.frame_id.c_str(),
3262 fixedFrameId.c_str(),
3264 output.header.stamp.toSec());
3269 for(
size_t v=0;
v<input.height; ++
v)
3271 unsigned char * dataPtr = &output.data[
v*output.row_step + u*output.point_step];
3272 float &
x = *((
float*)(dataPtr+offsetX));
3273 float &
y = *((
float*)(dataPtr+offsetY));
3274 float &
z = *((
float*)(dataPtr+offsetZ));
3275 pcl::PointXYZ pt(
x,
y,
z);
3282 if(timeDatatype == 6)
3284 *((
unsigned int*)(dataPtr+offsetTime)) = 0;
3286 else if(timeDatatype == 7)
3288 *((
float*)(dataPtr+offsetTime)) = 0;
3290 else if(timeDatatype == 8)
3292 *((
double*)(dataPtr+offsetTime)) = 0;
3305 for(
size_t v=0;
v<output.height; ++
v)
3307 if(timeDatatype == 6)
3309 unsigned int nsec = *((
const unsigned int*)(&output.data[
v*output.row_step]+offsetTime));
3312 else if(timeDatatype == 7)
3314 float sec = *((
const float*)(&output.data[
v*output.row_step]+offsetTime));
3317 else if(timeDatatype == 8)
3319 double sec = *((
const double*)(&output.data[
v*output.row_step]+offsetTime));
3325 else if(
sec > 1.e15)
3330 else if(
sec > 1.e12)
3346 output.header.frame_id,
3348 output.header.stamp,
3354 ROS_ERROR(
"Could not get transform of %s accordingly to %s between stamps %f and %f!",
3355 output.header.frame_id.c_str(),
3356 fixedFrameId.c_str(),
3358 output.header.stamp.toSec());
3363 for(
size_t u=0; u<input.width; ++u)
3365 unsigned char * dataPtr = &output.data[
v*output.row_step + u*output.point_step];
3366 float &
x = *((
float*)(dataPtr+offsetX));
3367 float &
y = *((
float*)(dataPtr+offsetY));
3368 float &
z = *((
float*)(dataPtr+offsetZ));
3369 pcl::PointXYZ pt(
x,
y,
z);
3376 if(timeDatatype == 6)
3378 *((
unsigned int*)(dataPtr+offsetTime)) = 0;
3380 else if(timeDatatype == 7)
3382 *((
float*)(dataPtr+offsetTime)) = 0;
3384 else if(timeDatatype == 8)
3386 *((
double*)(dataPtr+offsetTime)) = 0;
3396 const sensor_msgs::PointCloud2 & input,
3397 sensor_msgs::PointCloud2 & output,
3398 const std::string & fixedFrameId,
3400 double waitForTransform,
3407 const sensor_msgs::PointCloud2 & input,
3408 sensor_msgs::PointCloud2 & output,
3409 double previousStamp,