00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "rtabmap_ros/MsgConversion.h"
00029
00030 #include <opencv2/highgui/highgui.hpp>
00031 #include <zlib.h>
00032 #include <ros/ros.h>
00033 #include <rtabmap/core/util3d.h>
00034 #include <rtabmap/core/util3d_transforms.h>
00035 #include <rtabmap/core/util3d_filtering.h>
00036 #include <rtabmap/core/Compression.h>
00037 #include <rtabmap/utilite/UStl.h>
00038 #include <rtabmap/utilite/ULogger.h>
00039 #include <pcl_conversions/pcl_conversions.h>
00040 #include <eigen_conversions/eigen_msg.h>
00041 #include <tf_conversions/tf_eigen.h>
00042 #include <image_geometry/pinhole_camera_model.h>
00043 #include <image_geometry/stereo_camera_model.h>
00044 #include <sensor_msgs/image_encodings.h>
00045 #include <laser_geometry/laser_geometry.h>
00046 #include <rtabmap/core/util3d_surface.h>
00047
00048 namespace rtabmap_ros {
00049
00050 void transformToTF(const rtabmap::Transform & transform, tf::Transform & tfTransform)
00051 {
00052 if(!transform.isNull())
00053 {
00054 tf::transformEigenToTF(transform.toEigen3d(), tfTransform);
00055 }
00056 else
00057 {
00058 tfTransform = tf::Transform();
00059 }
00060 }
00061
00062 rtabmap::Transform transformFromTF(const tf::Transform & transform)
00063 {
00064 Eigen::Affine3d eigenTf;
00065 tf::transformTFToEigen(transform, eigenTf);
00066 return rtabmap::Transform::fromEigen3d(eigenTf);
00067 }
00068
00069 void transformToGeometryMsg(const rtabmap::Transform & transform, geometry_msgs::Transform & msg)
00070 {
00071 if(!transform.isNull())
00072 {
00073 tf::transformEigenToMsg(transform.toEigen3d(), msg);
00074
00075
00076 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);
00077 msg.rotation.x *= recipNorm;
00078 msg.rotation.y *= recipNorm;
00079 msg.rotation.z *= recipNorm;
00080 msg.rotation.w *= recipNorm;
00081 }
00082 else
00083 {
00084 msg = geometry_msgs::Transform();
00085 }
00086 }
00087
00088
00089 rtabmap::Transform transformFromGeometryMsg(const geometry_msgs::Transform & msg)
00090 {
00091 if(msg.rotation.w == 0 &&
00092 msg.rotation.x == 0 &&
00093 msg.rotation.y == 0 &&
00094 msg.rotation.z ==0)
00095 {
00096 return rtabmap::Transform();
00097 }
00098
00099 Eigen::Affine3d tfTransform;
00100 tf::transformMsgToEigen(msg, tfTransform);
00101 return rtabmap::Transform::fromEigen3d(tfTransform);
00102 }
00103
00104 void transformToPoseMsg(const rtabmap::Transform & transform, geometry_msgs::Pose & msg)
00105 {
00106 if(!transform.isNull())
00107 {
00108 tf::poseEigenToMsg(transform.toEigen3d(), msg);
00109 }
00110 else
00111 {
00112 msg = geometry_msgs::Pose();
00113 }
00114 }
00115
00116 rtabmap::Transform transformFromPoseMsg(const geometry_msgs::Pose & msg)
00117 {
00118 if(msg.orientation.w == 0 &&
00119 msg.orientation.x == 0 &&
00120 msg.orientation.y == 0 &&
00121 msg.orientation.z ==0)
00122 {
00123 return rtabmap::Transform();
00124 }
00125 Eigen::Affine3d tfPose;
00126 tf::poseMsgToEigen(msg, tfPose);
00127 return rtabmap::Transform::fromEigen3d(tfPose);
00128 }
00129
00130 void toCvCopy(const rtabmap_ros::RGBDImage & image, cv_bridge::CvImagePtr & rgb, cv_bridge::CvImagePtr & depth)
00131 {
00132 if(!image.rgb.data.empty())
00133 {
00134 rgb = cv_bridge::toCvCopy(image.rgb);
00135 }
00136 else if(!image.rgbCompressed.data.empty())
00137 {
00138 #ifdef CV_BRIDGE_HYDRO
00139 ROS_ERROR("Unsupported compressed image copy, please upgrade at least to ROS Indigo to use this.");
00140 #else
00141 rgb = cv_bridge::toCvCopy(image.rgbCompressed);
00142 #endif
00143 }
00144 else
00145 {
00146
00147 rgb = boost::make_shared<cv_bridge::CvImage>();
00148 }
00149
00150 if(!image.depth.data.empty())
00151 {
00152 depth = cv_bridge::toCvCopy(image.depth);
00153 }
00154 else if(!image.depthCompressed.data.empty())
00155 {
00156 cv_bridge::CvImagePtr ptr = boost::make_shared<cv_bridge::CvImage>();
00157 ptr->header = image.depthCompressed.header;
00158 ptr->image = rtabmap::uncompressImage(image.depthCompressed.data);
00159 ROS_ASSERT(ptr->image.empty() || ptr->image.type() == CV_32FC1 || ptr->image.type() == CV_16UC1);
00160 ptr->encoding = ptr->image.empty()?"":ptr->image.type() == CV_32FC1?sensor_msgs::image_encodings::TYPE_32FC1:sensor_msgs::image_encodings::TYPE_16UC1;
00161 depth = ptr;
00162 }
00163 else
00164 {
00165
00166 depth = boost::make_shared<cv_bridge::CvImage>();
00167 }
00168 }
00169
00170 void toCvShare(const rtabmap_ros::RGBDImageConstPtr & image, cv_bridge::CvImageConstPtr & rgb, cv_bridge::CvImageConstPtr & depth)
00171 {
00172 if(!image->rgb.data.empty())
00173 {
00174 rgb = cv_bridge::toCvShare(image->rgb, image);
00175 }
00176 else if(!image->rgbCompressed.data.empty())
00177 {
00178 #ifdef CV_BRIDGE_HYDRO
00179 ROS_ERROR("Unsupported compressed image copy, please upgrade at least to ROS Indigo to use this.");
00180 #else
00181 rgb = cv_bridge::toCvCopy(image->rgbCompressed);
00182 #endif
00183 }
00184 else
00185 {
00186
00187 rgb = boost::make_shared<cv_bridge::CvImage>();
00188 }
00189
00190 if(!image->depth.data.empty())
00191 {
00192 depth = cv_bridge::toCvShare(image->depth, image);
00193 }
00194 else if(!image->depthCompressed.data.empty())
00195 {
00196 if(image->depthCompressed.format.compare("jpg")==0)
00197 {
00198 #ifdef CV_BRIDGE_HYDRO
00199 ROS_ERROR("Unsupported compressed image copy, please upgrade at least to ROS Indigo to use this.");
00200 #else
00201 depth = cv_bridge::toCvCopy(image->depthCompressed);
00202 #endif
00203 }
00204 else
00205 {
00206 cv_bridge::CvImagePtr ptr = boost::make_shared<cv_bridge::CvImage>();
00207 ptr->header = image->depthCompressed.header;
00208 ptr->image = rtabmap::uncompressImage(image->depthCompressed.data);
00209 ROS_ASSERT(ptr->image.empty() || ptr->image.type() == CV_32FC1 || ptr->image.type() == CV_16UC1);
00210 ptr->encoding = ptr->image.empty()?"":ptr->image.type() == CV_32FC1?sensor_msgs::image_encodings::TYPE_32FC1:sensor_msgs::image_encodings::TYPE_16UC1;
00211 depth = ptr;
00212 }
00213 }
00214 else
00215 {
00216
00217 depth = boost::make_shared<cv_bridge::CvImage>();
00218 }
00219 }
00220
00221 rtabmap::SensorData rgbdImageFromROS(const rtabmap_ros::RGBDImageConstPtr & image)
00222 {
00223 rtabmap::SensorData data;
00224 cv_bridge::CvImageConstPtr imageMsg;
00225 cv_bridge::CvImageConstPtr depthMsg;
00226 toCvShare(image, imageMsg, depthMsg);
00227
00228 rtabmap::StereoCameraModel stereoModel = stereoCameraModelFromROS(image->rgbCameraInfo, image->depthCameraInfo, rtabmap::Transform::getIdentity());
00229
00230 if(stereoModel.isValidForProjection())
00231 {
00232 cv_bridge::CvImageConstPtr imageRectLeft = imageMsg;
00233 cv_bridge::CvImageConstPtr imageRectRight = depthMsg;
00234 if(!(imageRectLeft->encoding.compare(sensor_msgs::image_encodings::MONO8) ==0 ||
00235 imageRectLeft->encoding.compare(sensor_msgs::image_encodings::MONO16) ==0 ||
00236 imageRectLeft->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0 ||
00237 imageRectLeft->encoding.compare(sensor_msgs::image_encodings::RGB8) == 0) ||
00238 !(imageRectRight->encoding.compare(sensor_msgs::image_encodings::MONO8) ==0 ||
00239 imageRectRight->encoding.compare(sensor_msgs::image_encodings::MONO16) ==0 ||
00240 imageRectRight->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0 ||
00241 imageRectRight->encoding.compare(sensor_msgs::image_encodings::RGB8) == 0))
00242 {
00243 ROS_ERROR("Input type must be image=mono8,mono16,rgb8,bgr8 (mono8 recommended), received types are %s (left) and %s (right)",
00244 imageRectLeft->encoding.c_str(), imageRectRight->encoding.c_str());
00245 return data;
00246 }
00247
00248 if(!imageRectLeft->image.empty() && !imageRectRight->image.empty())
00249 {
00250 if(stereoModel.baseline() > 10.0)
00251 {
00252 static bool shown = false;
00253 if(!shown)
00254 {
00255 ROS_WARN("Detected baseline (%f m) is quite large! Is your "
00256 "right camera_info P(0,3) correctly set? Note that "
00257 "baseline=-P(0,3)/P(0,0). This warning is printed only once.",
00258 stereoModel.baseline());
00259 shown = true;
00260 }
00261 }
00262
00263 cv::Mat left, right;
00264 if(imageRectLeft->encoding.compare(sensor_msgs::image_encodings::MONO8) == 0 ||
00265 imageRectLeft->encoding.compare(sensor_msgs::image_encodings::MONO16) == 0)
00266 {
00267 left = cv_bridge::cvtColor(imageRectLeft, "mono8")->image;
00268 }
00269 else
00270 {
00271 left = cv_bridge::cvtColor(imageRectLeft, "bgr8")->image;
00272 }
00273 right = cv_bridge::cvtColor(imageRectRight, "mono8")->image;
00274
00275
00276
00277 data = rtabmap::SensorData(
00278 left,
00279 right,
00280 stereoModel,
00281 0,
00282 rtabmap_ros::timestampFromROS(image->header.stamp));
00283 }
00284 else
00285 {
00286 ROS_WARN("Odom: input images empty?!?");
00287 }
00288 }
00289 else
00290 {
00291 ros::Time higherStamp;
00292 int imageWidth = imageMsg->image.cols;
00293 int imageHeight = imageMsg->image.rows;
00294 int depthWidth = depthMsg->image.cols;
00295 int depthHeight = depthMsg->image.rows;
00296
00297 UASSERT_MSG(
00298 imageWidth % depthWidth == 0 && imageHeight % depthHeight == 0 &&
00299 imageWidth/depthWidth == imageHeight/depthHeight,
00300 uFormat("rgb=%dx%d depth=%dx%d", imageWidth, imageHeight, depthWidth, depthHeight).c_str());
00301
00302 cv::Mat rgb;
00303 cv::Mat depth;
00304 rtabmap::CameraModel cameraModels;
00305
00306 if(!(imageMsg->encoding.compare(sensor_msgs::image_encodings::TYPE_8UC1) ==0 ||
00307 imageMsg->encoding.compare(sensor_msgs::image_encodings::MONO8) ==0 ||
00308 imageMsg->encoding.compare(sensor_msgs::image_encodings::MONO16) ==0 ||
00309 imageMsg->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0 ||
00310 imageMsg->encoding.compare(sensor_msgs::image_encodings::RGB8) == 0 ||
00311 imageMsg->encoding.compare(sensor_msgs::image_encodings::BGRA8) == 0 ||
00312 imageMsg->encoding.compare(sensor_msgs::image_encodings::RGBA8) == 0 ||
00313 imageMsg->encoding.compare(sensor_msgs::image_encodings::BAYER_GRBG8) == 0) ||
00314 !(depthMsg->encoding.compare(sensor_msgs::image_encodings::TYPE_16UC1) == 0 ||
00315 depthMsg->encoding.compare(sensor_msgs::image_encodings::TYPE_32FC1) == 0 ||
00316 depthMsg->encoding.compare(sensor_msgs::image_encodings::MONO16) == 0))
00317 {
00318 ROS_ERROR("Input type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8 and "
00319 "image_depth=32FC1,16UC1,mono16. Current rgb=%s and depth=%s",
00320 imageMsg->encoding.c_str(),
00321 depthMsg->encoding.c_str());
00322 return data;
00323 }
00324
00325 cv_bridge::CvImageConstPtr ptrImage = imageMsg;
00326 if(imageMsg->encoding.compare(sensor_msgs::image_encodings::TYPE_8UC1)==0 ||
00327 imageMsg->encoding.compare(sensor_msgs::image_encodings::MONO8) == 0 ||
00328 imageMsg->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0)
00329 {
00330
00331 }
00332 else if(imageMsg->encoding.compare(sensor_msgs::image_encodings::MONO16) == 0)
00333 {
00334 ptrImage = cv_bridge::cvtColor(imageMsg, "mono8");
00335 }
00336 else
00337 {
00338 ptrImage = cv_bridge::cvtColor(imageMsg, "bgr8");
00339 }
00340
00341 cv_bridge::CvImageConstPtr ptrDepth = depthMsg;
00342 data = rtabmap::SensorData(
00343 ptrImage->image,
00344 ptrDepth->image,
00345 rtabmap_ros::cameraModelFromROS(image->rgbCameraInfo),
00346 0,
00347 rtabmap_ros::timestampFromROS(image->header.stamp));
00348 }
00349
00350 return data;
00351 }
00352
00353 void compressedMatToBytes(const cv::Mat & compressed, std::vector<unsigned char> & bytes)
00354 {
00355 UASSERT(compressed.empty() || compressed.type() == CV_8UC1);
00356 bytes.clear();
00357 if(!compressed.empty())
00358 {
00359 bytes.resize(compressed.cols * compressed.rows);
00360 memcpy(bytes.data(), compressed.data, bytes.size());
00361 }
00362 }
00363
00364 cv::Mat compressedMatFromBytes(const std::vector<unsigned char> & bytes, bool copy)
00365 {
00366 cv::Mat out;
00367 if(bytes.size())
00368 {
00369 out = cv::Mat(1, bytes.size(), CV_8UC1, (void*)bytes.data());
00370 if(copy)
00371 {
00372 out = out.clone();
00373 }
00374 }
00375 return out;
00376 }
00377
00378 void infoFromROS(const rtabmap_ros::Info & info, rtabmap::Statistics & stat)
00379 {
00380 stat.setExtended(true);
00381
00382
00383 stat.setRefImageId(info.refId);
00384 stat.setLoopClosureId(info.loopClosureId);
00385 stat.setProximityDetectionId(info.proximityDetectionId);
00386 stat.setStamp(info.header.stamp.toSec());
00387
00388 stat.setLoopClosureTransform(rtabmap_ros::transformFromGeometryMsg(info.loopClosureTransform));
00389
00390
00391 std::map<int, float> mapIntFloat;
00392 for(unsigned int i=0; i<info.posteriorKeys.size() && i<info.posteriorValues.size(); ++i)
00393 {
00394 mapIntFloat.insert(std::pair<int, float>(info.posteriorKeys.at(i), info.posteriorValues.at(i)));
00395 }
00396 stat.setPosterior(mapIntFloat);
00397 mapIntFloat.clear();
00398 for(unsigned int i=0; i<info.likelihoodKeys.size() && i<info.likelihoodValues.size(); ++i)
00399 {
00400 mapIntFloat.insert(std::pair<int, float>(info.likelihoodKeys.at(i), info.likelihoodValues.at(i)));
00401 }
00402 stat.setLikelihood(mapIntFloat);
00403 mapIntFloat.clear();
00404 for(unsigned int i=0; i<info.rawLikelihoodKeys.size() && i<info.rawLikelihoodValues.size(); ++i)
00405 {
00406 mapIntFloat.insert(std::pair<int, float>(info.rawLikelihoodKeys.at(i), info.rawLikelihoodValues.at(i)));
00407 }
00408 stat.setRawLikelihood(mapIntFloat);
00409 std::map<int, int> mapIntInt;
00410 for(unsigned int i=0; i<info.weightsKeys.size() && i<info.weightsValues.size(); ++i)
00411 {
00412 mapIntInt.insert(std::pair<int, int>(info.weightsKeys.at(i), info.weightsValues.at(i)));
00413 }
00414 stat.setWeights(mapIntInt);
00415
00416 stat.setLocalPath(info.localPath);
00417 stat.setCurrentGoalId(info.currentGoalId);
00418
00419
00420 for(unsigned int i=0; i<info.statsKeys.size() && i<info.statsValues.size(); i++)
00421 {
00422 stat.addStatistic(info.statsKeys.at(i), info.statsValues.at(i));
00423 }
00424 }
00425
00426 void infoToROS(const rtabmap::Statistics & stats, rtabmap_ros::Info & info)
00427 {
00428 info.refId = stats.refImageId();
00429 info.loopClosureId = stats.loopClosureId();
00430 info.proximityDetectionId = stats.proximityDetectionId();
00431
00432 rtabmap_ros::transformToGeometryMsg(stats.loopClosureTransform(), info.loopClosureTransform);
00433
00434
00435 if(stats.extended())
00436 {
00437
00438 info.posteriorKeys = uKeys(stats.posterior());
00439 info.posteriorValues = uValues(stats.posterior());
00440 info.likelihoodKeys = uKeys(stats.likelihood());
00441 info.likelihoodValues = uValues(stats.likelihood());
00442 info.rawLikelihoodKeys = uKeys(stats.rawLikelihood());
00443 info.rawLikelihoodValues = uValues(stats.rawLikelihood());
00444 info.weightsKeys = uKeys(stats.weights());
00445 info.weightsValues = uValues(stats.weights());
00446 info.localPath = stats.localPath();
00447 info.currentGoalId = stats.currentGoalId();
00448
00449
00450 info.statsKeys = uKeys(stats.data());
00451 info.statsValues = uValues(stats.data());
00452 }
00453 }
00454
00455 rtabmap::Link linkFromROS(const rtabmap_ros::Link & msg)
00456 {
00457 cv::Mat information = cv::Mat(6,6,CV_64FC1, (void*)msg.information.data()).clone();
00458 return rtabmap::Link(msg.fromId, msg.toId, (rtabmap::Link::Type)msg.type, transformFromGeometryMsg(msg.transform), information);
00459 }
00460
00461 void linkToROS(const rtabmap::Link & link, rtabmap_ros::Link & msg)
00462 {
00463 msg.fromId = link.from();
00464 msg.toId = link.to();
00465 msg.type = link.type();
00466 if(link.infMatrix().type() == CV_64FC1 && link.infMatrix().cols == 6 && link.infMatrix().rows == 6)
00467 {
00468 memcpy(msg.information.data(), link.infMatrix().data, 36*sizeof(double));
00469 }
00470 transformToGeometryMsg(link.transform(), msg.transform);
00471 }
00472
00473 cv::KeyPoint keypointFromROS(const rtabmap_ros::KeyPoint & msg)
00474 {
00475 return cv::KeyPoint(msg.pt.x, msg.pt.y, msg.size, msg.angle, msg.response, msg.octave, msg.class_id);
00476 }
00477
00478 void keypointToROS(const cv::KeyPoint & kpt, rtabmap_ros::KeyPoint & msg)
00479 {
00480 msg.angle = kpt.angle;
00481 msg.class_id = kpt.class_id;
00482 msg.octave = kpt.octave;
00483 msg.pt.x = kpt.pt.x;
00484 msg.pt.y = kpt.pt.y;
00485 msg.response = kpt.response;
00486 msg.size = kpt.size;
00487 }
00488
00489 std::vector<cv::KeyPoint> keypointsFromROS(const std::vector<rtabmap_ros::KeyPoint> & msg)
00490 {
00491 std::vector<cv::KeyPoint> v(msg.size());
00492 for(unsigned int i=0; i<msg.size(); ++i)
00493 {
00494 v[i] = keypointFromROS(msg[i]);
00495 }
00496 return v;
00497 }
00498
00499 void keypointsToROS(const std::vector<cv::KeyPoint> & kpts, std::vector<rtabmap_ros::KeyPoint> & msg)
00500 {
00501 msg.resize(kpts.size());
00502 for(unsigned int i=0; i<msg.size(); ++i)
00503 {
00504 keypointToROS(kpts[i], msg[i]);
00505 }
00506 }
00507
00508 cv::Point2f point2fFromROS(const rtabmap_ros::Point2f & msg)
00509 {
00510 return cv::Point2f(msg.x, msg.y);
00511 }
00512
00513 void point2fToROS(const cv::Point2f & kpt, rtabmap_ros::Point2f & msg)
00514 {
00515 msg.x = kpt.x;
00516 msg.y = kpt.y;
00517 }
00518
00519 std::vector<cv::Point2f> points2fFromROS(const std::vector<rtabmap_ros::Point2f> & msg)
00520 {
00521 std::vector<cv::Point2f> v(msg.size());
00522 for(unsigned int i=0; i<msg.size(); ++i)
00523 {
00524 v[i] = point2fFromROS(msg[i]);
00525 }
00526 return v;
00527 }
00528
00529 void points2fToROS(const std::vector<cv::Point2f> & kpts, std::vector<rtabmap_ros::Point2f> & msg)
00530 {
00531 msg.resize(kpts.size());
00532 for(unsigned int i=0; i<msg.size(); ++i)
00533 {
00534 point2fToROS(kpts[i], msg[i]);
00535 }
00536 }
00537
00538 cv::Point3f point3fFromROS(const rtabmap_ros::Point3f & msg)
00539 {
00540 return cv::Point3f(msg.x, msg.y, msg.z);
00541 }
00542
00543 void point3fToROS(const cv::Point3f & kpt, rtabmap_ros::Point3f & msg)
00544 {
00545 msg.x = kpt.x;
00546 msg.y = kpt.y;
00547 msg.z = kpt.z;
00548 }
00549
00550 std::vector<cv::Point3f> points3fFromROS(const std::vector<rtabmap_ros::Point3f> & msg)
00551 {
00552 std::vector<cv::Point3f> v(msg.size());
00553 for(unsigned int i=0; i<msg.size(); ++i)
00554 {
00555 v[i] = point3fFromROS(msg[i]);
00556 }
00557 return v;
00558 }
00559
00560 void points3fToROS(const std::vector<cv::Point3f> & kpts, std::vector<rtabmap_ros::Point3f> & msg)
00561 {
00562 msg.resize(kpts.size());
00563 for(unsigned int i=0; i<msg.size(); ++i)
00564 {
00565 point3fToROS(kpts[i], msg[i]);
00566 }
00567 }
00568
00569 rtabmap::CameraModel cameraModelFromROS(
00570 const sensor_msgs::CameraInfo & camInfo,
00571 const rtabmap::Transform & localTransform)
00572 {
00573 cv:: Mat K;
00574 UASSERT(camInfo.K.empty() || camInfo.K.size() == 9);
00575 if(!camInfo.K.empty())
00576 {
00577 K = cv::Mat(3, 3, CV_64FC1);
00578 memcpy(K.data, camInfo.K.elems, 9*sizeof(double));
00579 }
00580
00581 cv::Mat D;
00582 if(camInfo.D.size())
00583 {
00584 if(camInfo.D.size()>=4 &&
00585 (uStrContains(camInfo.distortion_model, "fisheye") ||
00586 uStrContains(camInfo.distortion_model, "equidistant")))
00587 {
00588 D = cv::Mat::zeros(1, 6, CV_64FC1);
00589 D.at<double>(0,0) = camInfo.D[0];
00590 D.at<double>(0,1) = camInfo.D[1];
00591 D.at<double>(0,4) = camInfo.D[2];
00592 D.at<double>(0,5) = camInfo.D[3];
00593 }
00594 else
00595 {
00596 D = cv::Mat(1, camInfo.D.size(), CV_64FC1);
00597 memcpy(D.data, camInfo.D.data(), D.cols*sizeof(double));
00598 }
00599 }
00600
00601 cv:: Mat R;
00602 UASSERT(camInfo.R.empty() || camInfo.R.size() == 9);
00603 if(!camInfo.R.empty())
00604 {
00605 R = cv::Mat(3, 3, CV_64FC1);
00606 memcpy(R.data, camInfo.R.elems, 9*sizeof(double));
00607 }
00608
00609 cv:: Mat P;
00610 UASSERT(camInfo.P.empty() || camInfo.P.size() == 12);
00611 if(!camInfo.P.empty())
00612 {
00613 P = cv::Mat(3, 4, CV_64FC1);
00614 memcpy(P.data, camInfo.P.elems, 12*sizeof(double));
00615 }
00616
00617 return rtabmap::CameraModel(
00618 "ros",
00619 cv::Size(camInfo.width, camInfo.height),
00620 K, D, R, P,
00621 localTransform);
00622 }
00623 void cameraModelToROS(
00624 const rtabmap::CameraModel & model,
00625 sensor_msgs::CameraInfo & camInfo)
00626 {
00627 UASSERT(model.K_raw().empty() || model.K_raw().total() == 9);
00628 if(model.K_raw().empty())
00629 {
00630 memset(camInfo.K.elems, 0.0, 9*sizeof(double));
00631 }
00632 else
00633 {
00634 memcpy(camInfo.K.elems, model.K_raw().data, 9*sizeof(double));
00635 }
00636
00637 if(camInfo.D.size() == 6)
00638 {
00639 camInfo.D = std::vector<double>(4);
00640 camInfo.D[0] = model.D_raw().at<double>(0,0);
00641 camInfo.D[1] = model.D_raw().at<double>(0,1);
00642 camInfo.D[2] = model.D_raw().at<double>(0,4);
00643 camInfo.D[3] = model.D_raw().at<double>(0,5);
00644 camInfo.distortion_model = "equidistant";
00645 }
00646 else
00647 {
00648 camInfo.D = std::vector<double>(model.D_raw().cols);
00649 memcpy(camInfo.D.data(), model.D_raw().data, model.D_raw().cols*sizeof(double));
00650 if(camInfo.D.size() > 5)
00651 {
00652 camInfo.distortion_model = "rational_polynomial";
00653 }
00654 else
00655 {
00656 camInfo.distortion_model = "plumb_bob";
00657 }
00658 }
00659
00660 UASSERT(model.R().empty() || model.R().total() == 9);
00661 if(model.R().empty())
00662 {
00663 memset(camInfo.R.elems, 0.0, 9*sizeof(double));
00664 }
00665 else
00666 {
00667 memcpy(camInfo.R.elems, model.R().data, 9*sizeof(double));
00668 }
00669
00670 UASSERT(model.P().empty() || model.P().total() == 12);
00671 if(model.P().empty())
00672 {
00673 memset(camInfo.P.elems, 0.0, 12*sizeof(double));
00674 }
00675 else
00676 {
00677 memcpy(camInfo.P.elems, model.P().data, 12*sizeof(double));
00678 }
00679
00680 camInfo.binning_x = 1;
00681 camInfo.binning_y = 1;
00682 camInfo.roi.width = model.imageWidth();
00683 camInfo.roi.height = model.imageHeight();
00684
00685 camInfo.width = model.imageWidth();
00686 camInfo.height = model.imageHeight();
00687 }
00688 rtabmap::StereoCameraModel stereoCameraModelFromROS(
00689 const sensor_msgs::CameraInfo & leftCamInfo,
00690 const sensor_msgs::CameraInfo & rightCamInfo,
00691 const rtabmap::Transform & localTransform)
00692 {
00693 return rtabmap::StereoCameraModel(
00694 "ros",
00695 cameraModelFromROS(leftCamInfo, localTransform),
00696 cameraModelFromROS(rightCamInfo, localTransform),
00697 rtabmap::Transform());
00698 }
00699
00700 void mapDataFromROS(
00701 const rtabmap_ros::MapData & msg,
00702 std::map<int, rtabmap::Transform> & poses,
00703 std::multimap<int, rtabmap::Link> & links,
00704 std::map<int, rtabmap::Signature> & signatures,
00705 rtabmap::Transform & mapToOdom)
00706 {
00707
00708 mapGraphFromROS(msg.graph, poses, links, mapToOdom);
00709
00710
00711 for(unsigned int i=0; i<msg.nodes.size(); ++i)
00712 {
00713 signatures.insert(std::make_pair(msg.nodes[i].id, nodeDataFromROS(msg.nodes[i])));
00714 }
00715 }
00716 void mapDataToROS(
00717 const std::map<int, rtabmap::Transform> & poses,
00718 const std::multimap<int, rtabmap::Link> & links,
00719 const std::map<int, rtabmap::Signature> & signatures,
00720 const rtabmap::Transform & mapToOdom,
00721 rtabmap_ros::MapData & msg)
00722 {
00723
00724 mapGraphToROS(poses, links, mapToOdom, msg.graph);
00725
00726
00727 msg.nodes.resize(signatures.size());
00728 int index=0;
00729 for(std::multimap<int, rtabmap::Signature>::const_iterator iter = signatures.begin();
00730 iter!=signatures.end();
00731 ++iter)
00732 {
00733 nodeDataToROS(iter->second, msg.nodes[index++]);
00734 }
00735 }
00736
00737 void mapGraphFromROS(
00738 const rtabmap_ros::MapGraph & msg,
00739 std::map<int, rtabmap::Transform> & poses,
00740 std::multimap<int, rtabmap::Link> & links,
00741 rtabmap::Transform & mapToOdom)
00742 {
00743
00744 UASSERT(msg.posesId.size() == msg.poses.size());
00745 for(unsigned int i=0; i<msg.posesId.size(); ++i)
00746 {
00747 poses.insert(std::make_pair(msg.posesId[i], rtabmap_ros::transformFromPoseMsg(msg.poses[i])));
00748 }
00749 for(unsigned int i=0; i<msg.links.size(); ++i)
00750 {
00751 rtabmap::Transform t = rtabmap_ros::transformFromGeometryMsg(msg.links[i].transform);
00752 links.insert(std::make_pair(msg.links[i].fromId, linkFromROS(msg.links[i])));
00753 }
00754 mapToOdom = transformFromGeometryMsg(msg.mapToOdom);
00755 }
00756 void mapGraphToROS(
00757 const std::map<int, rtabmap::Transform> & poses,
00758 const std::multimap<int, rtabmap::Link> & links,
00759 const rtabmap::Transform & mapToOdom,
00760 rtabmap_ros::MapGraph & msg)
00761 {
00762
00763 msg.posesId.resize(poses.size());
00764 msg.poses.resize(poses.size());
00765 int index = 0;
00766 for(std::map<int, rtabmap::Transform>::const_iterator iter = poses.begin();
00767 iter != poses.end();
00768 ++iter)
00769 {
00770 msg.posesId[index] = iter->first;
00771 transformToPoseMsg(iter->second, msg.poses[index]);
00772 ++index;
00773 }
00774
00775 msg.links.resize(links.size());
00776 index=0;
00777 for(std::multimap<int, rtabmap::Link>::const_iterator iter = links.begin();
00778 iter!=links.end();
00779 ++iter)
00780 {
00781 linkToROS(iter->second, msg.links[index++]);
00782 }
00783
00784 transformToGeometryMsg(mapToOdom, msg.mapToOdom);
00785 }
00786
00787 rtabmap::Signature nodeDataFromROS(const rtabmap_ros::NodeData & msg)
00788 {
00789
00790 std::multimap<int, cv::KeyPoint> words;
00791 std::multimap<int, cv::Point3f> words3D;
00792 std::multimap<int, cv::Mat> wordsDescriptors;
00793 pcl::PointCloud<pcl::PointXYZ> cloud;
00794 cv::Mat descriptors;
00795 if(msg.wordPts.data.size() &&
00796 msg.wordPts.height*msg.wordPts.width == msg.wordIds.size())
00797 {
00798 pcl::fromROSMsg(msg.wordPts, cloud);
00799 descriptors = rtabmap::uncompressData(msg.descriptors);
00800 }
00801
00802 for(unsigned int i=0; i<msg.wordIds.size() && i<msg.wordKpts.size(); ++i)
00803 {
00804 cv::KeyPoint pt = keypointFromROS(msg.wordKpts.at(i));
00805 int wordId = msg.wordIds.at(i);
00806 words.insert(std::make_pair(wordId, pt));
00807 if(i< cloud.size())
00808 {
00809 words3D.insert(std::make_pair(wordId, cv::Point3f(cloud[i].x, cloud[i].y, cloud[i].z)));
00810 }
00811 if(i < descriptors.rows)
00812 {
00813 wordsDescriptors.insert(std::make_pair(wordId, descriptors.row(i).clone()));
00814 }
00815 }
00816
00817 if(words3D.size() && words3D.size() != words.size())
00818 {
00819 ROS_ERROR("Words 2D and 3D should be the same size (%d, %d)!", (int)words.size(), (int)words3D.size());
00820 }
00821
00822 rtabmap::StereoCameraModel stereoModel;
00823 std::vector<rtabmap::CameraModel> models;
00824 if(msg.baseline > 0.0f)
00825 {
00826
00827 if(msg.fx.size() == 1 &&
00828 msg.fy.size() == 1 &&
00829 msg.cx.size() == 1 &&
00830 msg.cy.size() == 1 &&
00831 msg.width.size() == 1 &&
00832 msg.height.size() == 1 &&
00833 msg.localTransform.size() == 1)
00834 {
00835 stereoModel = rtabmap::StereoCameraModel(
00836 msg.fx[0],
00837 msg.fy[0],
00838 msg.cx[0],
00839 msg.cy[0],
00840 msg.baseline,
00841 transformFromGeometryMsg(msg.localTransform[0]),
00842 cv::Size(msg.width[0], msg.height[0]));
00843 }
00844 }
00845 else
00846 {
00847
00848 if(msg.fx.size() &&
00849 msg.fx.size() == msg.fy.size(),
00850 msg.fx.size() == msg.cx.size(),
00851 msg.fx.size() == msg.cy.size(),
00852 msg.fx.size() == msg.localTransform.size())
00853 {
00854 for(unsigned int i=0; i<msg.fx.size(); ++i)
00855 {
00856 models.push_back(rtabmap::CameraModel(
00857 msg.fx[i],
00858 msg.fy[i],
00859 msg.cx[i],
00860 msg.cy[i],
00861 transformFromGeometryMsg(msg.localTransform[i]),
00862 0.0,
00863 cv::Size(msg.width[i], msg.height[i])));
00864 }
00865 }
00866 }
00867
00868 rtabmap::Signature s(
00869 msg.id,
00870 msg.mapId,
00871 msg.weight,
00872 msg.stamp,
00873 msg.label,
00874 transformFromPoseMsg(msg.pose),
00875 transformFromPoseMsg(msg.groundTruthPose),
00876 stereoModel.isValidForProjection()?
00877 rtabmap::SensorData(
00878 rtabmap::LaserScan(compressedMatFromBytes(msg.laserScan),
00879 msg.laserScanMaxPts,
00880 msg.laserScanMaxRange,
00881 (rtabmap::LaserScan::Format)msg.laserScanFormat,
00882 transformFromGeometryMsg(msg.laserScanLocalTransform)),
00883 compressedMatFromBytes(msg.image),
00884 compressedMatFromBytes(msg.depth),
00885 stereoModel,
00886 msg.id,
00887 msg.stamp,
00888 compressedMatFromBytes(msg.userData)):
00889 rtabmap::SensorData(
00890 rtabmap::LaserScan(compressedMatFromBytes(msg.laserScan),
00891 msg.laserScanMaxPts,
00892 msg.laserScanMaxRange,
00893 (rtabmap::LaserScan::Format)msg.laserScanFormat,
00894 transformFromGeometryMsg(msg.laserScanLocalTransform)),
00895 compressedMatFromBytes(msg.image),
00896 compressedMatFromBytes(msg.depth),
00897 models,
00898 msg.id,
00899 msg.stamp,
00900 compressedMatFromBytes(msg.userData)));
00901 s.setWords(words);
00902 s.setWords3(words3D);
00903 s.setWordsDescriptors(wordsDescriptors);
00904 s.sensorData().setOccupancyGrid(
00905 compressedMatFromBytes(msg.grid_ground),
00906 compressedMatFromBytes(msg.grid_obstacles),
00907 compressedMatFromBytes(msg.grid_empty_cells),
00908 msg.grid_cell_size,
00909 point3fFromROS(msg.grid_view_point));
00910 s.sensorData().setGPS(rtabmap::GPS(msg.gps.stamp, msg.gps.longitude, msg.gps.latitude, msg.gps.altitude, msg.gps.error, msg.gps.bearing));
00911 return s;
00912 }
00913 void nodeDataToROS(const rtabmap::Signature & signature, rtabmap_ros::NodeData & msg)
00914 {
00915
00916 msg.id = signature.id();
00917 msg.mapId = signature.mapId();
00918 msg.weight = signature.getWeight();
00919 msg.stamp = signature.getStamp();
00920 msg.label = signature.getLabel();
00921 transformToPoseMsg(signature.getPose(), msg.pose);
00922 transformToPoseMsg(signature.getGroundTruthPose(), msg.groundTruthPose);
00923 msg.gps.stamp = signature.sensorData().gps().stamp();
00924 msg.gps.longitude = signature.sensorData().gps().longitude();
00925 msg.gps.latitude = signature.sensorData().gps().latitude();
00926 msg.gps.altitude = signature.sensorData().gps().altitude();
00927 msg.gps.error = signature.sensorData().gps().error();
00928 msg.gps.bearing = signature.sensorData().gps().bearing();
00929 compressedMatToBytes(signature.sensorData().imageCompressed(), msg.image);
00930 compressedMatToBytes(signature.sensorData().depthOrRightCompressed(), msg.depth);
00931 compressedMatToBytes(signature.sensorData().laserScanCompressed().data(), msg.laserScan);
00932 compressedMatToBytes(signature.sensorData().userDataCompressed(), msg.userData);
00933 compressedMatToBytes(signature.sensorData().gridGroundCellsCompressed(), msg.grid_ground);
00934 compressedMatToBytes(signature.sensorData().gridObstacleCellsCompressed(), msg.grid_obstacles);
00935 compressedMatToBytes(signature.sensorData().gridEmptyCellsCompressed(), msg.grid_empty_cells);
00936 point3fToROS(signature.sensorData().gridViewPoint(), msg.grid_view_point);
00937 msg.grid_cell_size = signature.sensorData().gridCellSize();
00938 msg.laserScanMaxPts = signature.sensorData().laserScanCompressed().maxPoints();
00939 msg.laserScanMaxRange = signature.sensorData().laserScanCompressed().maxRange();
00940 msg.laserScanFormat = signature.sensorData().laserScanCompressed().format();
00941 transformToGeometryMsg(signature.sensorData().laserScanCompressed().localTransform(), msg.laserScanLocalTransform);
00942 msg.baseline = 0;
00943 if(signature.sensorData().cameraModels().size())
00944 {
00945 msg.fx.resize(signature.sensorData().cameraModels().size());
00946 msg.fy.resize(signature.sensorData().cameraModels().size());
00947 msg.cx.resize(signature.sensorData().cameraModels().size());
00948 msg.cy.resize(signature.sensorData().cameraModels().size());
00949 msg.width.resize(signature.sensorData().cameraModels().size());
00950 msg.height.resize(signature.sensorData().cameraModels().size());
00951 msg.localTransform.resize(signature.sensorData().cameraModels().size());
00952 for(unsigned int i=0; i<signature.sensorData().cameraModels().size(); ++i)
00953 {
00954 msg.fx[i] = signature.sensorData().cameraModels()[i].fx();
00955 msg.fy[i] = signature.sensorData().cameraModels()[i].fy();
00956 msg.cx[i] = signature.sensorData().cameraModels()[i].cx();
00957 msg.cy[i] = signature.sensorData().cameraModels()[i].cy();
00958 msg.width[i] = signature.sensorData().cameraModels()[i].imageWidth();
00959 msg.height[i] = signature.sensorData().cameraModels()[i].imageHeight();
00960 transformToGeometryMsg(signature.sensorData().cameraModels()[i].localTransform(), msg.localTransform[i]);
00961 }
00962 }
00963 else if(signature.sensorData().stereoCameraModel().isValidForProjection())
00964 {
00965 msg.fx.push_back(signature.sensorData().stereoCameraModel().left().fx());
00966 msg.fy.push_back(signature.sensorData().stereoCameraModel().left().fy());
00967 msg.cx.push_back(signature.sensorData().stereoCameraModel().left().cx());
00968 msg.cy.push_back(signature.sensorData().stereoCameraModel().left().cy());
00969 msg.width.push_back(signature.sensorData().stereoCameraModel().left().imageWidth());
00970 msg.height.push_back(signature.sensorData().stereoCameraModel().left().imageHeight());
00971 msg.baseline = signature.sensorData().stereoCameraModel().baseline();
00972 msg.localTransform.resize(1);
00973 transformToGeometryMsg(signature.sensorData().stereoCameraModel().left().localTransform(), msg.localTransform[0]);
00974 }
00975
00976
00977 msg.wordIds = uKeys(signature.getWords());
00978 msg.wordKpts.resize(signature.getWords().size());
00979 int index = 0;
00980 for(std::multimap<int, cv::KeyPoint>::const_iterator jter=signature.getWords().begin();
00981 jter!=signature.getWords().end();
00982 ++jter)
00983 {
00984 keypointToROS(jter->second, msg.wordKpts.at(index++));
00985 }
00986
00987 if(signature.getWords3().size() && signature.getWords3().size() == signature.getWords().size())
00988 {
00989 pcl::PointCloud<pcl::PointXYZ> cloud;
00990 cloud.resize(signature.getWords3().size());
00991 index = 0;
00992 for(std::multimap<int, cv::Point3f>::const_iterator jter=signature.getWords3().begin();
00993 jter!=signature.getWords3().end();
00994 ++jter)
00995 {
00996 cloud[index].x = jter->second.x;
00997 cloud[index].y = jter->second.y;
00998 cloud[index++].z = jter->second.z;
00999 }
01000 pcl::toROSMsg(cloud, msg.wordPts);
01001 }
01002 else if(signature.getWords3().size())
01003 {
01004 ROS_ERROR("Words 2D and words 3D must have the same size (%d vs %d)!",
01005 (int)signature.getWords().size(),
01006 (int)signature.getWords3().size());
01007 }
01008
01009 if(signature.getWordsDescriptors().size() && signature.getWordsDescriptors().size() == signature.getWords().size())
01010 {
01011 cv::Mat descriptors(
01012 signature.getWordsDescriptors().size(),
01013 signature.getWordsDescriptors().begin()->second.cols,
01014 signature.getWordsDescriptors().begin()->second.type());
01015 index = 0;
01016 bool valid = true;
01017 for(std::multimap<int, cv::Mat>::const_iterator jter=signature.getWordsDescriptors().begin();
01018 jter!=signature.getWordsDescriptors().end() && valid;
01019 ++jter)
01020 {
01021 if(jter->second.cols == descriptors.cols &&
01022 jter->second.type() == descriptors.type())
01023 {
01024 jter->second.copyTo(descriptors.row(index++));
01025 }
01026 else
01027 {
01028 valid = false;
01029 ROS_ERROR("Some descriptors have different type/size! Cannot copy them...");
01030 }
01031 }
01032
01033 if(valid)
01034 {
01035 msg.descriptors = rtabmap::compressData(descriptors);
01036 }
01037 }
01038 else if(signature.getWordsDescriptors().size())
01039 {
01040 ROS_ERROR("Words and descriptors must have the same size (%d vs %d)!",
01041 (int)signature.getWords().size(),
01042 (int)signature.getWordsDescriptors().size());
01043 }
01044 }
01045
01046 rtabmap::Signature nodeInfoFromROS(const rtabmap_ros::NodeData & msg)
01047 {
01048 rtabmap::Signature s(
01049 msg.id,
01050 msg.mapId,
01051 msg.weight,
01052 msg.stamp,
01053 msg.label,
01054 transformFromPoseMsg(msg.pose),
01055 transformFromPoseMsg(msg.groundTruthPose));
01056 return s;
01057 }
01058 void nodeInfoToROS(const rtabmap::Signature & signature, rtabmap_ros::NodeData & msg)
01059 {
01060
01061 msg.id = signature.id();
01062 msg.mapId = signature.mapId();
01063 msg.weight = signature.getWeight();
01064 msg.stamp = signature.getStamp();
01065 msg.label = signature.getLabel();
01066 transformToPoseMsg(signature.getPose(), msg.pose);
01067 transformToPoseMsg(signature.getGroundTruthPose(), msg.groundTruthPose);
01068 }
01069
01070 rtabmap::OdometryInfo odomInfoFromROS(const rtabmap_ros::OdomInfo & msg)
01071 {
01072 rtabmap::OdometryInfo info;
01073 info.lost = msg.lost;
01074 info.reg.matches = msg.matches;
01075 info.reg.inliers = msg.inliers;
01076 info.reg.icpInliersRatio = msg.icpInliersRatio;
01077 info.reg.icpRotation = msg.icpRotation;
01078 info.reg.icpTranslation = msg.icpTranslation;
01079 info.reg.icpStructuralComplexity = msg.icpStructuralComplexity;
01080 info.reg.covariance = cv::Mat(6,6,CV_64FC1, (void*)msg.covariance.data()).clone();
01081 info.features = msg.features;
01082 info.localMapSize = msg.localMapSize;
01083 info.localScanMapSize = msg.localScanMapSize;
01084 info.localKeyFrames = msg.localKeyFrames;
01085 info.localBundleOutliers = msg.localBundleOutliers;
01086 info.localBundleConstraints = msg.localBundleConstraints;
01087 info.localBundleTime = msg.localBundleTime;
01088 info.keyFrameAdded = msg.keyFrameAdded;
01089 info.timeEstimation = msg.timeEstimation;
01090 info.timeParticleFiltering = msg.timeParticleFiltering;
01091 info.stamp = msg.stamp;
01092 info.interval = msg.interval;
01093 info.distanceTravelled = msg.distanceTravelled;
01094 info.memoryUsage = msg.memoryUsage;
01095
01096 info.type = msg.type;
01097
01098 UASSERT(msg.wordsKeys.size() == msg.wordsValues.size());
01099 for(unsigned int i=0; i<msg.wordsKeys.size(); ++i)
01100 {
01101 info.words.insert(std::make_pair(msg.wordsKeys[i], keypointFromROS(msg.wordsValues[i])));
01102 }
01103
01104 info.reg.matchesIDs = msg.wordMatches;
01105 info.reg.inliersIDs = msg.wordInliers;
01106
01107 info.refCorners = points2fFromROS(msg.refCorners);
01108 info.newCorners = points2fFromROS(msg.newCorners);
01109 info.cornerInliers = msg.cornerInliers;
01110
01111 info.transform = transformFromGeometryMsg(msg.transform);
01112 info.transformFiltered = transformFromGeometryMsg(msg.transformFiltered);
01113
01114 UASSERT(msg.localMapKeys.size() == msg.localMapValues.size());
01115 for(unsigned int i=0; i<msg.localMapKeys.size(); ++i)
01116 {
01117 info.localMap.insert(std::make_pair(msg.localMapKeys[i], point3fFromROS(msg.localMapValues[i])));
01118 }
01119
01120 info.localScanMap = rtabmap::LaserScan::backwardCompatibility(rtabmap::uncompressData(msg.localScanMap));
01121
01122 return info;
01123 }
01124
01125 void odomInfoToROS(const rtabmap::OdometryInfo & info, rtabmap_ros::OdomInfo & msg)
01126 {
01127 msg.lost = info.lost;
01128 msg.matches = info.reg.matches;
01129 msg.inliers = info.reg.inliers;
01130 msg.icpInliersRatio = info.reg.icpInliersRatio;
01131 msg.icpRotation = info.reg.icpRotation;
01132 msg.icpTranslation = info.reg.icpTranslation;
01133 msg.icpStructuralComplexity = info.reg.icpStructuralComplexity;
01134 if(info.reg.covariance.type() == CV_64FC1 && info.reg.covariance.cols == 6 && info.reg.covariance.rows == 6)
01135 {
01136 memcpy(msg.covariance.data(), info.reg.covariance.data, 36*sizeof(double));
01137 }
01138 msg.features = info.features;
01139 msg.localMapSize = info.localMapSize;
01140 msg.localScanMapSize = info.localScanMapSize;
01141 msg.localKeyFrames = info.localKeyFrames;
01142 msg.localBundleOutliers = info.localBundleOutliers;
01143 msg.localBundleConstraints = info.localBundleConstraints;
01144 msg.localBundleTime = info.localBundleTime;
01145 msg.keyFrameAdded = info.keyFrameAdded;
01146 msg.timeEstimation = info.timeEstimation;
01147 msg.timeParticleFiltering = info.timeParticleFiltering;
01148 msg.stamp = info.stamp;
01149 msg.interval = info.interval;
01150 msg.distanceTravelled = info.distanceTravelled;
01151 msg.memoryUsage = info.memoryUsage;
01152
01153 msg.type = info.type;
01154
01155 msg.wordsKeys = uKeys(info.words);
01156 keypointsToROS(uValues(info.words), msg.wordsValues);
01157
01158 msg.wordMatches = info.reg.matchesIDs;
01159 msg.wordInliers = info.reg.inliersIDs;
01160
01161 points2fToROS(info.refCorners, msg.refCorners);
01162 points2fToROS(info.newCorners, msg.newCorners);
01163 msg.cornerInliers = info.cornerInliers;
01164
01165 transformToGeometryMsg(info.transform, msg.transform);
01166 transformToGeometryMsg(info.transformFiltered, msg.transformFiltered);
01167
01168 msg.localMapKeys = uKeys(info.localMap);
01169 points3fToROS(uValues(info.localMap), msg.localMapValues);
01170
01171 msg.localScanMap = rtabmap::compressData(rtabmap::util3d::transformLaserScan(info.localScanMap, info.localScanMap.localTransform()).data());
01172 }
01173
01174 cv::Mat userDataFromROS(const rtabmap_ros::UserData & dataMsg)
01175 {
01176 cv::Mat data;
01177 if(!dataMsg.data.empty())
01178 {
01179 if(dataMsg.cols > 0 && dataMsg.rows > 0 && dataMsg.type >= 0)
01180 {
01181 data = cv::Mat(dataMsg.rows, dataMsg.cols, dataMsg.type, (void*)dataMsg.data.data()).clone();
01182 }
01183 else
01184 {
01185 if(dataMsg.cols != (int)dataMsg.data.size() || dataMsg.rows != 1 || dataMsg.type != CV_8UC1)
01186 {
01187 ROS_ERROR("cols, rows and type fields of the UserData msg "
01188 "are not correctly set (cols=%d, rows=%d, type=%d)! We assume that the data "
01189 "is compressed (cols=%d, rows=1, type=%d(CV_8UC1)).",
01190 dataMsg.cols, dataMsg.rows, dataMsg.type, (int)dataMsg.data.size(), CV_8UC1);
01191
01192 }
01193 data = cv::Mat(1, dataMsg.data.size(), CV_8UC1, (void*)dataMsg.data.data()).clone();
01194 }
01195 }
01196 return data;
01197 }
01198 void userDataToROS(const cv::Mat & data, rtabmap_ros::UserData & dataMsg, bool compress)
01199 {
01200 if(!data.empty())
01201 {
01202 if(compress)
01203 {
01204 dataMsg.data = rtabmap::compressData(data);
01205 dataMsg.rows = 1;
01206 dataMsg.cols = dataMsg.data.size();
01207 dataMsg.type = CV_8UC1;
01208 }
01209 else
01210 {
01211 dataMsg.data.resize(data.step[0] * data.rows);
01212 memcpy(dataMsg.data.data(), data.data, dataMsg.data.size());
01213 dataMsg.rows = data.rows;
01214 dataMsg.cols = data.cols;
01215 dataMsg.type = data.type();
01216 }
01217 }
01218 }
01219
01220 rtabmap::Transform getTransform(
01221 const std::string & fromFrameId,
01222 const std::string & toFrameId,
01223 const ros::Time & stamp,
01224 tf::TransformListener & listener,
01225 double waitForTransform)
01226 {
01227
01228 rtabmap::Transform transform;
01229 try
01230 {
01231 if(waitForTransform > 0.0 && !stamp.isZero())
01232 {
01233
01234 std::string errorMsg;
01235 if(!listener.waitForTransform(fromFrameId, toFrameId, stamp, ros::Duration(waitForTransform), ros::Duration(0.01), &errorMsg))
01236 {
01237 ROS_WARN("Could not get transform from %s to %s after %f seconds (for stamp=%f)! Error=\"%s\".",
01238 fromFrameId.c_str(), toFrameId.c_str(), waitForTransform, stamp.toSec(), errorMsg.c_str());
01239 return transform;
01240 }
01241 }
01242
01243 tf::StampedTransform tmp;
01244 listener.lookupTransform(fromFrameId, toFrameId, stamp, tmp);
01245 transform = rtabmap_ros::transformFromTF(tmp);
01246 }
01247 catch(tf::TransformException & ex)
01248 {
01249 ROS_WARN("(getting transform %s -> %s) %s", fromFrameId.c_str(), toFrameId.c_str(), ex.what());
01250 }
01251 return transform;
01252 }
01253
01254
01255
01256 rtabmap::Transform getTransform(
01257 const std::string & sourceTargetFrame,
01258 const std::string & fixedFrame,
01259 const ros::Time & stampSource,
01260 const ros::Time & stampTarget,
01261 tf::TransformListener & listener,
01262 double waitForTransform)
01263 {
01264
01265 rtabmap::Transform transform;
01266 try
01267 {
01268 ros::Time stamp = stampSource>stampTarget?stampSource:stampTarget;
01269 if(waitForTransform > 0.0 && !stamp.isZero())
01270 {
01271 std::string errorMsg;
01272 if(!listener.waitForTransform(sourceTargetFrame, fixedFrame, stamp, ros::Duration(waitForTransform), ros::Duration(0.01), &errorMsg))
01273 {
01274 ROS_WARN("Could not get transform from %s to %s accordingly to %s after %f seconds (for stamps=%f -> %f)! Error=\"%s\".",
01275 sourceTargetFrame.c_str(), sourceTargetFrame.c_str(), fixedFrame.c_str(), waitForTransform, stampSource.toSec(), stampTarget.toSec(), errorMsg.c_str());
01276 return transform;
01277 }
01278 }
01279
01280 tf::StampedTransform tmp;
01281 listener.lookupTransform(sourceTargetFrame, stampTarget, sourceTargetFrame, stampSource, fixedFrame, tmp);
01282 transform = rtabmap_ros::transformFromTF(tmp);
01283 }
01284 catch(tf::TransformException & ex)
01285 {
01286 ROS_WARN("(getting transform movement of %s according to fixed %s) %s", sourceTargetFrame.c_str(), fixedFrame.c_str(), ex.what());
01287 }
01288 return transform;
01289 }
01290
01291 bool convertRGBDMsgs(
01292 const std::vector<cv_bridge::CvImageConstPtr> & imageMsgs,
01293 const std::vector<cv_bridge::CvImageConstPtr> & depthMsgs,
01294 const std::vector<sensor_msgs::CameraInfo> & cameraInfoMsgs,
01295 const std::string & frameId,
01296 const std::string & odomFrameId,
01297 const ros::Time & odomStamp,
01298 cv::Mat & rgb,
01299 cv::Mat & depth,
01300 std::vector<rtabmap::CameraModel> & cameraModels,
01301 tf::TransformListener & listener,
01302 double waitForTransform)
01303 {
01304 UASSERT(imageMsgs.size()>0 &&
01305 (imageMsgs.size() == depthMsgs.size() || depthMsgs.empty()) &&
01306 imageMsgs.size() == cameraInfoMsgs.size());
01307
01308 int imageWidth = imageMsgs[0]->image.cols;
01309 int imageHeight = imageMsgs[0]->image.rows;
01310 int depthWidth = depthMsgs.size()?depthMsgs[0]->image.cols:0;
01311 int depthHeight = depthMsgs.size()?depthMsgs[0]->image.rows:0;
01312
01313 if(depthMsgs.size())
01314 {
01315 UASSERT_MSG(
01316 imageWidth % depthWidth == 0 && imageHeight % depthHeight == 0 &&
01317 imageWidth/depthWidth == imageHeight/depthHeight,
01318 uFormat("rgb=%dx%d depth=%dx%d", imageWidth, imageHeight, depthWidth, depthHeight).c_str());
01319 }
01320
01321 int cameraCount = imageMsgs.size();
01322 for(unsigned int i=0; i<imageMsgs.size(); ++i)
01323 {
01324 if(!(imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::TYPE_8UC1) == 0 ||
01325 imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::MONO8) ==0 ||
01326 imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::MONO16) ==0 ||
01327 imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0 ||
01328 imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::RGB8) == 0 ||
01329 imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::BGRA8) == 0 ||
01330 imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::RGBA8) == 0 ||
01331 imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::BAYER_GRBG8) == 0))
01332 {
01333
01334 ROS_ERROR("Input rgb type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8. Current rgb=%s",
01335 imageMsgs[i]->encoding.c_str());
01336 return false;
01337 }
01338 if(depthMsgs.size() &&
01339 !(depthMsgs[i]->encoding.compare(sensor_msgs::image_encodings::TYPE_16UC1) == 0 ||
01340 depthMsgs[i]->encoding.compare(sensor_msgs::image_encodings::TYPE_32FC1) == 0 ||
01341 depthMsgs[i]->encoding.compare(sensor_msgs::image_encodings::MONO16) == 0))
01342 {
01343 ROS_ERROR("Input depth type must be image_depth=32FC1,16UC1,mono16. Current depth=%s",
01344 depthMsgs[i]->encoding.c_str());
01345 return false;
01346 }
01347
01348 UASSERT_MSG(imageMsgs[i]->image.cols == imageWidth && imageMsgs[i]->image.rows == imageHeight,
01349 uFormat("imageWidth=%d vs %d imageHeight=%d vs %d",
01350 imageWidth,
01351 imageMsgs[i]->image.cols,
01352 imageHeight,
01353 imageMsgs[i]->image.rows).c_str());
01354 ros::Time stamp;
01355 if(depthMsgs.size())
01356 {
01357 UASSERT_MSG(depthMsgs[i]->image.cols == depthWidth && depthMsgs[i]->image.rows == depthHeight,
01358 uFormat("depthWidth=%d vs %d imageHeight=%d vs %d",
01359 depthWidth,
01360 depthMsgs[i]->image.cols,
01361 depthHeight,
01362 depthMsgs[i]->image.rows).c_str());
01363 stamp = depthMsgs[i]->header.stamp;
01364 }
01365 else
01366 {
01367 stamp = imageMsgs[i]->header.stamp;
01368 }
01369
01370
01371 rtabmap::Transform localTransform = rtabmap_ros::getTransform(frameId, imageMsgs[i]->header.frame_id, stamp, listener, waitForTransform);
01372 if(localTransform.isNull())
01373 {
01374 ROS_ERROR("TF of received image %d at time %fs is not set!", i, stamp.toSec());
01375 return false;
01376 }
01377
01378 if(!odomFrameId.empty() && odomStamp != stamp)
01379 {
01380 rtabmap::Transform sensorT = getTransform(
01381 frameId,
01382 odomFrameId,
01383 odomStamp,
01384 stamp,
01385 listener,
01386 waitForTransform);
01387 if(sensorT.isNull())
01388 {
01389 ROS_WARN("Could not get odometry value for depth image stamp (%fs). Latest odometry "
01390 "stamp is %fs. The depth image pose will not be synchronized with odometry.", stamp.toSec(), odomStamp.toSec());
01391 }
01392 else
01393 {
01394
01395 localTransform = sensorT * localTransform;
01396 }
01397 }
01398
01399 cv_bridge::CvImageConstPtr ptrImage = imageMsgs[i];
01400 if(imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::TYPE_8UC1)==0 ||
01401 imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::MONO8) == 0 ||
01402 imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0)
01403 {
01404
01405 }
01406 else if(imageMsgs[i]->encoding.compare(sensor_msgs::image_encodings::MONO16) == 0)
01407 {
01408 ptrImage = cv_bridge::cvtColor(imageMsgs[i], "mono8");
01409 }
01410 else
01411 {
01412 ptrImage = cv_bridge::cvtColor(imageMsgs[i], "bgr8");
01413 }
01414
01415
01416 if(rgb.empty())
01417 {
01418 rgb = cv::Mat(imageHeight, imageWidth*cameraCount, ptrImage->image.type());
01419 }
01420 if(ptrImage->image.type() == rgb.type())
01421 {
01422 ptrImage->image.copyTo(cv::Mat(rgb, cv::Rect(i*imageWidth, 0, imageWidth, imageHeight)));
01423 }
01424 else
01425 {
01426 ROS_ERROR("Some RGB images are not the same type!");
01427 return false;
01428 }
01429
01430 if(depthMsgs.size())
01431 {
01432 cv_bridge::CvImageConstPtr ptrDepth = depthMsgs[i];
01433 cv::Mat subDepth = ptrDepth->image;
01434
01435 if(depth.empty())
01436 {
01437 depth = cv::Mat(depthHeight, depthWidth*cameraCount, subDepth.type());
01438 }
01439
01440 if(subDepth.type() == depth.type())
01441 {
01442 subDepth.copyTo(cv::Mat(depth, cv::Rect(i*depthWidth, 0, depthWidth, depthHeight)));
01443 }
01444 else
01445 {
01446 ROS_ERROR("Some Depth images are not the same type!");
01447 return false;
01448 }
01449 }
01450
01451 cameraModels.push_back(rtabmap_ros::cameraModelFromROS(cameraInfoMsgs[i], localTransform));
01452 }
01453 return true;
01454 }
01455
01456 bool convertStereoMsg(
01457 const cv_bridge::CvImageConstPtr& leftImageMsg,
01458 const cv_bridge::CvImageConstPtr& rightImageMsg,
01459 const sensor_msgs::CameraInfo& leftCamInfoMsg,
01460 const sensor_msgs::CameraInfo& rightCamInfoMsg,
01461 const std::string & frameId,
01462 const std::string & odomFrameId,
01463 const ros::Time & odomStamp,
01464 cv::Mat & left,
01465 cv::Mat & right,
01466 rtabmap::StereoCameraModel & stereoModel,
01467 tf::TransformListener & listener,
01468 double waitForTransform)
01469 {
01470 UASSERT(leftImageMsg.get() && rightImageMsg.get());
01471
01472 if(!(leftImageMsg->encoding.compare(sensor_msgs::image_encodings::MONO8) == 0 ||
01473 leftImageMsg->encoding.compare(sensor_msgs::image_encodings::MONO16) == 0 ||
01474 leftImageMsg->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0 ||
01475 leftImageMsg->encoding.compare(sensor_msgs::image_encodings::RGB8) == 0 ||
01476 leftImageMsg->encoding.compare(sensor_msgs::image_encodings::BGRA8) == 0 ||
01477 leftImageMsg->encoding.compare(sensor_msgs::image_encodings::RGBA8) == 0) ||
01478 !(rightImageMsg->encoding.compare(sensor_msgs::image_encodings::MONO8) == 0 ||
01479 rightImageMsg->encoding.compare(sensor_msgs::image_encodings::MONO16) == 0 ||
01480 rightImageMsg->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0 ||
01481 rightImageMsg->encoding.compare(sensor_msgs::image_encodings::RGB8) == 0 ||
01482 rightImageMsg->encoding.compare(sensor_msgs::image_encodings::BGRA8) == 0 ||
01483 rightImageMsg->encoding.compare(sensor_msgs::image_encodings::RGBA8) == 0))
01484 {
01485 ROS_ERROR("Input type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8");
01486 ROS_ERROR("Input type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8 Current left=%s and right=%s",
01487 leftImageMsg->encoding.c_str(),
01488 rightImageMsg->encoding.c_str());
01489 return false;
01490 }
01491
01492 if(leftImageMsg->encoding.compare(sensor_msgs::image_encodings::MONO8) == 0 ||
01493 leftImageMsg->encoding.compare(sensor_msgs::image_encodings::MONO16) == 0)
01494 {
01495 left = cv_bridge::cvtColor(leftImageMsg, "mono8")->image;
01496 }
01497 else
01498 {
01499 left = cv_bridge::cvtColor(leftImageMsg, "bgr8")->image;
01500 }
01501 right = cv_bridge::cvtColor(rightImageMsg, "mono8")->image;
01502
01503 rtabmap::Transform localTransform = getTransform(frameId, leftImageMsg->header.frame_id, leftImageMsg->header.stamp, listener, waitForTransform);
01504 if(localTransform.isNull())
01505 {
01506 return false;
01507 }
01508
01509 if(!odomFrameId.empty() && odomStamp != leftImageMsg->header.stamp)
01510 {
01511 rtabmap::Transform sensorT = getTransform(
01512 frameId,
01513 odomFrameId,
01514 odomStamp,
01515 leftImageMsg->header.stamp,
01516 listener,
01517 waitForTransform);
01518 if(sensorT.isNull())
01519 {
01520 ROS_WARN("Could not get odometry value for stereo msg stamp (%fs). Latest odometry "
01521 "stamp is %fs. The stereo image pose will not be synchronized with odometry.", leftImageMsg->header.stamp.toSec(), odomStamp.toSec());
01522 }
01523 else
01524 {
01525 localTransform = sensorT * localTransform;
01526 }
01527 }
01528
01529 stereoModel = rtabmap_ros::stereoCameraModelFromROS(leftCamInfoMsg, rightCamInfoMsg, localTransform);
01530
01531 if(stereoModel.baseline() > 10.0)
01532 {
01533 static bool shown = false;
01534 if(!shown)
01535 {
01536 ROS_WARN("Detected baseline (%f m) is quite large! Is your "
01537 "right camera_info P(0,3) correctly set? Note that "
01538 "baseline=-P(0,3)/P(0,0). You may need to calibrate your camera. "
01539 "This warning is printed only once.",
01540 stereoModel.baseline());
01541 shown = true;
01542 }
01543 }
01544 return true;
01545 }
01546
01547 bool convertScanMsg(
01548 const sensor_msgs::LaserScanConstPtr& scan2dMsg,
01549 const std::string & frameId,
01550 const std::string & odomFrameId,
01551 const ros::Time & odomStamp,
01552 cv::Mat & scan,
01553 rtabmap::Transform & scanLocalTransform,
01554 tf::TransformListener & listener,
01555 double waitForTransform)
01556 {
01557
01558 rtabmap::Transform tmpT = getTransform(
01559 odomFrameId.empty()?frameId:odomFrameId,
01560 scan2dMsg->header.frame_id,
01561 scan2dMsg->header.stamp + ros::Duration().fromSec(scan2dMsg->ranges.size()*scan2dMsg->time_increment),
01562 listener,
01563 waitForTransform);
01564 if(tmpT.isNull())
01565 {
01566 return false;
01567 }
01568
01569 scanLocalTransform = getTransform(
01570 frameId,
01571 scan2dMsg->header.frame_id,
01572 scan2dMsg->header.stamp,
01573 listener,
01574 waitForTransform);
01575 if(scanLocalTransform.isNull())
01576 {
01577 return false;
01578 }
01579
01580
01581 sensor_msgs::PointCloud2 scanOut;
01582 laser_geometry::LaserProjection projection;
01583 projection.transformLaserScanToPointCloud(odomFrameId.empty()?frameId:odomFrameId, *scan2dMsg, scanOut, listener);
01584 pcl::PointCloud<pcl::PointXYZ>::Ptr pclScan(new pcl::PointCloud<pcl::PointXYZ>);
01585 pcl::fromROSMsg(scanOut, *pclScan);
01586 pclScan->is_dense = true;
01587
01588
01589 rtabmap::Transform laserToOdom = getTransform(
01590 scan2dMsg->header.frame_id,
01591 odomFrameId.empty()?frameId:odomFrameId,
01592 scan2dMsg->header.stamp,
01593 listener,
01594 waitForTransform);
01595 if(laserToOdom.isNull())
01596 {
01597 return false;
01598 }
01599
01600
01601 if(!odomFrameId.empty() && odomStamp != scan2dMsg->header.stamp)
01602 {
01603 rtabmap::Transform sensorT = getTransform(
01604 frameId,
01605 odomFrameId,
01606 odomStamp,
01607 scan2dMsg->header.stamp,
01608 listener,
01609 waitForTransform);
01610 if(sensorT.isNull())
01611 {
01612 ROS_WARN("Could not get odometry value for laser scan stamp (%fs). Latest odometry "
01613 "stamp is %fs. The laser scan pose will not be synchronized with odometry.", scan2dMsg->header.stamp.toSec(), odomStamp.toSec());
01614 }
01615 else
01616 {
01617
01618 scanLocalTransform = sensorT * scanLocalTransform;
01619 }
01620 }
01621
01622 scan = rtabmap::util3d::laserScan2dFromPointCloud(*pclScan, laserToOdom);
01623
01624 return true;
01625 }
01626
01627 bool convertScan3dMsg(
01628 const sensor_msgs::PointCloud2ConstPtr & scan3dMsg,
01629 const std::string & frameId,
01630 const std::string & odomFrameId,
01631 const ros::Time & odomStamp,
01632 cv::Mat & scan,
01633 rtabmap::Transform & scanLocalTransform,
01634 tf::TransformListener & listener,
01635 double waitForTransform)
01636 {
01637 bool containNormals = false;
01638 bool containColors = false;
01639 for(unsigned int i=0; i<scan3dMsg->fields.size(); ++i)
01640 {
01641 if(scan3dMsg->fields[i].name.compare("normal_x") == 0)
01642 {
01643 containNormals = true;
01644 }
01645 if(scan3dMsg->fields[i].name.compare("rgb") == 0 || scan3dMsg->fields[i].name.compare("rgba") == 0)
01646 {
01647 containColors = true;
01648 }
01649 }
01650
01651 scanLocalTransform = getTransform(frameId, scan3dMsg->header.frame_id, scan3dMsg->header.stamp, listener, waitForTransform);
01652 if(scanLocalTransform.isNull())
01653 {
01654 ROS_ERROR("TF of received scan cloud at time %fs is not set, aborting rtabmap update.", scan3dMsg->header.stamp.toSec());
01655 return false;
01656 }
01657
01658
01659 if(!odomFrameId.empty() && odomStamp != scan3dMsg->header.stamp)
01660 {
01661 rtabmap::Transform sensorT = getTransform(
01662 frameId,
01663 odomFrameId,
01664 odomStamp,
01665 scan3dMsg->header.stamp,
01666 listener,
01667 waitForTransform);
01668 if(sensorT.isNull())
01669 {
01670 ROS_WARN("Could not get odometry value for laser scan stamp (%fs). Latest odometry "
01671 "stamp is %fs. The 3d laser scan pose will not be synchronized with odometry.", scan3dMsg->header.stamp.toSec(), odomStamp.toSec());
01672 }
01673 else
01674 {
01675 scanLocalTransform = sensorT * scanLocalTransform;
01676 }
01677 }
01678
01679 if(containNormals)
01680 {
01681 if(containColors)
01682 {
01683 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr pclScan(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
01684 pcl::fromROSMsg(*scan3dMsg, *pclScan);
01685 if(!pclScan->is_dense)
01686 {
01687 pclScan = rtabmap::util3d::removeNaNNormalsFromPointCloud(pclScan);
01688 }
01689 scan = rtabmap::util3d::laserScanFromPointCloud(*pclScan);
01690 }
01691 else
01692 {
01693 pcl::PointCloud<pcl::PointNormal>::Ptr pclScan(new pcl::PointCloud<pcl::PointNormal>);
01694 pcl::fromROSMsg(*scan3dMsg, *pclScan);
01695 if(!pclScan->is_dense)
01696 {
01697 pclScan = rtabmap::util3d::removeNaNNormalsFromPointCloud(pclScan);
01698 }
01699 scan = rtabmap::util3d::laserScanFromPointCloud(*pclScan);
01700 }
01701 }
01702 else
01703 {
01704 if(containColors)
01705 {
01706 pcl::PointCloud<pcl::PointXYZRGB>::Ptr pclScan(new pcl::PointCloud<pcl::PointXYZRGB>);
01707 pcl::fromROSMsg(*scan3dMsg, *pclScan);
01708 if(!pclScan->is_dense)
01709 {
01710 pclScan = rtabmap::util3d::removeNaNFromPointCloud(pclScan);
01711 }
01712
01713 scan = rtabmap::util3d::laserScanFromPointCloud(*pclScan);
01714 }
01715 else
01716 {
01717 pcl::PointCloud<pcl::PointXYZ>::Ptr pclScan(new pcl::PointCloud<pcl::PointXYZ>);
01718 pcl::fromROSMsg(*scan3dMsg, *pclScan);
01719 if(!pclScan->is_dense)
01720 {
01721 pclScan = rtabmap::util3d::removeNaNFromPointCloud(pclScan);
01722 }
01723
01724 scan = rtabmap::util3d::laserScanFromPointCloud(*pclScan);
01725 }
01726 }
01727 return true;
01728 }
01729
01730 }