00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <rtabmap/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
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;
00082 fy = 0.0f;
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
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
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;
00146 fy = 0.0f;
00147 for(unsigned int h = 0; h < cloud.height; h++)
00148 {
00149 for(unsigned int w = 0; w < cloud.width; w++)
00150 {
00151
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
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
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
00227 cx = cx > 0.0f ? cx : float(depthImage.cols/2) - 0.5f;
00228 cy = cy > 0.0f ? cy : float(depthImage.rows/2) - 0.5f;
00229
00230
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
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)
00389 {
00390 mono = false;
00391 }
00392 else if(imageRgb.channels() == 1)
00393 {
00394 mono = true;
00395 }
00396 else
00397 {
00398 return cloud;
00399 }
00400
00401
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
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)
00582 {
00583 mono = false;
00584 }
00585 else
00586 {
00587 mono = true;
00588 }
00589
00590
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
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
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
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
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
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
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
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
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
01114 cv::Mat projectCloudToCamera(
01115 const cv::Size & imageSize,
01116 const cv::Mat & cameraMatrixK,
01117 const cv::Mat & laserScan,
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
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
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,
01182 const pcl::PointCloud<pcl::PointXYZ>::Ptr laserScan,
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
01201 pcl::PointXYZ ptScan = laserScan->at(i);
01202 ptScan = util3d::transformPoint(ptScan, t);
01203
01204
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
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
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;
01337 for(std::list<pcl::TextureMesh::Ptr>::const_iterator iter = meshes.begin(); iter!=meshes.end(); ++iter)
01338 {
01339
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
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
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
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
01475 float *px = data+0;
01476 float *py = data+1;
01477 float *pz = data+2;
01478 float *pr = data+3;
01479
01480
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);
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 }