MsgConversion.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007     * Redistributions of source code must retain the above copyright
00008       notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright
00010       notice, this list of conditions and the following disclaimer in the
00011       documentation and/or other materials provided with the distribution.
00012     * Neither the name of the Universite de Sherbrooke nor the
00013       names of its contributors may be used to endorse or promote products
00014       derived from this software without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
00020 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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                 // make sure the quaternion is normalized
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                 // empty
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                 // empty
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                 // empty
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                 // empty
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 //depth
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                         // do nothing
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); // Extended
00381 
00382         // rtabmap_ros::Info
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         //Posterior, likelihood, childCount
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         // Statistics data
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         // Detailed info
00435         if(stats.extended())
00436         {
00437                 //Posterior, likelihood, childCount
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                 // Statistics data
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"; // fisheye
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         //optimized graph
00708         mapGraphFromROS(msg.graph, poses, links, mapToOdom);
00709 
00710         //Data
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         //Optimized graph
00724         mapGraphToROS(poses, links, mapToOdom, msg.graph);
00725 
00726         //Data
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         //optimized graph
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         //Optimized graph
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         //Features stuff...
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                 // stereo model
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                 // multi-cameras model
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         // add data
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         //Features stuff...
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         // add data
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); // use step for non-contiguous matrices
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         // TF ready?
01228         rtabmap::Transform transform;
01229         try
01230         {
01231                 if(waitForTransform > 0.0 && !stamp.isZero())
01232                 {
01233                         //if(!tfBuffer_.canTransform(fromFrameId, toFrameId, stamp, ros::Duration(1)))
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 // get moving transform accordingly to a fixed frame. For example get
01255 // transform between moving /base_link between two stamps accordingly to /odom frame.
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         // TF ready?
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                 // use depth's stamp so that geometry is sync to odom, use rgb frame as we assume depth is registered (normally depth msg should have same frame than rgb)
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                 // sync with odometry stamp
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                                 //ROS_WARN("RGBD correction = %s (time diff=%fs)", sensorT.prettyPrint().c_str(), fabs(stamp.toSec()-odomStamp.toSec()));
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                         // do nothing
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                 // initialize
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         // sync with odometry stamp
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         // make sure the frame of the laser is updated too
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         //transform in frameId_ frame
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         //transform back in laser frame
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         // sync with odometry stamp
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                         //ROS_WARN("scan correction = %s (time diff=%fs)", sensorT.prettyPrint().c_str(), fabs(scan2dMsg->header.stamp.toSec()-odomStamp.toSec()));
01618                         scanLocalTransform = sensorT * scanLocalTransform;
01619                 }
01620         }
01621 
01622         scan = rtabmap::util3d::laserScan2dFromPointCloud(*pclScan, laserToOdom); // put back in laser frame
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         // sync with odometry stamp
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 }


rtabmap_ros
Author(s): Mathieu Labbe
autogenerated on Thu Jun 6 2019 21:30:49