util3d.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/core/util3d.h>
00029 #include <rtabmap/core/util3d_transforms.h>
00030 #include <rtabmap/core/util3d_filtering.h>
00031 #include <rtabmap/core/util3d_surface.h>
00032 #include <rtabmap/core/util2d.h>
00033 #include <rtabmap/utilite/ULogger.h>
00034 #include <rtabmap/utilite/UMath.h>
00035 #include <rtabmap/utilite/UConversion.h>
00036 #include <rtabmap/utilite/UFile.h>
00037 #include <pcl/io/pcd_io.h>
00038 #include <pcl/io/ply_io.h>
00039 #include <pcl/common/transforms.h>
00040 #include <opencv2/imgproc/imgproc.hpp>
00041 
00042 namespace rtabmap
00043 {
00044 
00045 namespace util3d
00046 {
00047 
00048 cv::Mat bgrFromCloud(const pcl::PointCloud<pcl::PointXYZRGBA> & cloud, bool bgrOrder)
00049 {
00050         cv::Mat frameBGR = cv::Mat(cloud.height,cloud.width,CV_8UC3);
00051 
00052         for(unsigned int h = 0; h < cloud.height; h++)
00053         {
00054                 for(unsigned int w = 0; w < cloud.width; w++)
00055                 {
00056                         if(bgrOrder)
00057                         {
00058                                 frameBGR.at<cv::Vec3b>(h,w)[0] = cloud.at(h*cloud.width + w).b;
00059                                 frameBGR.at<cv::Vec3b>(h,w)[1] = cloud.at(h*cloud.width + w).g;
00060                                 frameBGR.at<cv::Vec3b>(h,w)[2] = cloud.at(h*cloud.width + w).r;
00061                         }
00062                         else
00063                         {
00064                                 frameBGR.at<cv::Vec3b>(h,w)[0] = cloud.at(h*cloud.width + w).r;
00065                                 frameBGR.at<cv::Vec3b>(h,w)[1] = cloud.at(h*cloud.width + w).g;
00066                                 frameBGR.at<cv::Vec3b>(h,w)[2] = cloud.at(h*cloud.width + w).b;
00067                         }
00068                 }
00069         }
00070         return frameBGR;
00071 }
00072 
00073 // return float image in meter
00074 cv::Mat depthFromCloud(
00075                 const pcl::PointCloud<pcl::PointXYZRGBA> & cloud,
00076                 float & fx,
00077                 float & fy,
00078                 bool depth16U)
00079 {
00080         cv::Mat frameDepth = cv::Mat(cloud.height,cloud.width,depth16U?CV_16UC1:CV_32FC1);
00081         fx = 0.0f; // needed to reconstruct the cloud
00082         fy = 0.0f; // needed to reconstruct the cloud
00083         for(unsigned int h = 0; h < cloud.height; h++)
00084         {
00085                 for(unsigned int w = 0; w < cloud.width; w++)
00086                 {
00087                         float depth = cloud.at(h*cloud.width + w).z;
00088                         if(depth16U)
00089                         {
00090                                 depth *= 1000.0f;
00091                                 unsigned short depthMM = 0;
00092                                 if(depth <= (float)USHRT_MAX)
00093                                 {
00094                                         depthMM = (unsigned short)depth;
00095                                 }
00096                                 frameDepth.at<unsigned short>(h,w) = depthMM;
00097                         }
00098                         else
00099                         {
00100                                 frameDepth.at<float>(h,w) = depth;
00101                         }
00102 
00103                         // update constants
00104                         if(fx == 0.0f &&
00105                            uIsFinite(cloud.at(h*cloud.width + w).x) &&
00106                            uIsFinite(depth) &&
00107                            w != cloud.width/2 &&
00108                            depth > 0)
00109                         {
00110                                 fx = cloud.at(h*cloud.width + w).x / ((float(w) - float(cloud.width)/2.0f) * depth);
00111                                 if(depth16U)
00112                                 {
00113                                         fx*=1000.0f;
00114                                 }
00115                         }
00116                         if(fy == 0.0f &&
00117                            uIsFinite(cloud.at(h*cloud.width + w).y) &&
00118                            uIsFinite(depth) &&
00119                            h != cloud.height/2 &&
00120                            depth > 0)
00121                         {
00122                                 fy = cloud.at(h*cloud.width + w).y / ((float(h) - float(cloud.height)/2.0f) * depth);
00123                                 if(depth16U)
00124                                 {
00125                                         fy*=1000.0f;
00126                                 }
00127                         }
00128                 }
00129         }
00130         return frameDepth;
00131 }
00132 
00133 // return (unsigned short 16bits image in mm) (float 32bits image in m)
00134 void rgbdFromCloud(const pcl::PointCloud<pcl::PointXYZRGBA> & cloud,
00135                 cv::Mat & frameBGR,
00136                 cv::Mat & frameDepth,
00137                 float & fx,
00138                 float & fy,
00139                 bool bgrOrder,
00140                 bool depth16U)
00141 {
00142         frameDepth = cv::Mat(cloud.height,cloud.width,depth16U?CV_16UC1:CV_32FC1);
00143         frameBGR = cv::Mat(cloud.height,cloud.width,CV_8UC3);
00144 
00145         fx = 0.0f; // needed to reconstruct the cloud
00146         fy = 0.0f; // needed to reconstruct the cloud
00147         for(unsigned int h = 0; h < cloud.height; h++)
00148         {
00149                 for(unsigned int w = 0; w < cloud.width; w++)
00150                 {
00151                         //rgb
00152                         if(bgrOrder)
00153                         {
00154                                 frameBGR.at<cv::Vec3b>(h,w)[0] = cloud.at(h*cloud.width + w).b;
00155                                 frameBGR.at<cv::Vec3b>(h,w)[1] = cloud.at(h*cloud.width + w).g;
00156                                 frameBGR.at<cv::Vec3b>(h,w)[2] = cloud.at(h*cloud.width + w).r;
00157                         }
00158                         else
00159                         {
00160                                 frameBGR.at<cv::Vec3b>(h,w)[0] = cloud.at(h*cloud.width + w).r;
00161                                 frameBGR.at<cv::Vec3b>(h,w)[1] = cloud.at(h*cloud.width + w).g;
00162                                 frameBGR.at<cv::Vec3b>(h,w)[2] = cloud.at(h*cloud.width + w).b;
00163                         }
00164 
00165                         //depth
00166                         float depth = cloud.at(h*cloud.width + w).z;
00167                         if(depth16U)
00168                         {
00169                                 depth *= 1000.0f;
00170                                 unsigned short depthMM = 0;
00171                                 if(depth <= (float)USHRT_MAX)
00172                                 {
00173                                         depthMM = (unsigned short)depth;
00174                                 }
00175                                 frameDepth.at<unsigned short>(h,w) = depthMM;
00176                         }
00177                         else
00178                         {
00179                                 frameDepth.at<float>(h,w) = depth;
00180                         }
00181 
00182                         // update constants
00183                         if(fx == 0.0f &&
00184                            uIsFinite(cloud.at(h*cloud.width + w).x) &&
00185                            uIsFinite(depth) &&
00186                            w != cloud.width/2 &&
00187                            depth > 0)
00188                         {
00189                                 fx = 1.0f/(cloud.at(h*cloud.width + w).x / ((float(w) - float(cloud.width)/2.0f) * depth));
00190                                 if(depth16U)
00191                                 {
00192                                         fx/=1000.0f;
00193                                 }
00194                         }
00195                         if(fy == 0.0f &&
00196                            uIsFinite(cloud.at(h*cloud.width + w).y) &&
00197                            uIsFinite(depth) &&
00198                            h != cloud.height/2 &&
00199                            depth > 0)
00200                         {
00201                                 fy = 1.0f/(cloud.at(h*cloud.width + w).y / ((float(h) - float(cloud.height)/2.0f) * depth));
00202                                 if(depth16U)
00203                                 {
00204                                         fy/=1000.0f;
00205                                 }
00206                         }
00207                 }
00208         }
00209 }
00210 
00211 pcl::PointXYZ projectDepthTo3D(
00212                 const cv::Mat & depthImage,
00213                 float x, float y,
00214                 float cx, float cy,
00215                 float fx, float fy,
00216                 bool smoothing,
00217                 float maxZError)
00218 {
00219         UASSERT(depthImage.type() == CV_16UC1 || depthImage.type() == CV_32FC1);
00220 
00221         pcl::PointXYZ pt;
00222 
00223         float depth = util2d::getDepth(depthImage, x, y, smoothing, maxZError);
00224         if(depth > 0.0f)
00225         {
00226                 // Use correct principal point from calibration
00227                 cx = cx > 0.0f ? cx : float(depthImage.cols/2) - 0.5f; //cameraInfo.K.at(2)
00228                 cy = cy > 0.0f ? cy : float(depthImage.rows/2) - 0.5f; //cameraInfo.K.at(5)
00229 
00230                 // Fill in XYZ
00231                 pt.x = (x - cx) * depth / fx;
00232                 pt.y = (y - cy) * depth / fy;
00233                 pt.z = depth;
00234         }
00235         else
00236         {
00237                 pt.x = pt.y = pt.z = std::numeric_limits<float>::quiet_NaN();
00238         }
00239         return pt;
00240 }
00241 
00242 pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFromDepth(
00243                 const cv::Mat & imageDepth,
00244                 float cx, float cy,
00245                 float fx, float fy,
00246                 int decimation,
00247                 float maxDepth,
00248                 float minDepth,
00249                 std::vector<int> * validIndices)
00250 {
00251         CameraModel model(fx, fy, cx, cy);
00252         return cloudFromDepth(imageDepth, model, decimation, maxDepth, minDepth, validIndices);
00253 }
00254 
00255 pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFromDepth(
00256                 const cv::Mat & imageDepth,
00257                 const CameraModel & model,
00258                 int decimation,
00259                 float maxDepth,
00260                 float minDepth,
00261                 std::vector<int> * validIndices)
00262 {
00263         float rgbToDepthFactorX = 1.0f;
00264         float rgbToDepthFactorY = 1.0f;
00265 
00266         UASSERT(model.isValidForProjection());
00267         UASSERT(!imageDepth.empty() && (imageDepth.type() == CV_16UC1 || imageDepth.type() == CV_32FC1));
00268 
00269         int imageRows = imageDepth.rows;
00270         int imageCols = imageDepth.cols;
00271 
00272         if(model.imageHeight()>0 && model.imageWidth()>0)
00273         {
00274                 UASSERT(model.imageHeight() % imageDepth.rows == 0 && model.imageWidth() % imageDepth.cols == 0);
00275                 UASSERT_MSG(model.imageHeight() % decimation == 0, uFormat("model.imageHeight()=%d decimation=%d", model.imageHeight(), decimation).c_str());
00276                 UASSERT_MSG(model.imageWidth() % decimation == 0, uFormat("model.imageWidth()=%d decimation=%d", model.imageWidth(), decimation).c_str());
00277                 rgbToDepthFactorX = 1.0f/float((model.imageWidth() / imageDepth.cols));
00278                 rgbToDepthFactorY = 1.0f/float((model.imageHeight() / imageDepth.rows));
00279                 imageRows = model.imageHeight();
00280                 imageCols = model.imageWidth();
00281         }
00282         else
00283         {
00284                 UASSERT_MSG(imageDepth.rows % decimation == 0, uFormat("rows=%d decimation=%d", imageDepth.rows, decimation).c_str());
00285                 UASSERT_MSG(imageDepth.cols % decimation == 0, uFormat("cols=%d decimation=%d", imageDepth.cols, decimation).c_str());
00286         }
00287 
00288         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
00289         if(decimation < 1)
00290         {
00291                 return cloud;
00292         }
00293 
00294         //cloud.header = cameraInfo.header;
00295         cloud->height = imageRows/decimation;
00296         cloud->width  = imageCols/decimation;
00297         cloud->is_dense = false;
00298         cloud->resize(cloud->height * cloud->width);
00299         if(validIndices)
00300         {
00301                 validIndices->resize(cloud->size());
00302         }
00303 
00304         float depthFx = model.fx() * rgbToDepthFactorX;
00305         float depthFy = model.fy() * rgbToDepthFactorY;
00306         float depthCx = model.cx() * rgbToDepthFactorX;
00307         float depthCy = model.cy() * rgbToDepthFactorY;
00308 
00309         UDEBUG("rgb=%dx%d depth=%dx%d fx=%f fy=%f cx=%f cy=%f (depth factors=%f %f) decimation=%d",
00310                         imageCols, imageRows,
00311                         imageDepth.cols, imageDepth.rows,
00312                         model.fx(), model.fy(), model.cx(), model.cy(),
00313                         rgbToDepthFactorX,
00314                         rgbToDepthFactorY,
00315                         decimation);
00316 
00317         int oi = 0;
00318         for(int h = 0; h < imageRows && h/decimation < (int)cloud->height; h+=decimation)
00319         {
00320                 for(int w = 0; w < imageCols && w/decimation < (int)cloud->width; w+=decimation)
00321                 {
00322                         pcl::PointXYZ & pt = cloud->at((h/decimation)*cloud->width + (w/decimation));
00323 
00324                         pcl::PointXYZ ptXYZ = projectDepthTo3D(imageDepth, w*rgbToDepthFactorX, h*rgbToDepthFactorY, depthCx, depthCy, depthFx, depthFy, false);
00325                         if(pcl::isFinite(ptXYZ) && ptXYZ.z>=minDepth && (maxDepth<=0.0f || ptXYZ.z <= maxDepth))
00326                         {
00327                                 pt.x = ptXYZ.x;
00328                                 pt.y = ptXYZ.y;
00329                                 pt.z = ptXYZ.z;
00330                                 if(validIndices)
00331                                 {
00332                                         validIndices->at(oi++) = (h/decimation)*cloud->width + (w/decimation);
00333                                 }
00334                         }
00335                         else
00336                         {
00337                                 pt.x = pt.y = pt.z = std::numeric_limits<float>::quiet_NaN();
00338                         }
00339                 }
00340         }
00341 
00342         if(validIndices)
00343         {
00344                 validIndices->resize(oi);
00345         }
00346 
00347         return cloud;
00348 }
00349 
00350 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFromDepthRGB(
00351                 const cv::Mat & imageRgb,
00352                 const cv::Mat & imageDepth,
00353                 float cx, float cy,
00354                 float fx, float fy,
00355                 int decimation,
00356                 float maxDepth,
00357                 float minDepth,
00358                 std::vector<int> * validIndices)
00359 {
00360         CameraModel model(fx, fy, cx, cy);
00361         return cloudFromDepthRGB(imageRgb, imageDepth, model, decimation, maxDepth, minDepth, validIndices);
00362 }
00363 
00364 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFromDepthRGB(
00365                 const cv::Mat & imageRgb,
00366                 const cv::Mat & imageDepth,
00367                 const CameraModel & model,
00368                 int decimation,
00369                 float maxDepth,
00370                 float minDepth,
00371                 std::vector<int> * validIndices)
00372 {
00373         UDEBUG("");
00374         UASSERT(model.isValidForProjection());
00375         UASSERT((model.imageHeight() == 0 && model.imageWidth() == 0) || (model.imageHeight() == imageRgb.rows && model.imageWidth() == imageRgb.cols));
00376         UASSERT(imageRgb.rows % imageDepth.rows == 0 && imageRgb.cols % imageDepth.cols == 0);
00377         UASSERT(!imageDepth.empty() && (imageDepth.type() == CV_16UC1 || imageDepth.type() == CV_32FC1));
00378         UASSERT_MSG(imageRgb.rows % decimation == 0, uFormat("imageDepth.rows=%d decimation=%d", imageRgb.rows, decimation).c_str());
00379         UASSERT_MSG(imageRgb.cols % decimation == 0, uFormat("imageDepth.cols=%d decimation=%d", imageRgb.cols, decimation).c_str());
00380 
00381         pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
00382         if(decimation < 1)
00383         {
00384                 return cloud;
00385         }
00386 
00387         bool mono;
00388         if(imageRgb.channels() == 3) // BGR
00389         {
00390                 mono = false;
00391         }
00392         else if(imageRgb.channels() == 1) // Mono
00393         {
00394                 mono = true;
00395         }
00396         else
00397         {
00398                 return cloud;
00399         }
00400 
00401         //cloud.header = cameraInfo.header;
00402         cloud->height = imageRgb.rows/decimation;
00403         cloud->width  = imageRgb.cols/decimation;
00404         cloud->is_dense = false;
00405         cloud->resize(cloud->height * cloud->width);
00406         if(validIndices)
00407         {
00408                 validIndices->resize(cloud->size());
00409         }
00410 
00411         float rgbToDepthFactorX = 1.0f/float((imageRgb.cols / imageDepth.cols));
00412         float rgbToDepthFactorY = 1.0f/float((imageRgb.rows / imageDepth.rows));
00413         float depthFx = model.fx() * rgbToDepthFactorX;
00414         float depthFy = model.fy() * rgbToDepthFactorY;
00415         float depthCx = model.cx() * rgbToDepthFactorX;
00416         float depthCy = model.cy() * rgbToDepthFactorY;
00417 
00418         UDEBUG("rgb=%dx%d depth=%dx%d fx=%f fy=%f cx=%f cy=%f (depth factors=%f %f) decimation=%d",
00419                         imageRgb.cols, imageRgb.rows,
00420                         imageDepth.cols, imageDepth.rows,
00421                         model.fx(), model.fy(), model.cx(), model.cy(),
00422                         rgbToDepthFactorX,
00423                         rgbToDepthFactorY,
00424                         decimation);
00425 
00426         int oi = 0;
00427         for(int h = 0; h < imageRgb.rows && h/decimation < (int)cloud->height; h+=decimation)
00428         {
00429                 for(int w = 0; w < imageRgb.cols && w/decimation < (int)cloud->width; w+=decimation)
00430                 {
00431                         pcl::PointXYZRGB & pt = cloud->at((h/decimation)*cloud->width + (w/decimation));
00432                         if(!mono)
00433                         {
00434                                 pt.b = imageRgb.at<cv::Vec3b>(h,w)[0];
00435                                 pt.g = imageRgb.at<cv::Vec3b>(h,w)[1];
00436                                 pt.r = imageRgb.at<cv::Vec3b>(h,w)[2];
00437                         }
00438                         else
00439                         {
00440                                 unsigned char v = imageRgb.at<unsigned char>(h,w);
00441                                 pt.b = v;
00442                                 pt.g = v;
00443                                 pt.r = v;
00444                         }
00445 
00446                         pcl::PointXYZ ptXYZ = projectDepthTo3D(imageDepth, w*rgbToDepthFactorX, h*rgbToDepthFactorY, depthCx, depthCy, depthFx, depthFy, false);
00447                         if(pcl::isFinite(ptXYZ) && ptXYZ.z>=minDepth && (maxDepth<=0.0f || ptXYZ.z <= maxDepth))
00448                         {
00449                                 pt.x = ptXYZ.x;
00450                                 pt.y = ptXYZ.y;
00451                                 pt.z = ptXYZ.z;
00452                                 if(validIndices)
00453                                 {
00454                                         validIndices->at(oi) = (h/decimation)*cloud->width + (w/decimation);
00455                                 }
00456                                 ++oi;
00457                         }
00458                         else
00459                         {
00460                                 pt.x = pt.y = pt.z = std::numeric_limits<float>::quiet_NaN();
00461                         }
00462                 }
00463         }
00464         if(validIndices)
00465         {
00466                 validIndices->resize(oi);
00467         }
00468         if(oi == 0)
00469         {
00470                 UWARN("Cloud with only NaN values created!");
00471         }
00472         UDEBUG("");
00473         return cloud;
00474 }
00475 
00476 pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFromDisparity(
00477                 const cv::Mat & imageDisparity,
00478                 const StereoCameraModel & model,
00479                 int decimation,
00480                 float maxDepth,
00481                 float minDepth,
00482                 std::vector<int> * validIndices)
00483 {
00484         UASSERT(imageDisparity.type() == CV_32FC1 || imageDisparity.type()==CV_16SC1);
00485         UASSERT(imageDisparity.rows % decimation == 0);
00486         UASSERT(imageDisparity.cols % decimation == 0);
00487         UASSERT(decimation >= 1);
00488 
00489         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
00490 
00491         //cloud.header = cameraInfo.header;
00492         cloud->height = imageDisparity.rows/decimation;
00493         cloud->width  = imageDisparity.cols/decimation;
00494         cloud->is_dense = false;
00495         cloud->resize(cloud->height * cloud->width);
00496         if(validIndices)
00497         {
00498                 validIndices->resize(cloud->size());
00499         }
00500 
00501         int oi = 0;
00502         if(imageDisparity.type()==CV_16SC1)
00503         {
00504                 for(int h = 0; h < imageDisparity.rows && h/decimation < (int)cloud->height; h+=decimation)
00505                 {
00506                         for(int w = 0; w < imageDisparity.cols && w/decimation < (int)cloud->width; w+=decimation)
00507                         {
00508                                 float disp = float(imageDisparity.at<short>(h,w))/16.0f;
00509                                 cv::Point3f pt = projectDisparityTo3D(cv::Point2f(w, h), disp, model);
00510                                 if(pt.z >= minDepth && (maxDepth <= 0.0f || pt.z <= maxDepth))
00511                                 {
00512                                         cloud->at((h/decimation)*cloud->width + (w/decimation)) = pcl::PointXYZ(pt.x, pt.y, pt.z);
00513                                         if(validIndices)
00514                                         {
00515                                                 validIndices->at(oi++) = (h/decimation)*cloud->width + (w/decimation);
00516                                         }
00517                                 }
00518                                 else
00519                                 {
00520                                         cloud->at((h/decimation)*cloud->width + (w/decimation)) = pcl::PointXYZ(
00521                                                         std::numeric_limits<float>::quiet_NaN(),
00522                                                         std::numeric_limits<float>::quiet_NaN(),
00523                                                         std::numeric_limits<float>::quiet_NaN());
00524                                 }
00525                         }
00526                 }
00527         }
00528         else
00529         {
00530                 for(int h = 0; h < imageDisparity.rows && h/decimation < (int)cloud->height; h+=decimation)
00531                 {
00532                         for(int w = 0; w < imageDisparity.cols && w/decimation < (int)cloud->width; w+=decimation)
00533                         {
00534                                 float disp = imageDisparity.at<float>(h,w);
00535                                 cv::Point3f pt = projectDisparityTo3D(cv::Point2f(w, h), disp, model);
00536                                 if(pt.z > minDepth && (maxDepth <= 0.0f || pt.z <= maxDepth))
00537                                 {
00538                                         cloud->at((h/decimation)*cloud->width + (w/decimation)) = pcl::PointXYZ(pt.x, pt.y, pt.z);
00539                                         if(validIndices)
00540                                         {
00541                                                 validIndices->at(oi++) = (h/decimation)*cloud->width + (w/decimation);
00542                                         }
00543                                 }
00544                                 else
00545                                 {
00546                                         cloud->at((h/decimation)*cloud->width + (w/decimation)) = pcl::PointXYZ(
00547                                                         std::numeric_limits<float>::quiet_NaN(),
00548                                                         std::numeric_limits<float>::quiet_NaN(),
00549                                                         std::numeric_limits<float>::quiet_NaN());
00550                                 }
00551                         }
00552                 }
00553         }
00554         if(validIndices)
00555         {
00556                 validIndices->resize(oi);
00557         }
00558         return cloud;
00559 }
00560 
00561 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFromDisparityRGB(
00562                 const cv::Mat & imageRgb,
00563                 const cv::Mat & imageDisparity,
00564                 const StereoCameraModel & model,
00565                 int decimation,
00566                 float maxDepth,
00567                 float minDepth,
00568                 std::vector<int> * validIndices)
00569 {
00570         UASSERT(!imageRgb.empty() && !imageDisparity.empty());
00571         UASSERT(imageRgb.rows == imageDisparity.rows &&
00572                         imageRgb.cols == imageDisparity.cols &&
00573                         (imageDisparity.type() == CV_32FC1 || imageDisparity.type()==CV_16SC1));
00574         UASSERT(imageRgb.channels() == 3 || imageRgb.channels() == 1);
00575         UASSERT(decimation >= 1);
00576         UASSERT(imageDisparity.rows % decimation == 0 && imageDisparity.cols % decimation == 0);
00577 
00578         pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
00579 
00580         bool mono;
00581         if(imageRgb.channels() == 3) // BGR
00582         {
00583                 mono = false;
00584         }
00585         else // Mono
00586         {
00587                 mono = true;
00588         }
00589 
00590         //cloud.header = cameraInfo.header;
00591         cloud->height = imageRgb.rows/decimation;
00592         cloud->width  = imageRgb.cols/decimation;
00593         cloud->is_dense = false;
00594         cloud->resize(cloud->height * cloud->width);
00595         if(validIndices)
00596         {
00597                 validIndices->resize(cloud->size());
00598         }
00599 
00600         int oi=0;
00601         for(int h = 0; h < imageRgb.rows && h/decimation < (int)cloud->height; h+=decimation)
00602         {
00603                 for(int w = 0; w < imageRgb.cols && w/decimation < (int)cloud->width; w+=decimation)
00604                 {
00605                         pcl::PointXYZRGB & pt = cloud->at((h/decimation)*cloud->width + (w/decimation));
00606                         if(!mono)
00607                         {
00608                                 pt.b = imageRgb.at<cv::Vec3b>(h,w)[0];
00609                                 pt.g = imageRgb.at<cv::Vec3b>(h,w)[1];
00610                                 pt.r = imageRgb.at<cv::Vec3b>(h,w)[2];
00611                         }
00612                         else
00613                         {
00614                                 unsigned char v = imageRgb.at<unsigned char>(h,w);
00615                                 pt.b = v;
00616                                 pt.g = v;
00617                                 pt.r = v;
00618                         }
00619 
00620                         float disp = imageDisparity.type()==CV_16SC1?float(imageDisparity.at<short>(h,w))/16.0f:imageDisparity.at<float>(h,w);
00621                         cv::Point3f ptXYZ = projectDisparityTo3D(cv::Point2f(w, h), disp, model);
00622                         if(util3d::isFinite(ptXYZ) && ptXYZ.z >= minDepth && (maxDepth<=0.0f || ptXYZ.z <= maxDepth))
00623                         {
00624                                 pt.x = ptXYZ.x;
00625                                 pt.y = ptXYZ.y;
00626                                 pt.z = ptXYZ.z;
00627                                 if(validIndices)
00628                                 {
00629                                         validIndices->at(oi++) = (h/decimation)*cloud->width + (w/decimation);
00630                                 }
00631                         }
00632                         else
00633                         {
00634                                 pt.x = pt.y = pt.z = std::numeric_limits<float>::quiet_NaN();
00635                         }
00636                 }
00637         }
00638         if(validIndices)
00639         {
00640                 validIndices->resize(oi);
00641         }
00642         return cloud;
00643 }
00644 
00645 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFromStereoImages(
00646                 const cv::Mat & imageLeft,
00647                 const cv::Mat & imageRight,
00648                 const StereoCameraModel & model,
00649                 int decimation,
00650                 float maxDepth,
00651                 float minDepth,
00652                 std::vector<int> * validIndices,
00653                 const ParametersMap & parameters)
00654 {
00655         UASSERT(!imageLeft.empty() && !imageRight.empty());
00656         UASSERT(imageRight.type() == CV_8UC1);
00657         UASSERT(imageLeft.channels() == 3 || imageLeft.channels() == 1);
00658         UASSERT(imageLeft.rows == imageRight.rows &&
00659                         imageLeft.cols == imageRight.cols);
00660         UASSERT(decimation >= 1);
00661 
00662         cv::Mat leftColor = imageLeft;
00663         cv::Mat rightMono = imageRight;
00664 
00665         StereoCameraModel modelDecimation = model;
00666 
00667         if(leftColor.rows % decimation != 0 ||
00668            leftColor.cols % decimation != 0)
00669         {
00670                 leftColor = util2d::decimate(leftColor, decimation);
00671                 rightMono = util2d::decimate(rightMono, decimation);
00672                 modelDecimation.scale(1/float(decimation));
00673                 decimation = 1;
00674         }
00675 
00676         cv::Mat leftMono;
00677         if(leftColor.channels() == 3)
00678         {
00679                 cv::cvtColor(leftColor, leftMono, CV_BGR2GRAY);
00680         }
00681         else
00682         {
00683                 leftMono = leftColor;
00684         }
00685 
00686         return cloudFromDisparityRGB(
00687                         leftColor,
00688                         util2d::disparityFromStereoImages(leftMono, rightMono, parameters),
00689                         modelDecimation,
00690                         decimation,
00691                         maxDepth,
00692                         minDepth,
00693                         validIndices);
00694 }
00695 
00696 pcl::PointCloud<pcl::PointXYZ>::Ptr RTABMAP_EXP cloudFromSensorData(
00697                 const SensorData & sensorData,
00698                 int decimation,
00699                 float maxDepth,
00700                 float minDepth,
00701                 std::vector<int> * validIndices,
00702                 const ParametersMap & parameters)
00703 {
00704         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
00705 
00706         if(!sensorData.depthRaw().empty() && sensorData.cameraModels().size())
00707         {
00708                 //depth
00709                 UASSERT(int((sensorData.depthRaw().cols/sensorData.cameraModels().size())*sensorData.cameraModels().size()) == sensorData.depthRaw().cols);
00710                 int subImageWidth = sensorData.depthRaw().cols/sensorData.cameraModels().size();
00711                 for(unsigned int i=0; i<sensorData.cameraModels().size(); ++i)
00712                 {
00713                         if(sensorData.cameraModels()[i].isValidForProjection())
00714                         {
00715                                 pcl::PointCloud<pcl::PointXYZ>::Ptr tmp = util3d::cloudFromDepth(
00716                                                 cv::Mat(sensorData.depthRaw(), cv::Rect(subImageWidth*i, 0, subImageWidth, sensorData.depthRaw().rows)),
00717                                                 sensorData.cameraModels()[i],
00718                                                 decimation,
00719                                                 maxDepth,
00720                                                 minDepth,
00721                                                 sensorData.cameraModels().size()==1?validIndices:0);
00722 
00723                                 if(tmp->size())
00724                                 {
00725                                         tmp = util3d::transformPointCloud(tmp, sensorData.cameraModels()[i].localTransform());
00726 
00727                                         if(sensorData.cameraModels().size() > 1)
00728                                         {
00729                                                 tmp = util3d::removeNaNFromPointCloud(tmp);
00730                                                 *cloud += *tmp;
00731                                         }
00732                                         else
00733                                         {
00734                                                 cloud = tmp;
00735                                         }
00736                                 }
00737                         }
00738                         else
00739                         {
00740                                 UERROR("Camera model %d is invalid", i);
00741                         }
00742                 }
00743 
00744                 if(cloud->is_dense && validIndices)
00745                 {
00746                         //generate indices for all points (they are all valid)
00747                         validIndices->resize(cloud->size());
00748                         for(unsigned int i=0; i<cloud->size(); ++i)
00749                         {
00750                                 validIndices->at(i) = i;
00751                         }
00752                 }
00753         }
00754         else if(!sensorData.imageRaw().empty() && !sensorData.rightRaw().empty() && sensorData.stereoCameraModel().isValidForProjection())
00755         {
00756                 //stereo
00757                 UASSERT(sensorData.rightRaw().type() == CV_8UC1);
00758 
00759                 cv::Mat leftMono;
00760                 if(sensorData.imageRaw().channels() == 3)
00761                 {
00762                         cv::cvtColor(sensorData.imageRaw(), leftMono, CV_BGR2GRAY);
00763                 }
00764                 else
00765                 {
00766                         leftMono = sensorData.imageRaw();
00767                 }
00768                 cloud = cloudFromDisparity(
00769                                 util2d::disparityFromStereoImages(leftMono, sensorData.rightRaw(), parameters),
00770                                 sensorData.stereoCameraModel(),
00771                                 decimation,
00772                                 maxDepth,
00773                                 minDepth,
00774                                 validIndices);
00775 
00776                 if(cloud->size())
00777                 {
00778                         if(cloud->size())
00779                         {
00780                                 cloud = util3d::transformPointCloud(cloud, sensorData.stereoCameraModel().left().localTransform());
00781                         }
00782                 }
00783         }
00784         return cloud;
00785 }
00786 
00787 pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP cloudRGBFromSensorData(
00788                 const SensorData & sensorData,
00789                 int decimation,
00790                 float maxDepth,
00791                 float minDepth,
00792                 std::vector<int> * validIndices,
00793                 const ParametersMap & parameters)
00794 {
00795         UASSERT(!sensorData.imageRaw().empty());
00796         UASSERT((!sensorData.depthRaw().empty() && sensorData.cameraModels().size()) ||
00797                         (!sensorData.rightRaw().empty() && sensorData.stereoCameraModel().isValidForProjection()));
00798         pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
00799 
00800         if(!sensorData.depthRaw().empty() && sensorData.cameraModels().size())
00801         {
00802                 //depth
00803                 UDEBUG("");
00804                 UASSERT(int((sensorData.imageRaw().cols/sensorData.cameraModels().size())*sensorData.cameraModels().size()) == sensorData.imageRaw().cols);
00805                 UASSERT(int((sensorData.depthRaw().cols/sensorData.cameraModels().size())*sensorData.cameraModels().size()) == sensorData.depthRaw().cols);
00806                 UASSERT(sensorData.imageRaw().cols % sensorData.depthRaw().cols == 0);
00807                 UASSERT(sensorData.imageRaw().rows % sensorData.depthRaw().rows == 0);
00808                 int subRGBWidth = sensorData.imageRaw().cols/sensorData.cameraModels().size();
00809                 int subDepthWidth = sensorData.depthRaw().cols/sensorData.cameraModels().size();
00810 
00811                 if(subRGBWidth % decimation != 0 || subDepthWidth % decimation != 0)
00812                 {
00813                         UWARN("Image size (rgb=%d,%d depth=%d,%d) modulus decimation (%d) is not null "
00814                                   "for the cloud creation! Setting decimation to 1...",
00815                                   subRGBWidth, sensorData.imageRaw().rows,
00816                                   subDepthWidth, sensorData.depthRaw().rows,
00817                                   decimation);
00818                         decimation = 1;
00819                 }
00820 
00821                 for(unsigned int i=0; i<sensorData.cameraModels().size(); ++i)
00822                 {
00823                         if(sensorData.cameraModels()[i].isValidForProjection())
00824                         {
00825                                 pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmp = util3d::cloudFromDepthRGB(
00826                                                 cv::Mat(sensorData.imageRaw(), cv::Rect(subRGBWidth*i, 0, subRGBWidth, sensorData.imageRaw().rows)),
00827                                                 cv::Mat(sensorData.depthRaw(), cv::Rect(subDepthWidth*i, 0, subDepthWidth, sensorData.depthRaw().rows)),
00828                                                 sensorData.cameraModels()[i],
00829                                                 decimation,
00830                                                 maxDepth,
00831                                                 minDepth,
00832                                                 sensorData.cameraModels().size() == 1?validIndices:0);
00833 
00834                                 if(tmp->size())
00835                                 {
00836                                         tmp = util3d::transformPointCloud(tmp, sensorData.cameraModels()[i].localTransform());
00837 
00838                                         if(sensorData.cameraModels().size() > 1)
00839                                         {
00840                                                 tmp = util3d::removeNaNFromPointCloud(tmp);
00841                                                 *cloud += *tmp;
00842                                         }
00843                                         else
00844                                         {
00845                                                 cloud = tmp;
00846                                         }
00847                                 }
00848                         }
00849                         else
00850                         {
00851                                 UERROR("Camera model %d is invalid", i);
00852                         }
00853                 }
00854 
00855                 if(cloud->is_dense && validIndices)
00856                 {
00857                         //generate indices for all points (they are all valid)
00858                         validIndices->resize(cloud->size());
00859                         for(unsigned int i=0; i<cloud->size(); ++i)
00860                         {
00861                                 validIndices->at(i) = i;
00862                         }
00863                 }
00864         }
00865         else if(!sensorData.rightRaw().empty() && sensorData.stereoCameraModel().isValidForProjection())
00866         {
00867                 //stereo
00868                 UDEBUG("");
00869                 cloud = cloudFromStereoImages(sensorData.imageRaw(),
00870                                 sensorData.rightRaw(),
00871                                 sensorData.stereoCameraModel(),
00872                                 decimation,
00873                                 maxDepth,
00874                                 minDepth,
00875                                 validIndices,
00876                                 parameters);
00877 
00878                 if(cloud->size())
00879                 {
00880                         cloud = util3d::transformPointCloud(cloud, sensorData.stereoCameraModel().left().localTransform());
00881                 }
00882         }
00883         return cloud;
00884 }
00885 
00886 pcl::PointCloud<pcl::PointXYZ> laserScanFromDepthImage(
00887                                         const cv::Mat & depthImage,
00888                                         float fx,
00889                                         float fy,
00890                                         float cx,
00891                                         float cy,
00892                                         float maxDepth,
00893                                         float minDepth,
00894                                         const Transform & localTransform)
00895 {
00896         UASSERT(depthImage.type() == CV_16UC1 || depthImage.type() == CV_32FC1);
00897         UASSERT(!localTransform.isNull());
00898 
00899         pcl::PointCloud<pcl::PointXYZ> scan;
00900         int middle = depthImage.rows/2;
00901         if(middle)
00902         {
00903                 scan.resize(depthImage.cols);
00904                 int oi = 0;
00905                 for(int i=0; i<depthImage.cols; ++i)
00906                 {
00907                         pcl::PointXYZ pt = util3d::projectDepthTo3D(depthImage, i, middle, cx, cy, fx, fy, false);
00908                         if(pcl::isFinite(pt) && pt.z >= minDepth && (maxDepth == 0 || pt.z < maxDepth))
00909                         {
00910                                 if(!localTransform.isIdentity())
00911                                 {
00912                                         pt = util3d::transformPoint(pt, localTransform);
00913                                 }
00914                                 scan[oi++] = pt;
00915                         }
00916                 }
00917                 scan.resize(oi);
00918         }
00919         return scan;
00920 }
00921 
00922 cv::Mat laserScanFromPointCloud(const pcl::PointCloud<pcl::PointXYZ> & cloud, const Transform & transform)
00923 {
00924         cv::Mat laserScan(1, (int)cloud.size(), CV_32FC3);
00925         bool nullTransform = transform.isNull() || transform.isIdentity();
00926         Eigen::Affine3f transform3f = transform.toEigen3f();
00927         for(unsigned int i=0; i<cloud.size(); ++i)
00928         {
00929                 if(!nullTransform)
00930                 {
00931                         pcl::PointXYZ pt = pcl::transformPoint(cloud.at(i), transform3f);
00932                         laserScan.at<cv::Vec3f>(i)[0] = pt.x;
00933                         laserScan.at<cv::Vec3f>(i)[1] = pt.y;
00934                         laserScan.at<cv::Vec3f>(i)[2] = pt.z;
00935                 }
00936                 else
00937                 {
00938                         laserScan.at<cv::Vec3f>(i)[0] = cloud.at(i).x;
00939                         laserScan.at<cv::Vec3f>(i)[1] = cloud.at(i).y;
00940                         laserScan.at<cv::Vec3f>(i)[2] = cloud.at(i).z;
00941                 }
00942 
00943         }
00944         return laserScan;
00945 }
00946 
00947 cv::Mat laserScanFromPointCloud(const pcl::PointCloud<pcl::PointNormal> & cloud, const Transform & transform)
00948 {
00949         cv::Mat laserScan(1, (int)cloud.size(), CV_32FC(6));
00950         bool nullTransform = transform.isNull() || transform.isIdentity();
00951         Eigen::Affine3f transform3f = transform.toEigen3f();
00952         for(unsigned int i=0; i<cloud.size(); ++i)
00953         {
00954                 if(!nullTransform)
00955                 {
00956                         pcl::PointNormal pt = pcl::transformPoint(cloud.at(i), transform3f);
00957                         laserScan.at<cv::Vec6f>(i)[0] = pt.x;
00958                         laserScan.at<cv::Vec6f>(i)[1] = pt.y;
00959                         laserScan.at<cv::Vec6f>(i)[2] = pt.z;
00960                         laserScan.at<cv::Vec6f>(i)[3] = pt.normal_x;
00961                         laserScan.at<cv::Vec6f>(i)[4] = pt.normal_y;
00962                         laserScan.at<cv::Vec6f>(i)[5] = pt.normal_z;
00963                 }
00964                 else
00965                 {
00966                         laserScan.at<cv::Vec6f>(i)[0] = cloud.at(i).x;
00967                         laserScan.at<cv::Vec6f>(i)[1] = cloud.at(i).y;
00968                         laserScan.at<cv::Vec6f>(i)[2] = cloud.at(i).z;
00969                         laserScan.at<cv::Vec6f>(i)[3] = cloud.at(i).normal_x;
00970                         laserScan.at<cv::Vec6f>(i)[4] = cloud.at(i).normal_y;
00971                         laserScan.at<cv::Vec6f>(i)[5] = cloud.at(i).normal_z;
00972                 }
00973         }
00974         return laserScan;
00975 }
00976 
00977 cv::Mat laserScan2dFromPointCloud(const pcl::PointCloud<pcl::PointXYZ> & cloud, const Transform & transform)
00978 {
00979         cv::Mat laserScan(1, (int)cloud.size(), CV_32FC2);
00980         bool nullTransform = transform.isNull();
00981         Eigen::Affine3f transform3f = transform.toEigen3f();
00982         for(unsigned int i=0; i<cloud.size(); ++i)
00983         {
00984                 if(!nullTransform)
00985                 {
00986                         pcl::PointXYZ pt = pcl::transformPoint(cloud.at(i), transform3f);
00987                         laserScan.at<cv::Vec2f>(i)[0] = pt.x;
00988                         laserScan.at<cv::Vec2f>(i)[1] = pt.y;
00989                 }
00990                 else
00991                 {
00992                         laserScan.at<cv::Vec2f>(i)[0] = cloud.at(i).x;
00993                         laserScan.at<cv::Vec2f>(i)[1] = cloud.at(i).y;
00994                 }
00995 
00996         }
00997         return laserScan;
00998 }
00999 
01000 pcl::PointCloud<pcl::PointXYZ>::Ptr laserScanToPointCloud(const cv::Mat & laserScan, const Transform & transform)
01001 {
01002         UASSERT(laserScan.empty() || laserScan.type() == CV_32FC2 || laserScan.type() == CV_32FC3 || laserScan.type() == CV_32FC(6));
01003 
01004         pcl::PointCloud<pcl::PointXYZ>::Ptr output(new pcl::PointCloud<pcl::PointXYZ>);
01005         output->resize(laserScan.cols);
01006         bool nullTransform = transform.isNull();
01007         Eigen::Affine3f transform3f = transform.toEigen3f();
01008         for(int i=0; i<laserScan.cols; ++i)
01009         {
01010                 if(laserScan.type() == CV_32FC2)
01011                 {
01012                         output->at(i).x = laserScan.at<cv::Vec2f>(i)[0];
01013                         output->at(i).y = laserScan.at<cv::Vec2f>(i)[1];
01014                 }
01015                 else if(laserScan.type() == CV_32FC3)
01016                 {
01017                         output->at(i).x = laserScan.at<cv::Vec3f>(i)[0];
01018                         output->at(i).y = laserScan.at<cv::Vec3f>(i)[1];
01019                         output->at(i).z = laserScan.at<cv::Vec3f>(i)[2];
01020                 }
01021                 else
01022                 {
01023                         output->at(i).x = laserScan.at<cv::Vec6f>(i)[0];
01024                         output->at(i).y = laserScan.at<cv::Vec6f>(i)[1];
01025                         output->at(i).z = laserScan.at<cv::Vec6f>(i)[2];
01026                 }
01027 
01028                 if(!nullTransform)
01029                 {
01030                         output->at(i) = pcl::transformPoint(output->at(i), transform3f);
01031                 }
01032         }
01033         return output;
01034 }
01035 
01036 pcl::PointCloud<pcl::PointNormal>::Ptr laserScanToPointCloudNormal(const cv::Mat & laserScan, const Transform & transform)
01037 {
01038         UASSERT(laserScan.empty() || laserScan.type() == CV_32FC2 || laserScan.type() == CV_32FC3 || laserScan.type() == CV_32FC(6));
01039 
01040         pcl::PointCloud<pcl::PointNormal>::Ptr output(new pcl::PointCloud<pcl::PointNormal>);
01041         output->resize(laserScan.cols);
01042         bool nullTransform = transform.isNull();
01043         for(int i=0; i<laserScan.cols; ++i)
01044         {
01045                 if(laserScan.type() == CV_32FC2)
01046                 {
01047                         output->at(i).x = laserScan.at<cv::Vec2f>(i)[0];
01048                         output->at(i).y = laserScan.at<cv::Vec2f>(i)[1];
01049                 }
01050                 else if(laserScan.type() == CV_32FC3)
01051                 {
01052                         output->at(i).x = laserScan.at<cv::Vec3f>(i)[0];
01053                         output->at(i).y = laserScan.at<cv::Vec3f>(i)[1];
01054                         output->at(i).z = laserScan.at<cv::Vec3f>(i)[2];
01055                 }
01056                 else
01057                 {
01058                         output->at(i).x = laserScan.at<cv::Vec6f>(i)[0];
01059                         output->at(i).y = laserScan.at<cv::Vec6f>(i)[1];
01060                         output->at(i).z = laserScan.at<cv::Vec6f>(i)[2];
01061                         output->at(i).normal_x = laserScan.at<cv::Vec6f>(i)[3];
01062                         output->at(i).normal_y = laserScan.at<cv::Vec6f>(i)[4];
01063                         output->at(i).normal_z = laserScan.at<cv::Vec6f>(i)[5];
01064                 }
01065 
01066                 if(!nullTransform)
01067                 {
01068                         output->at(i) = util3d::transformPoint(output->at(i), transform);
01069                 }
01070         }
01071         return output;
01072 }
01073 
01074 // inspired from ROS image_geometry/src/stereo_camera_model.cpp
01075 cv::Point3f projectDisparityTo3D(
01076                 const cv::Point2f & pt,
01077                 float disparity,
01078                 const StereoCameraModel & model)
01079 {
01080         if(disparity > 0.0f && model.baseline() > 0.0f && model.left().fx() > 0.0f)
01081         {
01082                 //Z = baseline * f / (d + cx1-cx0);
01083                 float c = 0.0f;
01084                 if(model.right().cx()>0.0f && model.left().cx()>0.0f)
01085                 {
01086                         c = model.right().cx() - model.left().cx();
01087                 }
01088                 float W = model.baseline()/(disparity + c);
01089                 return cv::Point3f((pt.x - model.left().cx())*W, (pt.y - model.left().cy())*W, model.left().fx()*W);
01090         }
01091         float bad_point = std::numeric_limits<float>::quiet_NaN ();
01092         return cv::Point3f(bad_point, bad_point, bad_point);
01093 }
01094 
01095 cv::Point3f projectDisparityTo3D(
01096                 const cv::Point2f & pt,
01097                 const cv::Mat & disparity,
01098                 const StereoCameraModel & model)
01099 {
01100         UASSERT(!disparity.empty() && (disparity.type() == CV_32FC1 || disparity.type() == CV_16SC1));
01101         int u = int(pt.x+0.5f);
01102         int v = int(pt.y+0.5f);
01103         float bad_point = std::numeric_limits<float>::quiet_NaN ();
01104         if(uIsInBounds(u, 0, disparity.cols) &&
01105            uIsInBounds(v, 0, disparity.rows))
01106         {
01107                 float d = disparity.type() == CV_16SC1?float(disparity.at<short>(v,u))/16.0f:disparity.at<float>(v,u);
01108                 return projectDisparityTo3D(pt, d, model);
01109         }
01110         return cv::Point3f(bad_point, bad_point, bad_point);
01111 }
01112 
01113 // Register point cloud to camera (return registered depth image)
01114 cv::Mat projectCloudToCamera(
01115                 const cv::Size & imageSize,
01116                 const cv::Mat & cameraMatrixK, // /base_link -> /camera_link
01117                 const cv::Mat & laserScan,     // assuming laser scan points are already in /base_link coordinate
01118                 const rtabmap::Transform & cameraTransform)
01119 {
01120         UASSERT(!cameraTransform.isNull());
01121         UASSERT(!laserScan.empty());
01122         UASSERT(laserScan.type() == CV_32FC2 || laserScan.type() == CV_32FC3 || laserScan.type() == CV_32FC(6));
01123         UASSERT(cameraMatrixK.type() == CV_64FC1 && cameraMatrixK.cols == 3 && cameraMatrixK.cols == 3);
01124 
01125         float fx = cameraMatrixK.at<double>(0,0);
01126         float fy = cameraMatrixK.at<double>(1,1);
01127         float cx = cameraMatrixK.at<double>(0,2);
01128         float cy = cameraMatrixK.at<double>(1,2);
01129 
01130         cv::Mat registered = cv::Mat::zeros(imageSize, CV_32FC1);
01131         Transform t = cameraTransform.inverse();
01132 
01133         int count = 0;
01134         for(int i=0; i<laserScan.cols; ++i)
01135         {
01136                 // Get 3D from laser scan
01137                 cv::Point3f ptScan;
01138                 if(laserScan.type() == CV_32FC2)
01139                 {
01140                         ptScan.x = laserScan.at<cv::Vec2f>(i)[0];
01141                         ptScan.y = laserScan.at<cv::Vec2f>(i)[1];
01142                         ptScan.z = 0;
01143                 }
01144                 else if(laserScan.type() == CV_32FC3)
01145                 {
01146                         ptScan.x = laserScan.at<cv::Vec3f>(i)[0];
01147                         ptScan.y = laserScan.at<cv::Vec3f>(i)[1];
01148                         ptScan.z = laserScan.at<cv::Vec3f>(i)[2];
01149                 }
01150                 else
01151                 {
01152                         ptScan.x = laserScan.at<cv::Vec6f>(i)[0];
01153                         ptScan.y = laserScan.at<cv::Vec6f>(i)[1];
01154                         ptScan.z = laserScan.at<cv::Vec6f>(i)[2];
01155                 }
01156                 ptScan = util3d::transformPoint(ptScan, t);
01157 
01158                 // re-project in camera frame
01159                 float z = ptScan.z;
01160                 float invZ = 1.0f/z;
01161                 int dx = (fx*ptScan.x)*invZ + cx;
01162                 int dy = (fy*ptScan.y)*invZ + cy;
01163 
01164                 if(z > 0.0f && uIsInBounds(dx, 0, registered.cols) && uIsInBounds(dy, 0, registered.rows))
01165                 {
01166                         ++count;
01167                         float &zReg = registered.at<float>(dy, dx);
01168                         if(zReg == 0 || z < zReg)
01169                         {
01170                                 zReg = z;
01171                         }
01172                 }
01173         }
01174         UDEBUG("Points in camera=%d/%d", count, laserScan.cols);
01175 
01176         return registered;
01177 }
01178 
01179 cv::Mat projectCloudToCamera(
01180                 const cv::Size & imageSize,
01181                 const cv::Mat & cameraMatrixK, // /base_link -> /camera_link
01182                 const pcl::PointCloud<pcl::PointXYZ>::Ptr laserScan,  // assuming points are already in /base_link coordinate
01183                 const rtabmap::Transform & cameraTransform)
01184 {
01185         UASSERT(!cameraTransform.isNull());
01186         UASSERT(!laserScan->empty());
01187         UASSERT(cameraMatrixK.type() == CV_64FC1 && cameraMatrixK.cols == 3 && cameraMatrixK.cols == 3);
01188 
01189         float fx = cameraMatrixK.at<double>(0,0);
01190         float fy = cameraMatrixK.at<double>(1,1);
01191         float cx = cameraMatrixK.at<double>(0,2);
01192         float cy = cameraMatrixK.at<double>(1,2);
01193 
01194         cv::Mat registered = cv::Mat::zeros(imageSize, CV_32FC1);
01195         Transform t = cameraTransform.inverse();
01196 
01197         int count = 0;
01198         for(int i=0; i<(int)laserScan->size(); ++i)
01199         {
01200                 // Get 3D from laser scan
01201                 pcl::PointXYZ ptScan = laserScan->at(i);
01202                 ptScan = util3d::transformPoint(ptScan, t);
01203 
01204                 // re-project in camera frame
01205                 float z = ptScan.z;
01206                 float invZ = 1.0f/z;
01207                 int dx = (fx*ptScan.x)*invZ + cx;
01208                 int dy = (fy*ptScan.y)*invZ + cy;
01209 
01210                 if(z > 0.0f && uIsInBounds(dx, 0, registered.cols) && uIsInBounds(dy, 0, registered.rows))
01211                 {
01212                         ++count;
01213                         float &zReg = registered.at<float>(dy, dx);
01214                         if(zReg == 0 || z < zReg)
01215                         {
01216                                 zReg = z;
01217                         }
01218                 }
01219         }
01220         UDEBUG("Points in camera=%d/%d", count, (int)laserScan->size());
01221 
01222         return registered;
01223 }
01224 
01225 void fillProjectedCloudHoles(cv::Mat & registeredDepth, bool verticalDirection, bool fillToBorder)
01226 {
01227         UASSERT(registeredDepth.type() == CV_32FC1);
01228         if(verticalDirection)
01229         {
01230                 // vertical, for each column
01231                 for(int x=0; x<registeredDepth.cols; ++x)
01232                 {
01233                         float valueA = 0.0f;
01234                         int indexA = -1;
01235                         for(int y=0; y<registeredDepth.rows; ++y)
01236                         {
01237                                 float v = registeredDepth.at<float>(y,x);
01238                                 if(fillToBorder && y == registeredDepth.rows-1 && v<=0.0f && indexA>=0)
01239                                 {
01240                                         v = valueA;
01241                                 }
01242                                 if(v > 0.0f)
01243                                 {
01244                                         if(fillToBorder && indexA < 0)
01245                                         {
01246                                                 indexA = 0;
01247                                                 valueA = v;
01248                                         }
01249                                         if(indexA >=0)
01250                                         {
01251                                                 int range = y-indexA;
01252                                                 if(range > 1)
01253                                                 {
01254                                                         float slope = (v-valueA)/(range);
01255                                                         for(int k=1; k<range; ++k)
01256                                                         {
01257                                                                 registeredDepth.at<float>(indexA+k,x) = valueA+slope*float(k);
01258                                                         }
01259                                                 }
01260                                         }
01261                                         valueA = v;
01262                                         indexA = y;
01263                                 }
01264                         }
01265                 }
01266         }
01267         else
01268         {
01269                 // horizontal, for each row
01270                 for(int y=0; y<registeredDepth.rows; ++y)
01271                 {
01272                         float valueA = 0.0f;
01273                         int indexA = -1;
01274                         for(int x=0; x<registeredDepth.cols; ++x)
01275                         {
01276                                 float v = registeredDepth.at<float>(y,x);
01277                                 if(fillToBorder && x == registeredDepth.cols-1 && v<=0.0f && indexA>=0)
01278                                 {
01279                                         v = valueA;
01280                                 }
01281                                 if(v > 0.0f)
01282                                 {
01283                                         if(fillToBorder && indexA < 0)
01284                                         {
01285                                                 indexA = 0;
01286                                                 valueA = v;
01287                                         }
01288                                         if(indexA >=0)
01289                                         {
01290                                                 int range = x-indexA;
01291                                                 if(range > 1)
01292                                                 {
01293                                                         float slope = (v-valueA)/(range);
01294                                                         for(int k=1; k<range; ++k)
01295                                                         {
01296                                                                 registeredDepth.at<float>(y,indexA+k) = valueA+slope*float(k);
01297                                                         }
01298                                                 }
01299                                         }
01300                                         valueA = v;
01301                                         indexA = x;
01302                                 }
01303                         }
01304                 }
01305         }
01306 }
01307 
01308 bool isFinite(const cv::Point3f & pt)
01309 {
01310         return uIsFinite(pt.x) && uIsFinite(pt.y) && uIsFinite(pt.z);
01311 }
01312 
01313 pcl::PointCloud<pcl::PointXYZ>::Ptr concatenateClouds(const std::list<pcl::PointCloud<pcl::PointXYZ>::Ptr> & clouds)
01314 {
01315         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
01316         for(std::list<pcl::PointCloud<pcl::PointXYZ>::Ptr>::const_iterator iter = clouds.begin(); iter!=clouds.end(); ++iter)
01317         {
01318                 *cloud += *(*iter);
01319         }
01320         return cloud;
01321 }
01322 
01323 pcl::PointCloud<pcl::PointXYZRGB>::Ptr concatenateClouds(const std::list<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> & clouds)
01324 {
01325         pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
01326         for(std::list<pcl::PointCloud<pcl::PointXYZRGB>::Ptr>::const_iterator iter = clouds.begin(); iter!=clouds.end(); ++iter)
01327         {
01328                 *cloud+=*(*iter);
01329         }
01330         return cloud;
01331 }
01332 
01333 pcl::TextureMesh::Ptr concatenateTextureMeshes(const std::list<pcl::TextureMesh::Ptr> & meshes)
01334 {
01335         pcl::TextureMesh::Ptr output(new pcl::TextureMesh);
01336         std::map<std::string, int> addedMaterials; //<file, index>
01337         for(std::list<pcl::TextureMesh::Ptr>::const_iterator iter = meshes.begin(); iter!=meshes.end(); ++iter)
01338         {
01339                 // append point cloud
01340                 int polygonStep = output->cloud.height * output->cloud.width;
01341                 pcl::PCLPointCloud2 tmp;
01342                 pcl::concatenatePointCloud(output->cloud, iter->get()->cloud, tmp);
01343                 output->cloud = tmp;
01344 
01345                 UASSERT((*iter)->tex_polygons.size() == (*iter)->tex_coordinates.size() &&
01346                                 (*iter)->tex_polygons.size() == (*iter)->tex_materials.size());
01347 
01348                 int materialCount = (*iter)->tex_polygons.size();
01349                 for(int i=0; i<materialCount; ++i)
01350                 {
01351                         std::map<std::string, int>::iterator jter = addedMaterials.find((*iter)->tex_materials[i].tex_file);
01352                         int index;
01353                         if(jter != addedMaterials.end())
01354                         {
01355                                 index = jter->second;
01356                         }
01357                         else
01358                         {
01359                                 addedMaterials.insert(std::make_pair((*iter)->tex_materials[i].tex_file, output->tex_materials.size()));
01360                                 index = output->tex_materials.size();
01361                                 output->tex_materials.push_back((*iter)->tex_materials[i]);
01362                                 output->tex_materials.back().tex_name = uFormat("material_%d", index);
01363                                 output->tex_polygons.resize(output->tex_polygons.size() + 1);
01364                                 output->tex_coordinates.resize(output->tex_coordinates.size() + 1);
01365                         }
01366 
01367                         // update and append polygon indices
01368                         int oi = output->tex_polygons[index].size();
01369                         output->tex_polygons[index].resize(output->tex_polygons[index].size() + (*iter)->tex_polygons[i].size());
01370                         for(unsigned int j=0; j<(*iter)->tex_polygons[i].size(); ++j)
01371                         {
01372                                 pcl::Vertices polygon = (*iter)->tex_polygons[i][j];
01373                                 for(unsigned int k=0; k<polygon.vertices.size(); ++k)
01374                                 {
01375                                         polygon.vertices[k] += polygonStep;
01376                                 }
01377                                 output->tex_polygons[index][oi+j] = polygon;
01378                         }
01379 
01380                         // append uv coordinates
01381                         oi = output->tex_coordinates[index].size();
01382                         output->tex_coordinates[index].resize(output->tex_coordinates[index].size() + (*iter)->tex_coordinates[i].size());
01383                         for(unsigned int j=0; j<(*iter)->tex_coordinates[i].size(); ++j)
01384                         {
01385                                 output->tex_coordinates[index][oi+j] = (*iter)->tex_coordinates[i][j];
01386                         }
01387                 }
01388         }
01389         return output;
01390 }
01391 
01392 pcl::IndicesPtr concatenate(const std::vector<pcl::IndicesPtr> & indices)
01393 {
01394         //compute total size
01395         unsigned int totalSize = 0;
01396         for(unsigned int i=0; i<indices.size(); ++i)
01397         {
01398                 totalSize += (unsigned int)indices[i]->size();
01399         }
01400         pcl::IndicesPtr ind(new std::vector<int>(totalSize));
01401         unsigned int io = 0;
01402         for(unsigned int i=0; i<indices.size(); ++i)
01403         {
01404                 for(unsigned int j=0; j<indices[i]->size(); ++j)
01405                 {
01406                         ind->at(io++) = indices[i]->at(j);
01407                 }
01408         }
01409         return ind;
01410 }
01411 
01412 pcl::IndicesPtr concatenate(const pcl::IndicesPtr & indicesA, const pcl::IndicesPtr & indicesB)
01413 {
01414         pcl::IndicesPtr ind(new std::vector<int>(*indicesA));
01415         ind->resize(ind->size()+indicesB->size());
01416         unsigned int oi = (unsigned int)indicesA->size();
01417         for(unsigned int i=0; i<indicesB->size(); ++i)
01418         {
01419                 ind->at(oi++) = indicesB->at(i);
01420         }
01421         return ind;
01422 }
01423 
01424 void savePCDWords(
01425                 const std::string & fileName,
01426                 const std::multimap<int, pcl::PointXYZ> & words,
01427                 const Transform & transform)
01428 {
01429         if(words.size())
01430         {
01431                 pcl::PointCloud<pcl::PointXYZ> cloud;
01432                 cloud.resize(words.size());
01433                 int i=0;
01434                 for(std::multimap<int, pcl::PointXYZ>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
01435                 {
01436                         cloud[i++] = transformPoint(iter->second, transform);
01437                 }
01438                 pcl::io::savePCDFile(fileName, cloud);
01439         }
01440 }
01441 
01442 void savePCDWords(
01443                 const std::string & fileName,
01444                 const std::multimap<int, cv::Point3f> & words,
01445                 const Transform & transform)
01446 {
01447         if(words.size())
01448         {
01449                 pcl::PointCloud<pcl::PointXYZ> cloud;
01450                 cloud.resize(words.size());
01451                 int i=0;
01452                 for(std::multimap<int, cv::Point3f>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
01453                 {
01454                         cv::Point3f pt = transformPoint(iter->second, transform);
01455                         cloud[i++] = pcl::PointXYZ(pt.x, pt.y, pt.z);
01456                 }
01457                 pcl::io::savePCDFile(fileName, cloud);
01458         }
01459 }
01460 
01461 pcl::PointCloud<pcl::PointXYZ>::Ptr loadBINCloud(const std::string & fileName, int dim)
01462 {
01463         UASSERT(dim > 0);
01464         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
01465 
01466         long bytes = UFile::length(fileName);
01467         if(bytes)
01468         {
01469                 UASSERT(bytes % sizeof(float) == 0);
01470                 int32_t num = bytes/sizeof(float);
01471                 UASSERT(num % dim == 0);
01472                 float *data = (float*)malloc(num*sizeof(float));
01473 
01474                 // pointers
01475                 float *px = data+0;
01476                 float *py = data+1;
01477                 float *pz = data+2;
01478                 float *pr = data+3;
01479 
01480                 // load point cloud
01481                 FILE *stream;
01482                 stream = fopen (fileName.c_str(),"rb");
01483                 num = fread(data,sizeof(float),num,stream)/4;
01484                 cloud->resize(num);
01485                 for (int32_t i=0; i<num; i++) {
01486                         (*cloud)[i].x = *px;
01487                         (*cloud)[i].y = *py;
01488                         (*cloud)[i].z = *pz;
01489                         px+=4; py+=4; pz+=4; pr+=4;
01490                 }
01491                 fclose(stream);
01492         }
01493 
01494         return cloud;
01495 }
01496 
01497 cv::Mat loadScan(
01498                 const std::string & path,
01499                 const Transform & transform,
01500                 int downsampleStep,
01501                 float voxelSize,
01502                 int normalsK)
01503 {
01504         cv::Mat scan;
01505         UDEBUG("Loading scan (normalsK=%d) : %s", normalsK, path.c_str());
01506         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = loadCloud(path, Transform::getIdentity(), downsampleStep, voxelSize);
01507         if(normalsK > 0 && cloud->size())
01508         {
01509                 pcl::PointCloud<pcl::Normal>::Ptr normals = util3d::computeNormals(cloud, normalsK);
01510                 pcl::PointCloud<pcl::PointNormal>::Ptr cloudNormals(new pcl::PointCloud<pcl::PointNormal>);
01511                 pcl::concatenateFields(*cloud, *normals, *cloudNormals);
01512                 scan = util3d::laserScanFromPointCloud(*cloudNormals, transform);
01513         }
01514         else
01515         {
01516                 scan = util3d::laserScanFromPointCloud(*cloud, transform);
01517         }
01518         return scan;
01519 }
01520 
01521 pcl::PointCloud<pcl::PointXYZ>::Ptr loadCloud(
01522                 const std::string & path,
01523                 const Transform & transform,
01524                 int downsampleStep,
01525                 float voxelSize)
01526 {
01527         UASSERT(!transform.isNull());
01528         UDEBUG("Loading cloud (step=%d, voxel=%f m) : %s", downsampleStep, voxelSize, path.c_str());
01529         std::string fileName = UFile::getName(path);
01530         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
01531         if(UFile::getExtension(fileName).compare("bin") == 0)
01532         {
01533                 cloud = util3d::loadBINCloud(path, 4); // Assume KITTI velodyne format
01534         }
01535         else if(UFile::getExtension(fileName).compare("pcd") == 0)
01536         {
01537                 pcl::io::loadPCDFile(path, *cloud);
01538         }
01539         else
01540         {
01541                 pcl::io::loadPLYFile(path, *cloud);
01542         }
01543         int previousSize = (int)cloud->size();
01544         if(downsampleStep > 1 && cloud->size())
01545         {
01546                 cloud = util3d::downsample(cloud, downsampleStep);
01547                 UDEBUG("Downsampling scan (step=%d): %d -> %d", downsampleStep, previousSize, (int)cloud->size());
01548         }
01549         previousSize = (int)cloud->size();
01550         if(voxelSize > 0.0f && cloud->size())
01551         {
01552                 cloud = util3d::voxelize(cloud, voxelSize);
01553                 UDEBUG("Voxel filtering scan (voxel=%f m): %d -> %d", voxelSize, previousSize, (int)cloud->size());
01554         }
01555         if(transform.isIdentity())
01556         {
01557                 return cloud;
01558         }
01559         return util3d::transformPointCloud(cloud, transform);
01560 }
01561 
01562 }
01563 
01564 }


rtabmap
Author(s): Mathieu Labbe
autogenerated on Sat Jul 23 2016 11:44:28