StructureColoring.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2013, Fraunhofer FKIE
00003  *
00004  * Authors: Bastian Gaspers
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  * * Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * * Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * * Neither the name of the Fraunhofer FKIE nor the names of its
00015  *   contributors may be used to endorse or promote products derived from
00016  *   this software without specific prior written permission.
00017  *
00018  * This file is part of the StructureColoring ROS package.
00019  *
00020  * The StructureColoring ROS package is free software:
00021  * you can redistribute it and/or modify it under the terms of the
00022  * GNU Lesser General Public License as published by the Free
00023  * Software Foundation, either version 3 of the License, or
00024  * (at your option) any later version.
00025  *
00026  * The StructureColoring ROS package is distributed in the hope that it will be useful,
00027  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00028  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00029  * GNU Lesser General Public License for more details.
00030  *
00031  * You should have received a copy of the GNU Lesser General Public License
00032  * along with The StructureColoring ROS package.
00033  * If not, see <http://www.gnu.org/licenses/>.
00034  */
00035 
00036 #include <structureColoring/StructureColoring.h>
00037 #include <structureColoring/grids/CylinderGridMap.h>
00038 #include <structureColoring/RosVisualization.h>
00039 #include <structureColoring/NodePair.h>
00040 #include <structureColoring/histograms/SphereUniformSampling.h>
00041 #include <structureColoring/histograms/TriangleDistributionHistogram.h>
00042 #include <structureColoring/histograms/TriangleDistributionHistogramWithRemove.h>
00043 #include <structureColoring/histograms/TriangleDistributionHistogram2D.h>
00044 #include <structureColoring/histograms/WeightedIdxVector.h>
00045 #include <pcl/sample_consensus/method_types.h>
00046 #include <pcl/sample_consensus/model_types.h>
00047 #include <pcl/segmentation/sac_segmentation.h>
00048 #include <pcl/filters/extract_indices.h>
00049 #include <pcl/filters/voxel_grid.h>
00050 #include <pcl/filters/passthrough.h>
00051 #include <pcl/features/normal_3d.h>
00052 #include <pcl/io/pcd_io.h>
00053 #include <pcl/common/time.h>
00054 #include <algorithm>
00055 #include <cmath>
00056 #include <limits>
00057 #include <queue>
00058 #include <set>
00059 #include <Eigen/StdVector>
00060 
00061 
00062 /*****************************************************************************/
00063 
00064 StructureColoring::StructureColoring(ros::NodeHandle& n, int argc, char* argv[]) : mVis(NULL)
00065 {
00066     init(n, argc, argv);
00067 }
00068 
00069 /*****************************************************************************/
00070 
00071 void StructureColoring::init(ros::NodeHandle& n, int argc, char* argv[])
00072 {
00073         init(argc, argv);
00074         initNode(n);
00075         mVis = new RosVisualization(n);
00076     if (mParams.mVerbose)
00077     {
00078         ROS_INFO("Verbose output enabled");
00079         mVis->printTopics();
00080     }
00081 }
00082 
00083 /*****************************************************************************/
00084 
00085 void StructureColoring::init(int argc, char* argv[])
00086 {
00087         initParams();
00088         std::string paramFilename;
00089         parseInput(paramFilename, mParams.mInputFilename, mParams.mOutputFilename, argc, argv);
00090         if (mParams.mInputFilename == "")
00091                 mParams.mInputFilename = "../ABW/abw.test.0";
00092         if (mParams.mABW)
00093                 mParams.mInputFilename.append(".range");
00094         if (mParams.mOutputFilename == "")
00095                 mParams.mOutputFilename = "output";
00096         mParams.mNormalOutputFilename = mParams.mOutputFilename;
00097         mParams.mOutputFilename.append(".ms-seg");
00098         mParams.mNormalOutputFilename.append(".ms-nor");
00099         mParams.parseParamFile(paramFilename);
00100         initOctree();
00101 }
00102 
00103 /*****************************************************************************/
00104 
00105 void StructureColoring::init()
00106 {
00107         initParams();
00108         initOctree();
00109 }
00110 
00111 /*****************************************************************************/
00112 
00113 StructureColoring::~StructureColoring()
00114 {
00115         if(mVis) delete mVis;
00116 }
00117 
00118 /*****************************************************************************/
00119 
00120 void StructureColoring::parseInput(std::string& paramFilename, std::string& inputFilename, std::string& outputFilename,
00121                 int argc, char* argv[])
00122 {
00123         for (int i = 1; i < argc; i += 2) {
00124                 if (std::string(argv[i]) == "--kinect") {
00125                         mParams.mKinect = true;
00126                         mParams.mTextures = true;
00127                         i--;
00128                         continue;
00129                 }
00130         else if (std::string(argv[i]) == "--textures") {
00131                 mParams.mTextures = true;
00132                         i--;
00133                         continue;
00134                 }
00135         else if (std::string(argv[i]) == "--cylinder") {
00136                 mParams.mCylinder = true;
00137                         i--;
00138                         continue;
00139                 }
00140         else if (std::string(argv[i]) == "--disableRansacStep") {
00141                 mParams.mNoRansacStep = true;
00142             i--;
00143             continue;
00144         }
00145         else if (std::string(argv[i]) == "-v") {
00146                 mParams.mVerbose = true;
00147                         i--;
00148                         continue;
00149                 }
00150                 if (i + 1 < argc) {
00151                         if (std::string(argv[i]) == "--kinectt") {
00152                                 mKinectTopic = argv[i + 1];
00153                                 mParams.mKinect = true;
00154                                 mParams.mTextures = true;
00155                                 continue;
00156                         } else if (std::string(argv[i]) == "--postprocessing") {
00157                                 mParams.mPostProcessing = atoi(argv[i + 1]);
00158                         } else if (std::string(argv[i]) == "--debugsteps") {
00159                                 mParams.mDebugSteps = atoi(argv[i + 1]);
00160                         } else if (std::string(argv[i]) == "-r") {
00161                                 inputFilename = argv[i + 1];
00162                                 mParams.mPGM = true;
00163                         } else if (std::string(argv[i]) == "--laser") {
00164                                 mParams.mLaser = true;
00165                                 mParams.mLaserTopic = argv[i+1];
00166                         } else if (std::string(argv[i]) == "-p") {
00167                                 paramFilename = argv[i + 1];
00168                         } else if (std::string(argv[i]) == "-m") {
00169                                 outputFilename = argv[i + 1];
00170                         } else if (std::string(argv[i]) == "--prefix") {
00171                                 mParams.mABW = true;
00172                                 inputFilename = outputFilename = argv[i + 1];
00173                         } else if (std::string(argv[i]) == "--percPrefix") {
00174                                 mParams.mPerceptron = true;
00175                                 inputFilename = outputFilename = argv[i + 1];
00176                         } else if (std::string(argv[i]) == "--rawpic") {
00177                                 mParams.mWriteRawPic = true;
00178                                 mParams.mRawPicFilename = argv[i + 1];
00179                         } else if (std::string(argv[i]) == "--pcd") {
00180                                 mParams.mTextures = true;
00181                                 mParams.mLoadPCD = true;
00182                                 inputFilename = argv[i + 1];
00183                         } else if (std::string(argv[i]) == "--pcdNoRgb") {
00184                                 mParams.mLoadPCD = true;
00185                                 mParams.mPCDnoRGB = true;
00186                                 inputFilename = argv[i + 1];
00187             } else if (std::string(argv[i]) == "--pclSAC") {
00188                 mParams.mPclSAC = true;
00189                 mParams.mPclSACmaxIter = atoi(argv[i+1]);
00190                         } else if (std::string(argv[i]) == "--runtimeFile") {
00191                                 mParams.mRuntimeFilename = argv[i + 1];
00192                         } else if (std::string(argv[i]) == "--depth") {
00193                                 mParams.mOnlyDepth = atoi(argv[i + 1]);
00194                         }
00195             else {
00196                                 std::cout << "Not enough or invalid arguments, please try again.\n"
00197                                                 << "arguments are:\n"
00198                                                 << "--kinect               Start segmentation on kinect topics\n"
00199                                                 << "--kinectt [string]     Start segmentation on kinect, specifying topic\n"
00200                                                 << "--laser [string]       Start segmentation on laser [string] topic\n"
00201                                                 << "--textures             Start segmentation and calculate textures for planes afterwards,\n"
00202                                                 << "                            works on PointClouds with RGB Data ONLY!\n"
00203                                                 << "--cylinder             Start segmentation, do cylinder segmentation after plane segmentation\n"
00204                                                 << "--disableRansacStep    Start segmentation, but leave out ransac steps#\n"
00205                                                 << "-v                     Start segmentation with verbose output (of ros frames)\n"
00206                                                 << "--postprocessing [int] Start segmentation with postprocessing steps according to [int]\n"
00207                                                 << "--debugsteps [int]     Start segmentation with [int] steps for debugging\n"
00208                                                 << "-r [string]            set input PGM filename to [string]\n"
00209                                                 << "-p [string]            set param file to [string], 3 params can be configured there:\n"
00210                                                 << "                            mMaxHTDistanceThreshold(float), mHTOctreeBinSizeFactor(float)\n"
00211                                                 << "                            mHTDistanceDeviationFactor(float)\n"
00212                                                 << "-m [string]            set output PGM filename to [string]\n"
00213                                                 << "--prefix [string]      set ABW rasterfile input and output prefix (without .range)\n"
00214                                                 << "--percPrefix [string]  set PERCEPTRON rasterfile input file and output prefix\n"
00215                                                 << "--rawpic [string]      set output for pcd and picture of colored points,\n"
00216                                                 << "                            works on PointClouds with RGB Data ONLY!\n"
00217                                                 << "--pcd [string]         set input pcd file to [string]\n"
00218                                                 << "--pclSAC [int]         start PCL RANSAC with [int] maxIterations\n"
00219                                                 << "--runtimeFile [string] write time used for segmentation to file [string]\n"
00220                                                 << "--depth [int]          start segmentation with HT / CC / RANSAC on octree depth [int]\n";
00221                                 exit(0);
00222                         }
00223                 }
00224         }
00225 }
00226 
00227 /*****************************************************************************/
00228 
00229 void StructureColoring::initNode(ros::NodeHandle& n)
00230 {
00231         mNodeHandle = &n;
00232         //setup subscriber
00233         if (mParams.mKinect)
00234                 mPointCloud2Subscriber = mNodeHandle->subscribe<sensor_msgs::PointCloud2> (mKinectTopic, 1,
00235                                 &StructureColoring::pointCloud2Callback, this);
00236         if (mParams.mLaser)
00237                 mPointCloudSubscriber = mNodeHandle->subscribe<sensor_msgs::PointCloud> (mParams.mLaserTopic, 1,
00238                                 &StructureColoring::pointCloudCallback, this);
00239         //publisher is set in class RosVisualization / member variable mVis
00240 }
00241 
00242 /*****************************************************************************/
00243 
00244 void StructureColoring::initParams()
00245 {
00246         mLastCellSizeWithNormals = mParams.mRho_max;
00247         mKinectTopic = "/camera/depth_registered/points";
00248 }
00249 
00250 /*****************************************************************************/
00251 
00252 void StructureColoring::initOctree()
00253 {
00254         unsigned int numPoints = 512 * 512; //TODO softcode resolution
00255         if (mParams.mKinect) numPoints = 640 * 480;
00256         if (mParams.mLaser) numPoints = 2000000;
00257         if (!mOcTree) mOcTree.reset(new OcTree(mParams.mMinOctreeResolution, mParams.mRho_max, mParams.mPrincipalVarFactor,
00258                         mParams.mMinPointsForNormal, mParams.mCurvThreshold, mParams.mCurv2Threshold, mParams.mSqDistFactor, numPoints));
00259 }
00260 
00261 /*****************************************************************************/
00262 
00263 void StructureColoring::pointCloud2Callback(const sensor_msgs::PointCloud2ConstPtr& msg)
00264 {
00265         PointCloudPtr pointCloud(new PointCloud());
00266         PlanePatchVector pointMappingPlanes;//for PlanePatches
00267         CylinderPatchVector pointMappingCylinders;//for CylinderPatches
00268         PlanePatches extractedPlanes;
00269         CylinderPatches extractedCylinders;
00270         //get input from rosMsg
00271         filterMsgSetupCloud(*pointCloud, msg, -mParams.mRho_max, mParams.mRho_max, mParams.mKinect, mParams.mWriteRawPic, mParams.mRawPicFilename, mParams.mRawPicCounter++);
00272 
00273         doSegmentation(pointCloud, pointMappingPlanes, extractedPlanes, pointMappingCylinders, extractedCylinders);
00274 }
00275 
00276 /*****************************************************************************/
00277 
00278 void StructureColoring::doSegmentation(PointCloudPtr pointCloud, PlanePatchVector& pointMapping, PlanePatches& extractedPlanes,
00279                 CylinderPatchVector& pointMappingCylinders, CylinderPatches& extractedCylinders){
00280         double elapsedTime = 0.0;
00281         if(mPointCloudMutex.tryLock(100)){
00282                 mPointCloud = pointCloud;
00283                 mPointCloudMutex.unlock();
00284         }
00285 
00286         if(mParams.mCylinder)
00287         {
00288             initSegmentation(pointMappingCylinders, *pointCloud);
00289         if (mParams.mPclSAC)
00290             elapsedTime = segmentCylindersSAC(extractedCylinders, pointMappingCylinders, *mOcTree, pointCloud);
00291         else
00292             elapsedTime = segmentCylinders(extractedCylinders, pointMappingCylinders, *mOcTree, pointCloud);
00293     }
00294     else
00295     {
00296         initSegmentation(pointMapping, *pointCloud);
00297         if (mParams.mPclSAC)
00298             elapsedTime = segmentPlanesSAC(extractedPlanes, pointMapping, pointCloud);
00299         else
00300             elapsedTime = segmentPlanes(extractedPlanes, pointMapping, *mOcTree, pointCloud);
00301     }
00302         if(mPointCloudMutex.tryLock(100)){
00303                 mPointMapping = pointMapping;
00304                 mPointCloudMutex.unlock();
00305         }
00306         if(mPlanePatchesMutex.tryLock(100)){
00307                 if (mParams.mTextures) generateTextures(extractedPlanes, *pointCloud);
00308                 mPlanePatches = extractedPlanes;
00309                 mPlanePatchesMutex.unlock();
00310         }
00311         if(mCylinderPatchesMutex.tryLock(100)){
00312                 mCylinderPatches = extractedCylinders;
00313                 mCylinderPatchesMutex.unlock();
00314         }
00315 
00316         if (std::strcmp(mParams.mRuntimeFilename.c_str(), "") != 0) writeTimeToFile(mParams.mRuntimeFilename, elapsedTime);
00317 
00318         callPublisher(*mOcTree, extractedPlanes, extractedCylinders, pointCloud, pointMapping, pointMappingCylinders);
00319 }
00320 
00321 /*****************************************************************************/
00322 
00323 void StructureColoring::pointCloudCallback(const sensor_msgs::PointCloudConstPtr& msg) {
00324         sensor_msgs::PointCloud2Ptr pc2msg(new sensor_msgs::PointCloud2());
00325         if (sensor_msgs::convertPointCloudToPointCloud2(*msg.get(), *pc2msg)){
00326                 pcl::PointCloud<pcl::PointXYZ>::Ptr noColorPC(new pcl::PointCloud<pcl::PointXYZ>);
00327                 pcl::fromROSMsg(*pc2msg, *noColorPC);
00328                 PointCloudPtr colorPC(new PointCloud);
00329                 colorPC->points.reserve(noColorPC->points.size());
00330                 for(std::vector<pcl::PointXYZ, Eigen::aligned_allocator<pcl::PointXYZ> >::const_iterator pit = noColorPC->points.begin();
00331                                 pit != noColorPC->points.end(); ++pit){
00332                         PointT p;
00333                         p.x = pit->x;
00334                         p.y = pit->y;
00335                         p.z = pit->z;
00336                         p.rgb = 0;
00337                         colorPC->points.push_back(p);
00338                 }
00339                 sensor_msgs::PointCloud2Ptr cpcMsg(new sensor_msgs::PointCloud2());
00340                 pcl::toROSMsg<PointT>(*colorPC, *cpcMsg);
00341                 pointCloud2Callback(cpcMsg);
00342         }
00343 }
00344 
00345 /*****************************************************************************/
00346 
00347 void StructureColoring::readPointCloudFromPCD(PointCloud& pointCloud, const std::string& filename, unsigned int& width,
00348                 unsigned int& height, std::vector<unsigned int>& undefPoints, const float& zMax, const float& zMin){
00349     sensor_msgs::PointCloud2Ptr msg(new sensor_msgs::PointCloud2);
00350         pcl::PCDReader reader;
00351     if (mParams.mPCDnoRGB)
00352     {
00353             reader.read(filename, *msg);
00354         pcl::PointCloud<pcl::PointXYZ> my_pointCloud;
00355         pcl::fromROSMsg(*msg, my_pointCloud);
00356         pointCloud.points.reserve(my_pointCloud.points.size());
00357         for (size_t i = 0; i < my_pointCloud.points.size(); ++i)
00358         {
00359                         PointT p;
00360                         p.rgb = 0x00000000;
00361             p.x = my_pointCloud.points[i].x;
00362             p.y = my_pointCloud.points[i].y;
00363             p.z = my_pointCloud.points[i].z;
00364             pointCloud.points.push_back(p);
00365         }
00366     }
00367     else
00368             reader.read(filename, pointCloud);
00369         filterCloud(pointCloud, undefPoints, zMax, zMin);
00370     if (mParams.mPCDnoRGB)
00371     {
00372         width = pointCloud.points.size();
00373         height = 1;
00374     }
00375     else
00376     {
00377         width = pointCloud.width;
00378         height =  pointCloud.height;
00379     }
00380         pointCloud.width = pointCloud.points.size();
00381         pointCloud.height = 1;
00382         ROS_INFO("read PointCloud with %zu points, width = %d, height = %d", pointCloud.points.size(), pointCloud.width, pointCloud.height);
00383 }
00384 
00385 /*****************************************************************************/
00386 
00387 void StructureColoring::filterCloud(PointCloud& pointCloud, std::vector<unsigned int>& undefPoints, const float& zMax, const float& zMin){
00388         PointCloud pc2;
00389         pc2.header = pointCloud.header;
00390         pc2.points.swap(pointCloud.points);
00391         pointCloud.points.reserve(pc2.points.size());
00392         undefPoints.reserve(pc2.points.size());
00393         for(unsigned int i=0; i<pc2.points.size(); ++i){
00394                 const PointT& p = pc2.points[i];
00395                 if(std::isfinite(p.x) && std::isfinite(p.y) && std::isfinite(p.z) && p.z < zMax && p.z > zMin)
00396                         pointCloud.points.push_back(p);
00397                 else undefPoints.push_back(i);
00398         }
00399 }
00400 
00401 /*****************************************************************************/
00402 
00403 void StructureColoring::getPointsFromFile() {
00404         PointCloudPtr pointCloud(new PointCloud());
00405         PlanePatchVector pointMappingPlanes;
00406         PlanePatches extractedPlanes;
00407         CylinderPatches extractedCylinders;
00408         CylinderPatchVector pointMappingCylinders;
00409         //input (from disc)
00410         unsigned int width = 512, height = 512;
00411         std::vector<unsigned int> undefPoints;
00412     ROS_INFO("reading file: %s", mParams.mInputFilename.c_str());
00413         if (mParams.mPerceptron)
00414                 readPointCloudFromPERCEPTRONFile(*pointCloud, mParams.mInputFilename, width, height, undefPoints);
00415         else if (mParams.mLoadPCD)
00416                 readPointCloudFromPCD(*pointCloud, mParams.mInputFilename, width, height, undefPoints, mParams.mRho_max, -mParams.mRho_max);
00417         else if (mParams.mABW)
00418                 readPointCloudFromABWFile(*pointCloud, mParams.mInputFilename, width, height, undefPoints, mParams.mPGM);
00419     else
00420     {
00421         ROS_ERROR("unknown input type");
00422         return;
00423     }
00424 
00425         mOcTree.reset(new OcTree(mParams.mMinOctreeResolution, mParams.mRho_max, mParams.mPrincipalVarFactor, mParams.mMinPointsForNormal,
00426                         mParams.mCurvThreshold, mParams.mCurv2Threshold, mParams.mSqDistFactor, width * height));
00427 
00428         if (mVis) mVis->publishPointCloud(*pointCloud);
00429         //start segmentation
00430         doSegmentation(pointCloud, pointMappingPlanes, extractedPlanes, pointMappingCylinders, extractedCylinders);
00431 
00432         if(mParams.mCylinder)
00433         {
00434                 writeSegments(width, height, undefPoints, pointMappingCylinders, mParams.mOutputFilename, extractedCylinders);
00435     }
00436     else
00437     {
00438                 writeSegments(width, height, undefPoints, pointMappingPlanes, mParams.mOutputFilename, extractedPlanes);
00439     }
00440 
00441         if(!mParams.mLoadPCD) writeMSNormals(mParams.mNormalOutputFilename, extractedPlanes);
00442         size_t unsegPoints = 0;
00443         for(PlanePatchVector::const_iterator ppvit = pointMappingPlanes.begin(); ppvit != pointMappingPlanes.end(); ++ppvit)
00444         {
00445                 if (!*ppvit) ++unsegPoints;
00446         }
00447         ROS_INFO("number of undefined points = %zu, number of unsegmented points = %zu", undefPoints.size(), unsegPoints);
00448 }
00449 
00450 /*****************************************************************************/
00451 
00452 double StructureColoring::segmentPlanes(PlanePatches& extractedPlanes, PlanePatchVector& pointMapping, OcTree& octree,
00453                 const PointCloudPtr& pointCloud) {
00454     double start = pcl::getTime();
00455 
00456         octree.buildOctree(*pointCloud);
00457         extractOctreePlanesFromCloud(extractedPlanes, pointMapping, octree, pointCloud);
00458 
00459         //post-processing
00460         if (mParams.mPostProcessing & 1) {
00461                 mergePlanes(extractedPlanes, pointMapping, *pointCloud);
00462         }
00463         if (mParams.mPostProcessing & 2) {
00464                 spreadNodes(octree, extractedPlanes, pointMapping, *pointCloud);
00465         }
00466         if (mParams.mPostProcessing & 4)
00467                 mergePlanes(extractedPlanes, pointMapping, *pointCloud);
00468 
00469     double end = pcl::getTime();
00470         double elapsedTime = end - start;
00471         ROS_ERROR("response sent %f seconds after receiving pointcloud", elapsedTime);
00472         return elapsedTime;
00473 }
00474 
00475 /*****************************************************************************/
00476 
00477 double StructureColoring::segmentCylinders(CylinderPatches& cylinderPatches, CylinderPatchVector& pointMapping, OcTree& octree, const PointCloudPtr& pointCloud){
00478     double start = pcl::getTime();
00479 
00480         octree.buildOctree(*pointCloud);
00481 
00482         extractOctreeCylindersFromCloud(cylinderPatches, pointMapping, octree, pointCloud);
00483 
00484 //    CylinderPatches::iterator it = cylinderPatches.begin();
00485 //    while (it != cylinderPatches.end())
00486 //    {
00487 //        if (!checkCylinder(*it, pointCloud))
00488 //        {
00489 //            it = cylinderPatches.erase(it);
00490 //        }
00491 //        else
00492 //            ++it;
00493 //    }
00494 //    rebuildPointMapping(pointMapping, cylinderPatches);
00495         ROS_INFO("%zu cylinders left", cylinderPatches.size());
00496 
00497     double end = pcl::getTime();
00498         double elapsedTime = end - start;
00499         ROS_ERROR("response sent %f seconds after receiving pointcloud", elapsedTime);
00500         return elapsedTime;
00501 }
00502 
00503 /*****************************************************************************/
00504 
00505 void StructureColoring::generateTextures(const PlanePatches& extractedPlanes, const PointCloud& pointCloud){
00506         for (PlanePatches::const_iterator plane_it = extractedPlanes.begin(); plane_it != extractedPlanes.end(); ++plane_it){
00507                 (*plane_it)->computeRGBTextureMap(pointCloud, mParams.mTexelSizeFactor, mParams.mDilateIterations);
00508         }
00509 }
00510 
00511 /*****************************************************************************/
00512 
00513 void StructureColoring::callPublisher(const OcTree& octree, PlanePatches& extractedPlanes, const CylinderPatches& extractedCylinders , const PointCloudPtr pointCloud,
00514                 const PlanePatchVector& pointMapping, const CylinderPatchVector& cylinderPointMapping) {
00515         CompArea compArea;
00516         extractedPlanes.sort(compArea);
00517         if (mVis) {
00518                 mVis->publishOctreeNormalMarker(octree);
00519                 mVis->publishPlaneMarker(extractedPlanes);
00520                 mVis->publishSegmentedPointcloud(pointMapping, extractedPlanes, *pointCloud);
00521                 mVis->publishSegmentedPointcloud(cylinderPointMapping, extractedCylinders, *pointCloud);
00522                 mVis->publishPointCloud(*pointCloud);
00523                 if(mParams.mCylinder){
00524                         mVis->publishCylinderMarker(extractedCylinders);
00525                         mVis->publishCylinderPoints(extractedCylinders, pointCloud);
00526                 }
00527         }
00528 }
00529 
00530 /*****************************************************************************/
00531 
00532 void writePicFromPointCloud(const PointCloud& cloudWithFarPoints, const std::string& rawPicFilename){
00533         cv::Mat pic(cloudWithFarPoints.height, cloudWithFarPoints.width, CV_8UC3);
00534         for(unsigned int r = 0; r < cloudWithFarPoints.height; ++r){
00535                 for(unsigned int c = 0; c < cloudWithFarPoints.width; ++c){
00536                         pcl::PointXYZRGB pointrgb = cloudWithFarPoints.points[r * cloudWithFarPoints.width + c];
00537                         if(std::isfinite(pointrgb.x) && std::isfinite(pointrgb.y) && std::isfinite(pointrgb.z)){
00538                                 float rgbfloat = pointrgb.rgb;
00539                                 int rgbint = *reinterpret_cast<int*> (&rgbfloat);
00540                                 pic.at<cv::Vec3b>(r, c)[0] = rgbint & 0xff;
00541                                 pic.at<cv::Vec3b>(r, c)[1] = (rgbint >> 8) & 0xff;
00542                                 pic.at<cv::Vec3b>(r, c)[2] = (rgbint >> 16) & 0xff;
00543                         } else {
00544                                 pic.at<cv::Vec3b>(r, c)[0] = 0.f;
00545                                 pic.at<cv::Vec3b>(r, c)[1] = 0.f;
00546                                 pic.at<cv::Vec3b>(r, c)[2] = 0.f;
00547                         }
00548                 }
00549         }
00550         std::string tmpfn(rawPicFilename);
00551         tmpfn.append(".ras");
00552         ROS_INFO("%s", tmpfn.c_str());
00553         cv::imwrite(tmpfn, pic);
00554 }
00555 
00556 /*****************************************************************************/
00557 
00558 template<typename PointCloudType>
00559 void writePCDFromPointCloud(const PointCloudType& cloudWithFarPoints, const std::string& rawPicFilename){
00560         pcl::PCDWriter writer;
00561         std::string tmpfn(rawPicFilename);
00562         tmpfn.append(".pcd");
00563         writer.write(tmpfn, cloudWithFarPoints, false);
00564 }
00565 
00566 /*****************************************************************************/
00567 
00568 void StructureColoring::filterMsgSetupCloud(PointCloud& pointCloud, const sensor_msgs::PointCloud2ConstPtr& pMsg, double zMin, double zMax, bool fromKinect, bool writePic, const std::string& picFilename, unsigned int picCounter) {
00569     PointCloud::Ptr cloudWithFarPoints(new PointCloud());
00570         pcl::fromROSMsg(*pMsg, *cloudWithFarPoints);
00571         if(writePic){
00572                 std::string tmpPicFilename(picFilename);
00573                 char counterChars[10];
00574                 sprintf(counterChars, "%d", picCounter++);
00575                 tmpPicFilename.append(counterChars);
00576                 writePicFromPointCloud(*cloudWithFarPoints, tmpPicFilename);
00577                 writePCDFromPointCloud(*cloudWithFarPoints, tmpPicFilename);
00578         }
00579 
00580 // Create the filtering object
00581         pcl::PassThrough<PointT> pass;
00582         pass.setInputCloud(cloudWithFarPoints);
00583         pass.setFilterFieldName("z");
00584         pass.setFilterLimits(zMin, zMax);
00585         pass.filter(pointCloud);
00586         pointCloud.width = pointCloud.points.size();
00587         pointCloud.height = 1;
00588         //      ROS_INFO("cloud: point cloud has %zu points", mPointCloud.points.size());
00589         if (mParams.mKinect) {
00590 #pragma omp parallel for schedule(dynamic,1)
00591                 for (size_t i = 0; i < pointCloud.points.size(); ++i) {
00592                         PointT& p = pointCloud.points[i];
00593                         PointT tmp = p;
00594                         p.x = tmp.z;
00595                         p.y = -tmp.x;
00596                         p.z = -tmp.y;
00597                 }
00598         }
00599 }
00600 
00601 /*****************************************************************************/
00602 
00603 void StructureColoring::filterConnectedNodes(std::vector<NodePointers>& CCInlierNodes, const Plane3D& pp,
00604                 const NodePointers& octreeNodes, float cellSize, GridMap* oldGridMap, NodePointers* notConnectedNodesOutput) {
00605         float nodeXMin = std::numeric_limits<float>::max();
00606         float nodeXMax = -std::numeric_limits<float>::max();
00607         float nodeYMin = std::numeric_limits<float>::max();
00608         float nodeYMax = -std::numeric_limits<float>::max();
00609         for(NodePointers::const_iterator npit = octreeNodes.begin(); npit != octreeNodes.end(); ++npit){
00610                 Vec3 tp(pp.transformToXYPlane((*npit)->value_.meanPos));
00611                 if (tp.x() < nodeXMin) nodeXMin = tp.x();
00612                 if (tp.x() > nodeXMax) nodeXMax = tp.x();
00613                 if (tp.y() < nodeYMin) nodeYMin = tp.y();
00614                 if (tp.y() > nodeYMax) nodeYMax = tp.y();
00615         }
00616         GridMap gridmap;
00617         if (oldGridMap == NULL){
00618                 gridmap = GridMap(pp, nodeXMin, nodeXMax, nodeYMin, nodeYMax, cellSize);
00619         }
00620         else {
00621                 float xMin = 0.f, xMax = 0.f, yMin = 0.f, yMax = 0.f;
00622                 unsigned int xOff = 0, xAdd = 0, yOff = 0, yAdd = 0;
00623                 oldGridMap->getNewExtremes(xMin, xMax, yMin, yMax, xOff, xAdd, yOff, yAdd, nodeXMin, nodeXMax, nodeYMin, nodeYMax, cellSize);
00624                 gridmap = GridMap(*oldGridMap, xMin, xMax, yMin, yMax, xOff, xAdd, yOff, yAdd, cellSize);
00625         }
00626         //register OcTreeNodes with grid
00627         gridmap.populate(octreeNodes);
00628 
00629         if (!oldGridMap)
00630     {   // if we constructed a new grid, startPos must be initialized:
00631             gridmap.calculateStartPos();
00632     }
00633         gridmap.getConnectedComponentsAndNotConnectedNodes(CCInlierNodes, octreeNodes, cellSize, mParams.mMinOctreeNodes,
00634                         mParams.mMinNodesInCC, notConnectedNodesOutput);
00635 }
00636 
00637 /*****************************************************************************/
00638 
00639 void StructureColoring::estimatePlane(const pclPointIndices::Ptr& inliers, PlanePatchPtr& planePatch, const PointCloudPtr& pointCloud,
00640                 const float& sacDist) {
00641         pcl::ModelCoefficients coefficients;
00642         pcl::SACSegmentation<PointT> seg;
00643         pclPointIndices newInliers;
00644 
00645         seg.setOptimizeCoefficients(true);
00646         seg.setModelType(pcl::SACMODEL_PLANE);
00647         seg.setMethodType(pcl::SAC_MSAC);
00648         seg.setMaxIterations(100);
00649         seg.setDistanceThreshold(sacDist);
00650         seg.setInputCloud(pointCloud);
00651         seg.setIndices(inliers);
00652         assert(inliers->indices.size() > 3);
00653         seg.segment(newInliers, coefficients);
00654 
00655         if (newInliers.indices.size() == 0) {
00656                 planePatch.reset();
00657         } else {
00658                 Vec3 norm(coefficients.values[0], coefficients.values[1], coefficients.values[2]);
00659                 // RANSAC model Coefficients: ax + by + cz + d = 0
00660                 // my model: n*p - d = 0 with d > 0
00661                 // thus i must switch the distance's sign!
00662                 float distance = -1.f * coefficients.values[3];
00663                 if (distance < 0) {
00664                         distance *= -1.f;
00665                         norm *= -1.f;
00666                 }
00667                 planePatch.reset(new PlanePatch(norm, distance, newInliers.indices, *pointCloud, sacDist));
00668         }
00669 }
00670 
00671 void StructureColoring::estimateCylinder(pclPointIndices& inliers, CylinderPatchPtr& cylinder, unsigned int& numPointsBefRansac, const NodePointers& octreeNodes,
00672                 const OcTree& octree, const PointCloudPtr& pointCloud, const float& sacDist,
00673                 const float& normalDistanceWeight, const float& minRadius, const float& maxRadius) {
00674         pcl::ModelCoefficients coefficients;
00675         pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg;
00676         typedef pcl::PointCloud<pcl::Normal> NormalCloud;
00677     NormalCloud::Ptr normalCloud(new NormalCloud());
00678         pclPointIndices partCloudIndices;
00679         PointCloudPtr partCloud(new PointCloud());
00680 
00681         for(NodePointers::const_iterator np_it = octreeNodes.begin(); np_it != octreeNodes.end(); ++np_it){
00682                 PointIndices inlierPoints;
00683                 getAllPointsFromNodes(inlierPoints, NodePointers(1, *np_it), octree, *pointCloud);
00684                 partCloudIndices.indices.reserve(partCloudIndices.indices.size() + inlierPoints.size());
00685                 copy(inlierPoints.begin(), inlierPoints.end(), back_inserter( partCloudIndices.indices));
00686         }
00687         numPointsBefRansac = partCloudIndices.indices.size();
00688 
00689         pcl::ExtractIndices<PointT> extract;
00690         extract.setInputCloud(pointCloud);
00691         extract.setIndices(boost::make_shared<pclPointIndices>(partCloudIndices));
00692         extract.setNegative(false);
00693         extract.filter(*partCloud);
00694 
00695         normalCloud->points.reserve(partCloud->points.size());
00696         for(unsigned int p_count = 0; p_count < partCloud->points.size(); ++p_count){
00697                 Vec3 point(partCloud->points[p_count].x, partCloud->points[p_count].y, partCloud->points[p_count].z);
00698                 Vec3 eNormal;
00699                 octree.findFinestNormal(eNormal, point);
00700                 pcl::Normal normal;
00701                 normal.normal_x = eNormal.x();
00702                 normal.normal_y = eNormal.y();
00703                 normal.normal_z = eNormal.z();
00704                 normalCloud->points.push_back(normal);
00705         }
00706         assert(partCloud->points.size() == normalCloud->points.size());
00707 
00708         seg.setOptimizeCoefficients(true);
00709         seg.setModelType(pcl::SACMODEL_CYLINDER);
00710         seg.setMethodType(pcl::SAC_RANSAC);
00711         seg.setMaxIterations(100);
00712         seg.setDistanceThreshold(sacDist);
00713         seg.setNormalDistanceWeight(normalDistanceWeight);
00714         seg.setRadiusLimits (minRadius, maxRadius);
00715         seg.setInputCloud(partCloud);
00716         seg.setInputNormals(normalCloud);
00717         seg.segment(inliers, coefficients);
00718 
00719         if(inliers.indices.size() == 0){
00720                 ROS_ERROR("RANSAC: no cylinder found, aborting");
00721                 cylinder.reset();
00722                 return;
00723         }
00724         Vec3 pointOnAxis(coefficients.values[0], coefficients.values[1], coefficients.values[2]);
00725         Vec3 axisDirection(coefficients.values[3], coefficients.values[4], coefficients.values[5]);
00726         float radius(coefficients.values[6]);
00727         const PointIndices& inlierIndices(inliers.indices);
00728         cylinder.reset(new CylinderPatch(inlierIndices, *partCloud, pointOnAxis, axisDirection, radius, sacDist));
00729 }
00730 
00731 void StructureColoring::estimateCylinderNNNormals(CylinderPatchPtr& cylinder,
00732                 const PointCloudPtr& pointCloud, const float& sacDist,
00733                 const float& normalDistanceWeight, const float& minRadius, 
00734         const float& maxRadius, float searchRadius, const Vec3& initialAxis) {
00735         pcl::ModelCoefficients coefficients;
00736         typedef pcl::PointCloud<pcl::Normal> NormalCloud;
00737     NormalCloud::Ptr normalCloud(new NormalCloud);
00738     pclPointIndices::Ptr partCloudIndices(new pclPointIndices());
00739     pclPointIndices::Ptr subsampledPartCloudIndices(new pclPointIndices());
00740         pclPointIndices subsampledInliers, inliers;
00741         PointCloudPtr partCloud(new PointCloud());
00742 
00743         PointCloudPtr subsampledPartCloud(new PointCloud());
00744         PointCloudPtr subsampledCloud(new PointCloud());
00745 
00746         copy(cylinder->getInliers().begin(), cylinder->getInliers().end(), back_inserter(partCloudIndices->indices));
00747 
00748         const float subsamplingLeafSize = 0.5f*0.5f*searchRadius;
00749 
00750         if( subsamplingLeafSize > 2.f*mParams.mMinOctreeResolution ) {
00751 
00752                 ROS_ERROR("downsampling");
00753 
00754                 pcl::VoxelGrid<PointT> subsampler1, subsampler2;
00755                 subsampler1.setSaveLeafLayout(true);
00756                 subsampler1.setInputCloud( pointCloud );
00757                 subsampler1.setLeafSize( subsamplingLeafSize, subsamplingLeafSize, subsamplingLeafSize );
00758                 subsampler1.setSaveLeafLayout(true);
00759                 subsampler1.filter( *subsampledCloud );
00760                 subsampler1.setSaveLeafLayout(true);
00761 
00762                 // subsample cylinder indices..
00763                 // build map from subsampled cylinder indices to original cylinder indices
00764                 std::map< int, std::vector< int > > cylinderSubsamplingMap;
00765                 std::set< int > subsampledPartCloudIndicesSet;
00766                 for( unsigned int i = 0; i < partCloudIndices->indices.size(); i++ ) {
00767                         const PointT& p = pointCloud->points[ partCloudIndices->indices[i] ];
00768                         int subsampledIndex = subsampler1.getCentroidIndexAt( subsampler1.getGridCoordinates( p.x, p.y, p.z ) );
00769                         if( subsampledIndex >= 0 ) {
00770                                 subsampledPartCloudIndicesSet.insert( subsampledIndex );
00771                                 cylinderSubsamplingMap[subsampledIndex].push_back( partCloudIndices->indices[i] );
00772                         }
00773                 }
00774 
00775                 for( std::set<int>::iterator it = subsampledPartCloudIndicesSet.begin(); it != subsampledPartCloudIndicesSet.end(); ++it ) {
00776                         subsampledPartCloudIndices->indices.push_back( *it );
00777                 }
00778 
00779                 pcl::ExtractIndices<PointT> extract;
00780                 extract.setInputCloud(subsampledCloud);
00781                 extract.setIndices(subsampledPartCloudIndices);
00782                 extract.setNegative(false);
00783                 extract.filter(*subsampledPartCloud);
00784 
00785                 pcl::NormalEstimation<PointT, pcl::Normal> ne;
00786                 ne.setIndices(subsampledPartCloudIndices);
00787                 ne.setInputCloud (subsampledCloud);
00788 
00789                 // Create an empty kdtree representation, and pass it to the normal estimation object.
00790                 // Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).
00791                 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB>);
00792                 tree->setInputCloud (subsampledCloud);
00793                 ne.setSearchMethod (tree);
00794 
00795                 // Use all neighbors in a sphere of radius ..
00796                 ne.setRadiusSearch (searchRadius);
00797                 ne.setViewPoint(0.f, 0.f, 0.f);
00798 
00799                 // Compute the features
00800                 ne.compute (*normalCloud);
00801 
00802                 assert(subsampledPartCloud->points.size() == normalCloud->points.size());
00803 
00804                 pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg;
00805                 seg.setOptimizeCoefficients(false);
00806                 seg.setModelType(pcl::SACMODEL_CYLINDER);
00807                 seg.setMethodType(pcl::SAC_RANSAC);
00808                 seg.setMaxIterations(10000);
00809                 seg.setDistanceThreshold(sacDist);
00810                 seg.setNormalDistanceWeight(normalDistanceWeight);
00811                 seg.setRadiusLimits (minRadius, maxRadius);
00812                 (void)initialAxis;
00813                 seg.setInputCloud(subsampledPartCloud);
00814                 seg.setInputNormals(normalCloud);
00815                 seg.segment(subsampledInliers, coefficients);
00816 
00817                 // retrieve cylinder inliers in original point cloud
00818                 PointIndices inlierIndices;
00819 
00820                 for( unsigned int i = 0; i< subsampledInliers.indices.size(); i++ ) {
00821                         int subsampledCloudIndex = subsampledPartCloudIndices->indices[ subsampledInliers.indices[i] ];
00822                         if( cylinderSubsamplingMap.find( subsampledCloudIndex ) == cylinderSubsamplingMap.end() ) {
00823                                 continue;
00824                         }
00825                         copy(cylinderSubsamplingMap[subsampledCloudIndex].begin(), cylinderSubsamplingMap[subsampledCloudIndex].end(), back_inserter(inlierIndices));
00826                 }
00827 
00828                 if(inlierIndices.size() < mParams.mMinPointsInCC){
00829                         ROS_ERROR("RANSAC: no cylinder found, aborting");
00830                         cylinder.reset();
00831                         return;
00832                 }
00833 
00834                 Vec3 pointOnAxis(coefficients.values[0], coefficients.values[1], coefficients.values[2]);
00835                 Vec3 axisDirection(coefficients.values[3], coefficients.values[4], coefficients.values[5]);
00836                 float radius(coefficients.values[6]);
00837                 cylinder.reset(new CylinderPatch(inlierIndices, *pointCloud, pointOnAxis, axisDirection, radius, sacDist));
00838 
00839         }
00840         else {
00841 
00842                 pcl::ExtractIndices<PointT> extract;
00843                 extract.setInputCloud(pointCloud);
00844                 extract.setIndices(partCloudIndices);
00845                 extract.setNegative(false);
00846                 extract.filter(*partCloud);
00847 
00848                 pcl::NormalEstimation<PointT, pcl::Normal> ne;
00849                 ne.setIndices(partCloudIndices);
00850                 ne.setInputCloud (pointCloud);
00851 
00852                 // Create an empty kdtree representation, and pass it to the normal estimation object.
00853                 // Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).
00854                 pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB>);
00855                 tree->setInputCloud (pointCloud);
00856                 ne.setSearchMethod (tree);
00857 
00858                 // Use all neighbors in a sphere of radius ..
00859                 ne.setRadiusSearch (searchRadius);
00860                 ne.setViewPoint(0.f, 0.f, 0.f);
00861 
00862                 ros::Time startTime = ros::Time::now();
00863                 // Compute the features
00864                 ne.compute (*normalCloud);
00865                 ROS_ERROR("ne took %lf", (ros::Time::now()-startTime).toSec());
00866 
00867                 assert(partCloud->points.size() == normalCloud->points.size());
00868 
00869                 pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg;
00870                 seg.setOptimizeCoefficients(false);
00871                 seg.setModelType(pcl::SACMODEL_CYLINDER);
00872                 seg.setMethodType(pcl::SAC_RANSAC);
00873                 seg.setMaxIterations(10000);
00874                 //seg.setDistanceThreshold(sacDist*(1-normalDistanceWeight)+mAngleEps*normalDistanceWeight);
00875                 seg.setDistanceThreshold(sacDist);
00876                 seg.setNormalDistanceWeight(normalDistanceWeight);
00877                 seg.setRadiusLimits (minRadius, maxRadius);
00878                 (void)initialAxis;
00879                 //seg.setAxis(initialAxis);  // scheint die Ergebnisse nicht zu verbessern, die Laufzeit sinkt auch nicht
00880                 //seg.setEpsAngle(2.f * mAngleEps); // TODO do not hardcode 2.f
00881                 seg.setInputCloud(partCloud);
00882                 seg.setInputNormals(normalCloud);
00883                 seg.segment(inliers, coefficients);
00884 
00885                 if(inliers.indices.size() < mParams.mMinPointsInCC){
00886                         ROS_ERROR("RANSAC: no cylinder found, aborting");
00887                         cylinder.reset();
00888                         return;
00889                 }
00890                 PointIndices inlierIndices;
00891                 inlierIndices.reserve(inliers.indices.size());
00892                 for(PointIndices::const_iterator pit = inliers.indices.begin(); pit != inliers.indices.end(); ++pit){
00893                         inlierIndices.push_back(cylinder->getInliers()[*pit]);
00894                 }
00895                 Vec3 pointOnAxis(coefficients.values[0], coefficients.values[1], coefficients.values[2]);
00896                 Vec3 axisDirection(coefficients.values[3], coefficients.values[4], coefficients.values[5]);
00897                 float radius(coefficients.values[6]);
00898                 cylinder.reset(new CylinderPatch(inlierIndices, *pointCloud, pointOnAxis, axisDirection, radius, sacDist));
00899 
00900         }
00901 }
00902 
00903 //TODO THIS DOES NOT WORK YET and should not be used!
00904 void StructureColoring::estimateCylinderFromNodes(NodeIndices& inliers, CylinderPatchPtr& cylinder, const NodePointers& octreeNodes,
00905                 const OcTree& octree, const PointCloudPtr& pointCloud, const float& sacDist, const float& normalDistanceWeight,
00906                 const float& minRadius, const float& maxRadius) {
00907         pcl::ModelCoefficients coefficients;
00908         pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg;
00909         typedef pcl::PointCloud<pcl::Normal> NormalCloud;
00910     NormalCloud::Ptr normalCloud(new NormalCloud());
00911         pclPointIndices partCloudIndices;
00912         PointCloudPtr partCloud;
00913 
00914         partCloud->points.reserve(octreeNodes.size());
00915         normalCloud->points.reserve(octreeNodes.size());
00916         PointT point;
00917         pcl::Normal normal;
00918         for(NodePointers::const_iterator np_it = octreeNodes.begin(); np_it != octreeNodes.end(); ++np_it){
00919                 point.x = (*np_it)->value_.meanPos.x();
00920                 point.y = (*np_it)->value_.meanPos.y();
00921                 point.z = (*np_it)->value_.meanPos.z();
00922                 partCloud->points.push_back(point);
00923                 normal.normal_x = (*np_it)->value_.normal.x();
00924                 normal.normal_y = (*np_it)->value_.normal.y();
00925                 normal.normal_z = (*np_it)->value_.normal.z();
00926                 normalCloud->points.push_back(normal);
00927         }
00928 
00929         seg.setOptimizeCoefficients(true);
00930         seg.setModelType(pcl::SACMODEL_CYLINDER);
00931         seg.setMethodType(pcl::SAC_RANSAC);
00932         seg.setMaxIterations(100);
00933         seg.setDistanceThreshold(sacDist);
00934         seg.setNormalDistanceWeight(0.0f);//normalDistanceWeight);
00935         seg.setRadiusLimits (minRadius, maxRadius);
00936         seg.setInputCloud(partCloud);
00937         seg.setInputNormals(normalCloud);
00938         seg.segment(partCloudIndices, coefficients);
00939 
00940         if(partCloudIndices.indices.size() == 0){
00941                 ROS_ERROR("RANSAC: no cylinder found, aborting");
00942                 cylinder.reset();
00943                 return;
00944         }
00945         Vec3 pointOnAxis(coefficients.values[0], coefficients.values[1], coefficients.values[2]);
00946         Vec3 axisDirection(coefficients.values[3], coefficients.values[4], coefficients.values[5]);
00947         float radius(coefficients.values[6]);
00948         PointIndices inlierIndices;
00949         getAllPointsFromNodes(inlierIndices, partCloudIndices.indices, octreeNodes, octree, *pointCloud);
00950         cylinder.reset(new CylinderPatch(inlierIndices, *partCloud, pointOnAxis, axisDirection, radius, sacDist));
00951 }
00952 
00953 /*****************************************************************************/
00954 
00955 void StructureColoring::generateSingleSphereOctreeHTBins(SphereUniformSamplings& houghBins, SphereBinsVec& pointNeighborBins,
00956                 const NodePointers& octreeNodes) {
00957         houghBins = SphereUniformSamplings(1, SphereUniformSampling(mParams.mPhi_resolution, true));
00958         pointNeighborBins.clear();
00959         pointNeighborBins.resize(octreeNodes.size());
00960         float angleEps = mParams.mAngleEps;
00961         for (unsigned int node = 0; node < octreeNodes.size(); node++) {
00962                 SphereBins neighborBins;
00963                 if (octreeNodes[node]->value_.stable) {
00964                         float curv = octreeNodes[node]->value_.curv / mParams.mCurvThreshold;
00965                         // TODO Use curv to widen the angle used to compute neighborhood as curv is somehow similar to covariance.
00966                         float weight = octreeNodes[node]->value_.numPoints * (1.f - curv);
00967                         const Vec3& n = octreeNodes[node]->value_.normal;
00968                         std::vector<Pair2ui> neighbors;
00969                         houghBins[0].getAllAngleNeighbors(neighbors, n, angleEps);
00970                         for (unsigned int neighbor = 0; neighbor < neighbors.size(); neighbor++) {
00971                                 Vec3 norm = houghBins[0].getNormal(neighbors[neighbor].first, neighbors[neighbor].second);
00972                                 assert((norm.x()!=0)||(norm.y()!=0)||(norm.z()!=0));
00973                                 SphereBin pb;
00974                                 pb.rho = 0;
00975                                 pb.i = neighbors[neighbor].first;
00976                                 pb.j = neighbors[neighbor].second;
00977                                 float scale = std::min(1.f, std::max(0.001f, (fabsf(norm.dot(n)) - fabsf(cos(
00978                                                 angleEps))) / fabsf(cos(angleEps))));
00979                                 houghBins[pb.rho].addPointNoNeighbors(pb.pit, pb.wit, pb.i, pb.j, node, weight * scale);
00980                                 neighborBins.push_back(pb);
00981                         }
00982                 }
00983                 pointNeighborBins[node] = neighborBins;
00984         }
00985 }
00986 
00987 /*****************************************************************************/
00988 
00989 void StructureColoring::estimatePlaneSingleSphereOctreeHT(pclPointIndices& inliers, Plane3DPtr& planePatch,
00990                 const SphereUniformSamplings& houghBins, const SphereBinsVec& pointNeighborBins, const NodePointers& octreeNodes,
00991                 NodeIndices& inlierNodes, const PointCloud& pointCloud, const OcTree& octree, const unsigned int& depth,
00992                 const PlanePatchVector& pointMapping) {
00993         unsigned int imax = 0, jmax = 0;
00994         houghBins[0].getMaximum(imax, jmax);
00995         NodeIndices nodes;
00996         houghBins[0].getPoints(nodes, imax, jmax);
00997         //      ROS_INFO("HT: number nodes in best orientation bin: %zu", nodes.size());
00998 
00999         //get "best" rho/distance:
01000         float HTDistThresh = getHTDistanceFromDepth(depth, octree);
01001         TriangleDistributionHistogram hist(-mParams.mRho_max, mParams.mRho_max, HTDistThresh, mParams.mHTDistanceDeviationFactor * HTDistThresh, pointMapping.size());
01002         Vec3 n(0.f, 0.f, 0.f);
01003         float sumWeight = 0.f;
01004         for (unsigned int p = 0; p < nodes.size(); p++) {
01005                 float weight = 0.f;
01006                 const SphereBins& bins = pointNeighborBins[nodes[p]];
01007                 for (SphereBins::const_iterator sbit = bins.begin(); sbit != bins.end(); ++sbit)
01008                         if (sbit->i == imax && sbit->j == jmax)
01009                                 weight = *(sbit->wit);
01010                 sumWeight += weight;
01011                 n += octreeNodes[nodes[p]]->value_.normal * weight;
01012         }
01013         n /= sumWeight;
01014 
01015         for (unsigned int p = 0; p < nodes.size(); p++) {
01016                 Vec3 pos = octreeNodes[nodes[p]]->value_.meanPos;
01017                 float x = pos.x() * n.x();
01018                 float y = pos.y() * n.y();
01019                 float z = pos.z() * n.z();
01020                 float rho = x + y + z;
01021                 if (rho > mParams.mRho_max)
01022                         ROS_ERROR("HT: Plane out of distance %f(%f)",rho, mParams.mRho_max);
01023                 if (rho < -mParams.mRho_max)
01024                         ROS_ERROR("HT: Plane out of distance %f(%f)", rho, -mParams.mRho_max);
01025                 hist.addDistributedToBins(rho, WeightedIdx(1.f, nodes[p]));
01026         }
01027         //get maximum weighted rho/distance
01028         WeightedIdxVector bestBin;
01029         float bestRho;
01030         CompareWeightedIdxVector compareWeightedIdxVector;
01031         hist.getMaxBin(bestBin, bestRho, compareWeightedIdxVector);
01032 
01033         //get indices of inlier points and nodes
01034         inliers.indices.clear();
01035         inliers.indices.reserve(bestBin.nodeIndices().size());//this is not the size it will have later. now it has enough space for all nodes, not for all points!
01036         inlierNodes.clear();
01037         inlierNodes.reserve(bestBin.nodeIndices().size());
01038         for (unsigned int p = 0; p < bestBin.nodeIndices().size(); p++) {
01039                 inlierNodes.push_back(bestBin.nodeIndices()[p]);
01040                 NodePointers all_nodes;
01041                 octree.getAllLeafs(all_nodes, octreeNodes[bestBin.nodeIndices()[p]]);
01042                 assert(octree.checkOctreeNodes(all_nodes));
01043                 assert(octree.checkOctreeNodes(octreeNodes));
01044                 for (unsigned int node = 0; node < all_nodes.size(); node++) {
01045                         const PointIndices& nodepoints = octree.getPointsFromNodeId(all_nodes[node]->value_.id);
01046                         for (PointIndices::const_iterator point_it = nodepoints.begin(); point_it != nodepoints.end(); ++point_it) {
01047                                 if ((!pointMapping[*point_it])) {
01048                                         inliers.indices.push_back(*point_it);
01049                                 }
01050                         }
01051                 }
01052         }
01053         if (inliers.indices.size() >= 3) {
01054                 Vec3 normal = houghBins[0].getNormal(imax, jmax);
01055                 float distance = bestRho;
01056                 if (distance < 0) {
01057                         distance *= -1.f;
01058                         normal *= -1.f;
01059                 }
01060                 planePatch.reset(new Plane3D(normal, distance));
01061         } else {
01062                 planePatch.reset();
01063                 inliers.indices.clear();
01064         }
01065 }
01066 
01067 /*****************************************************************************/
01070 void StructureColoring::updateHTBins(const NodeIndices& inliers, SphereUniformSamplings& houghBins, SphereBinsVec& pointNeighborBins) {
01071         for (NodeIndices::const_iterator in_it = inliers.begin(); in_it != inliers.end(); ++in_it) {
01072                 const SphereBins& neighborBins = pointNeighborBins[*in_it];
01073                 for (SphereBins::const_iterator nb_it = neighborBins.begin(); nb_it != neighborBins.end(); ++nb_it) {
01074                         assert(nb_it->rho < houghBins.size());
01075                         houghBins[nb_it->rho].deletePointNWeightAt(nb_it->pit, nb_it->wit, nb_it->i, nb_it->j);
01076                 }
01077                 pointNeighborBins[*in_it].clear();
01078         }
01079 }
01080 
01081 /*****************************************************************************/
01082 
01083 void StructureColoring::generateNeighboringNodePairs(NodePairs& nodePairs, NodePointers& octreeNodes,
01084                 const unsigned int neighborhoodSize, const unsigned int& currentOctreeDepth, const OcTree& octree) {
01085         for (NodePointers::iterator node_it = octreeNodes.begin(); node_it
01086                         != octreeNodes.end(); ++node_it) {
01087                 if ((*node_it)->value_.stable) {
01088                         NodePointers neighborNodes;
01089                         //get not yet querried neighboring nodes
01090                         octree.getNeighboringNodes(neighborNodes, *node_it,
01091                                         currentOctreeDepth, (float)neighborhoodSize);
01092                         for (NodePointers::const_iterator neighborNode_it =
01093                                         neighborNodes.begin(); neighborNode_it
01094                                         != neighborNodes.end(); ++neighborNode_it) {
01095                                 if ((*neighborNode_it)->value_.stable) {
01096                                         NodePair pair(*node_it, *neighborNode_it, mParams.mAngleEps);
01097                                         nodePairs.push_back(pair);
01098                                 }
01099                         }
01100                 }
01101                 (*node_it)->value_.nodeQuerried = true;
01102         }
01103 }
01104 
01105 /*****************************************************************************/
01106 
01107 void StructureColoring::generateCylinderOrientationHB(
01108                 SphereUniformSampling& cylinderOrientationBins,
01109                 SphereBinsVec& binNeighborhood, const NodePairs& nodePairs) {
01110         cylinderOrientationBins = SphereUniformSampling(mParams.mPhi_resolution);
01111         binNeighborhood.clear();
01112         binNeighborhood.resize(nodePairs.size());
01113         float angleEps = mParams.mAngleEps;
01114 #pragma omp parallel for schedule(dynamic,1) 
01115         for (unsigned int i = 0; i < nodePairs.size(); ++i) {
01116                 SphereBins neighborBins;
01117                 const Vec3& n = nodePairs[i].getCross();
01118                 // TODO Use curv to widen the angle used to compute neighborhood as curv is somehow similar to covariance.
01119                 float curv = nodePairs[i].getCrossCurv() / mParams.mCurvThreshold;
01120                 float weight = nodePairs[i].getNumPoints() * (1.f - curv);
01121                 std::vector<Pair2ui> neighbors;
01122                 cylinderOrientationBins.getAllAngleNeighbors(neighbors, n, angleEps);
01123                 for (unsigned int neighbor = 0; neighbor < neighbors.size(); neighbor++) {
01124                         Vec3 norm = cylinderOrientationBins.getNormal(
01125                                         neighbors[neighbor].first, neighbors[neighbor].second);
01126                         assert((norm.x()!=0)||(norm.y()!=0)||(norm.z()!=0));
01127                         SphereBin pb;
01128                         pb.rho = 0;
01129                         pb.i = neighbors[neighbor].first;
01130                         pb.j = neighbors[neighbor].second;
01131                         float scale = std::min(1.f, std::max(0.001f, (fabsf(norm.dot(n))
01132                                         - fabsf(cos(angleEps))) / fabsf(cos(angleEps))));
01133 #pragma omp critical
01134                         cylinderOrientationBins.addPointNoNeighbors(pb.pit, pb.wit, pb.i,
01135                                         pb.j, i, weight * scale);
01136                         neighborBins.push_back(pb);
01137                 }
01138                 binNeighborhood[i] = neighborBins;
01139         }
01140 }
01141 
01142 /*****************************************************************************/
01143 
01144 void StructureColoring::estimateCylinderHT(const SphereUniformSampling& cylinderOrientationBins, const NodePairs& nodePairs,
01145                 PairIndices& inlierIndices, CylinderPatchPtr& cylinder, const unsigned int& depth, const OcTree& octree,
01146                 const CylinderPatchVector& pointMapping, const PointCloud& pointCloud, const float& minRadius, const float& maxRadius) {
01147         unsigned int imax = 0, jmax = 0;
01148         cylinderOrientationBins.getMaximum(imax, jmax);
01149         PairIndices pairIndices;
01150         std::vector<float> weights;
01151         cylinderOrientationBins.getPoints(pairIndices, imax, jmax, &weights);
01152 
01153         Vec3 cylinderOrientation(0.f, 0.f, 0.f);
01154         float weightSum = 0.f;
01155         for(PairIndices::const_iterator pairInd_it = pairIndices.begin(); pairInd_it != pairIndices.end();++pairInd_it){
01156                 cylinderOrientation += nodePairs[*pairInd_it].getCross() * weights[pairInd_it-pairIndices.begin()];
01157                 weightSum += weights[pairInd_it-pairIndices.begin()];
01158         }
01159         cylinderOrientation /= weightSum;
01160 
01161         Mat3 transformation;
01162         float cylinderRotationAngle;
01163         Vec3 cylinderRotationAxis;
01164         NodePair2D::get2DTransformation(transformation, cylinderRotationAngle, cylinderRotationAxis, cylinderOrientation);
01165 
01166 //      Vec3 zAxis = transformation * cylinderOrientation;
01167         //1D radius histogram TriangleDistributionHistogram
01168         unsigned int cylinderBins = mParams.mCylinderBins;
01169         float radBinSize = (maxRadius - minRadius) / (float)cylinderBins;
01170         float devFactor = mParams.mRadiusDevFactor;//1,5f;
01171         TriangleDistributionHistogramWithRemove radiusHistogram(minRadius, maxRadius, radBinSize, devFactor * radBinSize, nodePairs.size());
01172         NodePairs2D nodePairs2D;
01173 
01174         //for each stable pair with normal (each pair in vector):
01175         unsigned int radiusPairCounter = 0;
01176         std::vector<int> nodePairIndexFrom2DLookUpTable;
01177         float htDist = getHTDistanceFromDepth(depth, octree);
01178         float sacDist = getSACDistanceFromDepth(depth, octree);
01179         for(PairIndices::const_iterator pairInd_it = pairIndices.begin(); pairInd_it != pairIndices.end();++pairInd_it){
01180                 //project to 2D and calculate 2D circle mid-point and radius
01181                 NodePair2D np2d(nodePairs[*pairInd_it], transformation, sacDist);
01182                 if (np2d.getRadius() < minRadius || np2d.getRadius() > maxRadius || !np2d.stable()) continue;
01183                 nodePairs2D.push_back(np2d);
01184                 radiusHistogram.addDistributedToBins(np2d.getRadius(), WeightedIdx(1.f, radiusPairCounter++));
01185                 nodePairIndexFrom2DLookUpTable.push_back(*pairInd_it);
01186         }
01187 
01188         //get maximum weighted radius
01189         WeightedIdxVector bestRadiusBin;
01190         float bestRadius;
01191 
01192         WeightedIdxVector bestMidPointBin;
01193         float bestMidPointx = 0.f, bestMidPointy = 0.f;
01194 
01195         unsigned int failcounter = 0;
01196         unsigned int triesForOneOrientation = mParams.mTriesOnEachDepth;
01197         do{
01198                 CompareWeightedIdxVector compareWeightedIdxVector;
01199                 radiusHistogram.getMaxBin(bestRadiusBin, bestRadius, compareWeightedIdxVector);
01200 //              ROS_INFO("got bestRadius (%f) from histogram, %zu pairs were in the bin", bestRadius, bestRadiusBin.nodeIndices().size());
01201                 if (bestRadiusBin.nodeIndices().size() < mParams.mMinNodesInCylinder){
01202                         for(PairIndices::const_iterator pairInd_it = pairIndices.begin(); pairInd_it != pairIndices.end();++pairInd_it){
01203                                 inlierIndices.push_back(*pairInd_it);
01204                         }
01205                         cylinder.reset();
01206                         return;
01207                 }
01208                 float midPointBinSizeFactor = mParams.mMidPointBinSizeFactor;//1.f;//0.25f;
01209                 float midPointBinSize = htDist * midPointBinSizeFactor;
01210                 float minMidX = std::numeric_limits<float>::max();
01211                 float minMidY = std::numeric_limits<float>::max();
01212                 float maxMidX = -std::numeric_limits<float>::max();
01213                 float maxMidY = -std::numeric_limits<float>::max();
01214                 for(unsigned int binIndex = 0; binIndex < bestRadiusBin.nodeIndices().size(); ++binIndex){
01215                         assert(binIndex < bestRadiusBin.nodeIndices().size());
01216                         assert((unsigned int)bestRadiusBin.nodeIndices()[binIndex] < nodePairs2D.size());
01217                         const NodePair2D& np2d(nodePairs2D[bestRadiusBin.nodeIndices()[binIndex]]);
01218                         const Eigen::Vector2f& mid = np2d.getCircleMidPoint();
01219                         if(!std::isfinite(mid.x()) || !std::isfinite(mid.y())
01220                                         || mid.x() < -2.f * mParams.mRho_max || mid.x() > 2.f * mParams.mRho_max
01221                                         || mid.y() < -2.f * mParams.mRho_max || mid.y() > 2.f * mParams.mRho_max){
01222                                 continue;
01223                         }
01224                         if (minMidX > mid.x()) minMidX = mid.x();
01225                         if (minMidY > mid.y()) minMidY = mid.y();
01226                         if (maxMidX < mid.x()) maxMidX = mid.x();
01227                         if (maxMidY < mid.y()) maxMidY = mid.y();
01228                 }
01229                 TriangleDistributionHistogram2D midPointHistogram(minMidX, maxMidX, minMidY, maxMidY,
01230                                 midPointBinSize, devFactor   * midPointBinSize);
01231                 unsigned int midpointPairCounter = 0;
01232                 for(unsigned int binIndex = 0; binIndex < bestRadiusBin.nodeIndices().size(); ++binIndex){
01233                         const NodePair2D& np2d(nodePairs2D[bestRadiusBin.nodeIndices()[binIndex]]);
01234 
01235                         const Eigen::Vector2f& mid = np2d.getCircleMidPoint();
01236                         if(!std::isfinite(mid.x()) || !std::isfinite(mid.y())
01237                                         || mid.x() < -2.f * mParams.mRho_max || mid.x() > 2.f * mParams.mRho_max
01238                                         || mid.y() < -2.f * mParams.mRho_max || mid.y() > 2.f * mParams.mRho_max){
01239                                 continue;
01240                         }
01241                         midPointHistogram.addDistributedToBins(np2d.getCircleMidPoint().x(), np2d.getCircleMidPoint().y(), WeightedIdx(1.f, binIndex));
01242                         ++midpointPairCounter;
01243                 }
01244 
01245                 //get maximum weighted mid-point
01246                 midPointHistogram.getMaxBin(bestMidPointBin, bestMidPointx, bestMidPointy, compareWeightedIdxVector);
01247 
01248                 if (bestMidPointBin.nodeIndices().size() < mParams.mMinNodesInCylinder){
01249                         if(failcounter < triesForOneOrientation){
01250 //                      remove all pairs of radius max bin from radius histogram
01251                         radiusHistogram.removeAllFromBin(bestRadius);
01252 //                      re-get max from radius histogram
01253                         } else{
01254                                 for(PairIndices::const_iterator pairInd_it = pairIndices.begin(); pairInd_it != pairIndices.end();++pairInd_it){
01255                                         inlierIndices.push_back(*pairInd_it);
01256                                 }
01257                                 cylinder.reset();
01258                                 return;
01259                         }
01260                 }
01261         }while(bestMidPointBin.nodeIndices().size() < mParams.mMinNodesInCylinder && failcounter++ < triesForOneOrientation);
01262 
01263         //get indices of inlier points and nodes
01264         inlierIndices.clear();
01265         inlierIndices.reserve(2 * bestMidPointBin.nodeIndices().size());//TODO change size reservation! this is not the size it will have later. now it has enough space for all nodes, not for all points!
01266         std::set<NodePtr> nodeSet;
01267         for(NodeIndices::const_iterator idx_it = bestMidPointBin.nodeIndices().begin(); idx_it != bestMidPointBin.nodeIndices().end(); ++idx_it){
01268                 inlierIndices.push_back(nodePairIndexFrom2DLookUpTable[bestRadiusBin.nodeIndices()[*idx_it]]);
01269                 const NodePair& np(nodePairs[nodePairIndexFrom2DLookUpTable[bestRadiusBin.nodeIndices()[*idx_it]]]);
01270                 nodeSet.insert(np.getFirst());
01271                 nodeSet.insert(np.getSecond());
01272         }
01273 
01274         NodePointers inlierNodes;
01275         inlierNodes.reserve(nodeSet.size());
01276         copy(nodeSet.begin(), nodeSet.end(), back_inserter(inlierNodes));
01277         PointIndices pointIndices;
01278         getPointsFromNodes(pointIndices, inlierNodes, octree, pointCloud, pointMapping);
01279 
01280         Mat3 invTrans = transformation.inverse();
01281         Vec3 midPoint2(bestMidPointx, bestMidPointy, 0.f);
01282         Vec3 midPoint3 = invTrans * midPoint2;
01283 
01284         if (pointIndices.size() >= mParams.mMinPointsInCC) {
01285                 cylinder.reset(new CylinderPatch(pointIndices, pointCloud, midPoint3, cylinderOrientation, bestRadius,
01286                                 2.f * getSACDistanceFromDepth(depth, octree)));
01287         } else {
01288                 cylinder.reset();
01289         }
01290 }
01291 
01292 /*****************************************************************************/
01293 
01294 void StructureColoring::updateCylinderHTBins(SphereUniformSampling& cylinderOrientationBins,
01295                 const PairIndices& inlierIndices, SphereBinsVec& binNeighborhood) {
01296         for (PairIndices::const_iterator in_it = inlierIndices.begin(); in_it != inlierIndices.end(); ++in_it) {
01297                 const SphereBins& neighborBins = binNeighborhood[*in_it];
01298                 for (SphereBins::const_iterator nb_it = neighborBins.begin(); nb_it != neighborBins.end(); ++nb_it) {
01299                         cylinderOrientationBins.deletePointNWeightAt(nb_it->pit, nb_it->wit, nb_it->i, nb_it->j);
01300                 }
01301                 binNeighborhood[*in_it].clear();
01302         }
01303 }
01304 
01305 /*****************************************************************************/
01306 
01307 void StructureColoring::getAllPointsFromNodes(PointIndices& pointIndices, const NodePointers& octreeNodes,
01308                 const OcTree& octree, const PointCloud& pointCloud) {
01309         pointIndices.clear();
01310         pointIndices.reserve(pointCloud.points.size());
01311         for (NodePointers::const_iterator node_it = octreeNodes.begin(); node_it != octreeNodes.end(); node_it++) {
01312                 NodePointers leaf_nodes;
01313                 octree.getAllLeafs(leaf_nodes, (*node_it));
01314                 for (NodePointers::const_iterator leaf_it = leaf_nodes.begin(); leaf_it != leaf_nodes.end(); leaf_it++) {
01315                         const PointIndices& points = octree.getPointsFromNodePtr(*leaf_it);
01316                         for (std::vector<int>::const_iterator point_it = points.begin(); point_it != points.end(); point_it++) {
01317                                 pointIndices.push_back(*point_it);
01318                         }
01319                 }
01320         }
01321 }
01322 
01323 /*****************************************************************************/
01324 
01325 void StructureColoring::getAllPointsFromNodes(PointIndices& pointIndices, const NodeIndices& nodeIndices,
01326                 const NodePointers& octreeNodes, const OcTree& octree, const PointCloud& pointCloud) {
01327         pointIndices.clear();
01328         pointIndices.reserve(pointCloud.points.size());
01329         for (NodeIndices::const_iterator node_it = nodeIndices.begin(); node_it != nodeIndices.end(); node_it++) {
01330                 NodePointers leaf_nodes;
01331                 octree.getAllLeafs(leaf_nodes, octreeNodes[*node_it]);
01332                 for (NodePointers::const_iterator leaf_it = leaf_nodes.begin(); leaf_it != leaf_nodes.end(); leaf_it++) {
01333                         const PointIndices& points = octree.getPointsFromNodePtr(*leaf_it);
01334                         for (std::vector<int>::const_iterator point_it = points.begin(); point_it != points.end(); point_it++) {
01335                                 pointIndices.push_back(*point_it);
01336                         }
01337                 }
01338         }
01339 }
01340 
01341 /*****************************************************************************/
01342 
01343 void StructureColoring::addNodesToPlane(PlanePatchPtr& plane, const NodePointers& nodes, const OcTree& octree,
01344                 const PointCloud& pointCloud, PlanePatchVector& pointMapping) {
01345         assert(!nodes.empty());
01346         PointIndices inlierCandidatePoints, inlierPoints;
01347         getPointsFromNodes(inlierCandidatePoints, nodes, octree, pointCloud, pointMapping);
01348         inlierPoints.reserve(inlierCandidatePoints.size());
01349         float xMin = 0.f, xMax = 0.f, yMin = 0.f, yMax= 0.f;
01350         unsigned int xOff = 0, xAdd = 0, yOff = 0, yAdd = 0;
01351         float pointXMin = std::numeric_limits<float>::max();
01352         float pointXMax = -std::numeric_limits<float>::max();
01353         float pointYMin = std::numeric_limits<float>::max();
01354         float pointYMax = -std::numeric_limits<float>::max();
01355         float cellSize = octree.getCellSizeFromDepth((*(nodes.rbegin()))->depth_);
01356         for (PointIndices::const_iterator poInIt = inlierCandidatePoints.begin(); poInIt != inlierCandidatePoints.end(); ++poInIt) {
01357                 if (plane->getPlane3D().checkDistance(pointCloud.points[*poInIt].getVector3fMap(), plane->getDistanceThreshold())){
01358                         inlierPoints.push_back(*poInIt);
01359                         pointMapping[*poInIt] = plane; //new from comment below
01360                         Vec3 tPoint(plane->getPlane3D().transformToXYPlane(pointCloud.points[*poInIt].getVector3fMap()));
01361                         if(tPoint.x() < pointXMin) pointXMin = tPoint.x();
01362                         if(tPoint.x() > pointXMax) pointXMax = tPoint.x();
01363                         if(tPoint.y() < pointYMin) pointYMin = tPoint.y();
01364                         if(tPoint.y() > pointYMax) pointYMax = tPoint.y();
01365                 }
01366         }
01367         //use Points(!) to update grid:
01368         plane->grid()->getNewExtremes(xMin, xMax, yMin, yMax, xOff, xAdd, yOff, yAdd, pointXMin, pointXMax, pointYMin, pointYMax, cellSize);
01369         plane->setGrid(new GridMap((*(plane->grid())), xMin, xMax, yMin, yMax, xOff, xAdd, yOff, yAdd, cellSize));
01370         plane->computeOrientedBoundingBox();
01371         plane->computeBoundingRectangle();
01372         plane->addPoints(inlierPoints, pointCloud);
01373         plane->grid()->blindPopulate(inlierPoints, pointCloud);
01374 }
01375 
01376 /*****************************************************************************/
01377 
01378 void StructureColoring::markNodesAsSegmented(const PlanePatch& pp, const NodePointers& nodes, const OcTree& octree,
01379                 const PointCloud& pointCloud, const float& maxDistance, const float& ratio) {
01380         for (NodePointers::const_iterator np_it = nodes.begin(); np_it != nodes.end(); ++np_it) {
01381                 PointIndices allPointIndices;
01382                 getAllPointsFromNodes(allPointIndices, NodePointers(1, *np_it), octree, pointCloud);
01383                 unsigned int count = 0;
01384                 for (PointIndices::const_iterator point_it = allPointIndices.begin(); point_it != allPointIndices.end(); ++point_it) {
01385                         if (pp.getPlane3D().checkDistance(pointCloud.points[*point_it].getVector3fMap(), maxDistance))
01386                                 ++count;
01387                 }
01388                 if (ratio <= (float) count / (float) allPointIndices.size()) {
01389                         (*np_it)->sweepDown(NULL, StructureColoring::markAsSegmented);
01390                 }
01391         }
01392 }
01393 
01394 /*****************************************************************************/
01395 
01396 void StructureColoring::assignNodesToPlanes(NodePointers& notAssignedOctreeNodes, const unsigned int& octreeDepth,
01397                 const OcTree& octree, PlanePatches& extractedPlanes, const PointCloud& pointCloud, PlanePatchVector& pointMapping) {
01398         NodePtrList notAssignedNodePtrList;
01399         for (NodePointerList::const_iterator node_iter = octree.getNodeListOnDepth(octreeDepth).begin(); node_iter
01400                         != octree.getNodeListOnDepth(octreeDepth).end(); ++node_iter) {
01401                 if ((*node_iter)->value_.stable){
01402                         if (!((*node_iter)->value_.segmented)){
01403                                 notAssignedNodePtrList.push_back(*node_iter);
01404                         }
01405                 }
01406         }
01407         if (!notAssignedNodePtrList.empty()) {
01408                 float cellSize = octree.getCellSizeFromDepth(octreeDepth);
01409                 if (cellSize < mLastCellSizeWithNormals)
01410                         mLastCellSizeWithNormals = cellSize;
01411         }
01412         //sorting is done in main routine before this method is called
01413         for (PlanePatches::iterator planes_iter = extractedPlanes.begin(); planes_iter != extractedPlanes.end(); ++planes_iter) {
01414                 NodePointers nodeCandidates;
01415                 nodeCandidates.reserve(notAssignedNodePtrList.size());
01416                 std::vector<NodePtrList::iterator> nodeCandidateIterators;
01417                 nodeCandidateIterators.reserve(notAssignedNodePtrList.size());
01418                 for (NodePtrList::iterator node_iter = notAssignedNodePtrList.begin(); node_iter != notAssignedNodePtrList.end(); ++node_iter) {
01419                         if ((*planes_iter)->getPlane3D().checkDistance((*node_iter)->value_.meanPos, (*planes_iter)->getDistanceThreshold())
01420                                         && (*planes_iter)->getPlane3D().checkNormal((*node_iter)->value_.normal, getAngleEpsFromDepth(octreeDepth,
01421                                                         octree))) {
01422                                 nodeCandidateIterators.push_back(node_iter);
01423                                 nodeCandidates.push_back(*node_iter);
01424                         }
01425                 }
01426                 if (nodeCandidates.empty())
01427                         continue;
01428                 NodeIndices inlierIndices;
01429                 (*planes_iter)->grid().get()->checkNodesAgainstGridConnection(inlierIndices, nodeCandidates, octree.getCellSizeFromDepth(octreeDepth),
01430                                 std::min(mParams.mMinOctreeNodes, mParams.mMinNodesInCC));
01431                 //erase nodes, that are connected with this plane
01432                 NodePointers inlierNodes;
01433                 inlierNodes.reserve(inlierIndices.size());
01434                 for (NodeIndices::const_iterator in_it = inlierIndices.begin(); in_it != inlierIndices.end(); ++in_it) {
01435                         assert((unsigned int)*in_it < nodeCandidates.size());
01436                         inlierNodes.push_back(nodeCandidates[*in_it]);
01437                         notAssignedNodePtrList.erase(nodeCandidateIterators[*in_it]);
01438                 }
01439                 if (!inlierNodes.empty()) {
01440                         //addPoints to this plane and update mSegmented
01441                         addNodesToPlane(*planes_iter, inlierNodes, octree, pointCloud, pointMapping);
01442                         markNodesAsSegmented(**planes_iter, inlierNodes, octree, pointCloud, getSACDistanceFromDepth(octreeDepth, octree),
01443                                         mParams.mNodeSegmentedRatio);
01444                 }
01445         }
01446         notAssignedOctreeNodes.resize(notAssignedNodePtrList.size());
01447         unsigned int i = 0;
01448         for (NodePtrList::const_iterator noas_iter = notAssignedNodePtrList.begin(); noas_iter != notAssignedNodePtrList.end(); ++noas_iter) {
01449                 notAssignedOctreeNodes[i++] = *noas_iter;
01450         }
01451 }
01452 
01453 /*****************************************************************************/
01454 /*
01455  void StructureColoring::extractOctreePlanesFromCloud(std::vector<SphereUniformSampling>& planeHTBins)
01456  {
01457  für jede Octree-Ebene:
01458  Knoten zu bisherigen Ebenen hinzufügen
01459  Zusammenhang bestimmen -> Ebenen zerteilen
01460  Restliche (gute) Knoten zu neuen Ebenen hinzufügen
01461  Punkte betrachten für RANSAC
01462  schlechte Knoten ignorieren
01463 
01464 
01465  --
01466  neue Ebene:
01467  Hough-Transformation
01468  ConnectedComponents
01469  RANSAC
01470  }
01471  */
01472 void StructureColoring::extractOctreePlanesFromCloud(PlanePatches& extractedPlanes, PlanePatchVector& pointMapping,
01473                 const OcTree& octree, const PointCloudPtr& pointCloud){
01474         //ROS_INFO("octree depth is: %d", mOctreeDepth);
01475         NodePointers octreeNodes;
01476         assert(octree.checkSamplingMap());
01477         assert(octree.checkGetAllLeafs());
01478 
01479         PointCloud histogramPC;
01480         unsigned int maxDepth = octree.getMaxDepth();
01481         unsigned int startDepth = 0;
01482         if (mParams.mDebugSteps >= 0 && (unsigned int) mParams.mDebugSteps <= maxDepth * 2)
01483                 maxDepth = mParams.mDebugSteps / 2;
01484         if(mParams.mOnlyDepth){
01485                 startDepth = mParams.mOnlyDepth;
01486                 maxDepth = mParams.mOnlyDepth;
01487         }
01488         for (unsigned int depth = startDepth; depth <= maxDepth; depth++) {
01489 //ROS_INFO("assign points to planes on depth %d", depth);
01490                 //      for (unsigned int depth = 0; depth <= 5; depth++){//for debug use and picture taking of single steps
01491                 octreeNodes.clear();
01492                 CompArea compArea;
01493                 extractedPlanes.sort(compArea);
01494                 assignNodesToPlanes(octreeNodes, depth, octree, extractedPlanes, *pointCloud, pointMapping);
01495 //ROS_INFO("points assigned to planes on depth %d", depth);
01496                 if (mParams.mOnlyDepth) ROS_INFO("cellsize %f on depth %i", octree.getCellSizeFromDepth(depth), depth);
01497                 if ((mParams.mDebugSteps < 0 || depth != maxDepth || mParams.mDebugSteps & 1) && octreeNodes.size() > mParams.mMinNodesInCC) {
01498                         float sacDist = getSACDistanceFromDepth(depth, octree);
01499 
01500                         SphereUniformSamplings planeHTBins;
01501                         SphereBinsVec pointNeighborhood;
01502                         generateSingleSphereOctreeHTBins(planeHTBins, pointNeighborhood, octreeNodes);
01503 //                      if(depth == 6)
01504                         if (mVis) {
01505 //                              mVis->publishHistogramMarker(planeHTBins[0], .05f, Vec3(0.f, 1.f - 0.125f * depth, 0.f));
01506                                 PointCloud tmpPointCloud;
01507                                 planeHTBins[0].getHistogramAsPointCloud(tmpPointCloud, .1f, Vec3(.5f, 0.5f, 0.f));
01508                                 histogramPC += tmpPointCloud;
01509                         }
01510                         NodeIndices inlierNodes;
01511                         unsigned int failcounter = 0;
01512                         unsigned int numberPoints = 0;
01514                         unsigned int HTCounter = 0;
01516                         do {
01517                                 Plane3DPtr pp;
01518                                 inlierNodes.clear();
01519                                 pclPointIndices planeInliers;
01520                                 estimatePlaneSingleSphereOctreeHT(planeInliers, pp, planeHTBins, pointNeighborhood, octreeNodes, inlierNodes, *pointCloud, octree, depth, pointMapping);
01521                                 //ROS_INFO("PlanePatch normal (%f, %f, %f) and distance (%f) after HT", pp.getPlaneNormal().x(), pp.getPlaneNormal().y(), pp.getPlaneNormal().z(), pp.getPlaneDistanceToOrigin());
01523                                 Vec3 color(Vec3::Zero());
01524                                 if (mParams.mDebugSteps != -1 && depth != maxDepth && mParams.mDebugSteps & 1) {
01525                                         PointIndices HTPointIndices;
01526                                         getAllPointsFromNodes(HTPointIndices, getNodesFromIndices(inlierNodes, octreeNodes), octree, *pointCloud);
01527                                         char app[255];
01528                                         sprintf(app, "HTPlane HT(%d) DEBUG depth(%d)", HTCounter, depth);
01529                                         float rgb[3];
01530                                         RosVisualization::getColorByIndex(rgb, HTCounter, failcounter + 10);
01531                                         color = Vec3(rgb[0], rgb[1], rgb[2]);
01532                                         if (mVis) mVis->publishPoints(getPointsFromIndices(HTPointIndices, *pointCloud), std::string(app), color);
01533                                 }
01535                                 updateHTBins(inlierNodes, planeHTBins, pointNeighborhood);
01536                                 if (inlierNodes.size() < mParams.mMinOctreeNodes) continue;
01537 //ROS_INFO("plane has %zu points before computing CCs", planeInliers.indices.size());
01538                                 if ((pp) && (planeInliers.indices.size() >= mParams.mMinPointsInCC)) {
01539                                         std::vector<NodePointers> CCInliers;
01540                                         NodePointers inlierOctreeNodes;
01541                                         for (NodeIndices::const_iterator in_it = inlierNodes.begin(); in_it != inlierNodes.end(); in_it++) {
01542                                                 inlierOctreeNodes.push_back(octreeNodes[*in_it]);
01543                                         }
01544                                         filterConnectedNodes(CCInliers, *pp, inlierOctreeNodes, octree.getCellSizeFromDepth(depth));
01545 //ROS_INFO("plane has %zu connected Components", CCInliers.size());
01546                                         for (unsigned int cc = 0; cc < CCInliers.size(); cc++) {
01547                                                 //ROS_INFO("PlanePatch normal (%f, %f, %f) and distance (%f) after CCFiltering", planePatchesVec[cc].getPlaneNormal().x(), planePatchesVec[cc].getPlaneNormal().y(), planePatchesVec[cc].getPlaneNormal().z(), planePatchesVec[cc].getPlaneDistanceToOrigin());
01548                         pclPointIndices::Ptr pinliers = boost::make_shared<pclPointIndices>(); // create empty PointIndices and shared_ptr to it
01549                                                 getPointsFromNodes(pinliers->indices, CCInliers[cc], octree, *pointCloud, pointMapping);
01551                                                 if (mParams.mDebugSteps != -1 && depth != maxDepth && mParams.mDebugSteps & 1) {
01552                                                         char nameApp[255];
01553                                                         sprintf(nameApp, "CCPlane CC(%d) DEBUG HT(%d) depth(%d)", cc, HTCounter, depth);
01554                                                         //                                                      float rgb[3];
01555                                                         //                                                      RosVisualization::getColorByIndex(rgb, cc, CCInliers.size());
01556                                                         //                                                      Vec3 color2(rgb[0], rgb[1], rgb[2]);
01557                                                         if (mVis) mVis->publishPoints(getPointsFromIndices(pinliers->indices, *pointCloud), std::string(nameApp),
01558                                                                         color);
01559                                                 }
01560                                                 PointIndices CCIndices = pinliers->indices;
01562                                                 size_t sizeOfInliers = pinliers->indices.size();
01563                                                 if (sizeOfInliers >= mParams.mMinPointsInCC) {
01564                                                         PlanePatchPtr pp2;
01565                                                         //                                                      pp2.reset(new PlanePatch(pp.getPlaneNormal(), pp.getPlaneDistanceToOrigin(), pinliers.indices, mPointCloud));
01566                                                         //ROS_INFO("pp2 normal (%f, %f, %f) and distance (%f) ", pp2->getPlaneNormal().x(), pp2->getPlaneNormal().y(), pp2->getPlaneNormal().z(), pp2->getPlaneDistanceToOrigin());
01567                             if (mParams.mNoRansacStep){
01568                                 const PointIndices& pp1Inliers(pinliers->indices);
01569                                 PointIndices pp2Inliers;
01570                                 pp2Inliers.reserve(pp1Inliers.size());
01571                                 for(PointIndices::const_iterator pis_it = pp1Inliers.begin(); pis_it != pp1Inliers.end(); ++pis_it){
01572                                         Vec3 pis_it_point(pointCloud->points[*pis_it].x, pointCloud->points[*pis_it].y, pointCloud->points[*pis_it].z);
01573                                                                         if(pp->checkDistance(pis_it_point, getHTDistanceFromDepth(depth, octree)))
01574                                                                                 pp2Inliers.push_back(*pis_it);
01575                                 }
01576                                 //generate new pp2!
01577                                 if ((float)pp2Inliers.size() / (float)sizeOfInliers >= mParams.mSACOutlierRatioThreshold){
01578                                         pp2.reset(new PlanePatch(pp->getPlaneNormal(), pp->getPlaneDistanceToOrigin(), pp2Inliers, *pointCloud, getHTDistanceFromDepth(depth, octree)));
01579 //ROS_INFO("pp2 normal (%f, %f, %f) and distance (%f) ", pp2->getPlane3D().getPlaneNormal().x(), pp2->getPlane3D().getPlaneNormal().y(), pp2->getPlane3D().getPlaneNormal().z(), pp2->getPlane3D().getPlaneDistanceToOrigin());
01580                                 }
01581                             } else
01582                                                             estimatePlane(pinliers, pp2, pointCloud, sacDist);
01583                                                         if (pp2 && (pp->checkNormal(pp2->getPlane3D().getPlaneNormal(), 2.f * getAngleEpsFromDepth(depth, octree)))
01584                                                                         && (fabsf(pp->getPlaneDistanceToOrigin() - pp2->getPlane3D().getPlaneDistanceToOrigin()) < 2.f
01585                                                                                         * getHTDistanceFromDepth(depth, octree)) && (pp2->getInliers().size()
01586                                                                         >= mParams.mMinPointsInCC) && (((float) pp2->getInliers().size()) / ((float) sizeOfInliers)
01587                                                                         >= mParams.mSACOutlierRatioThreshold)) {
01588                                                                 markNodesAsSegmented(*pp2, CCInliers[cc], octree, *pointCloud, getSACDistanceFromDepth(depth, octree),
01589                                                                                 mParams.mNodeSegmentedRatio);
01590                                                                 float cellSize = octree.getCellSizeFromDepth(depth);
01591 //ROS_INFO("new grid with blind spots from %zu points", pp2->getInliers().size());
01592                                                                 pp2->newGrid(cellSize);
01593                                                                 pp2->grid()->blindPopulate(pp2->getInliers(), *pointCloud);
01594                                                                 pp2->grid()->calculateStartPos();
01595 //pp2->grid()->print();
01596 //                                                              if (mDebugSteps < 0 || depth <= maxDepth) {
01597                                                                         extractedPlanes.push_front(pp2);
01598 //                                                              }
01599                                                                 numberPoints += pp2->getInliers().size();
01601                                                                 if (mParams.mDebugSteps != -1 && depth != maxDepth && mParams.mDebugSteps & 1) {
01602                                                                         char nameApp[255];
01603                                                                         sprintf(nameApp, "Plane b.R. CC(%d) DEBUG HT(%d) depth(%d)", cc, HTCounter, depth);
01604                                                                         PointIndices pointIndices;
01605                                                                         sort(CCIndices.begin(), CCIndices.end());
01606                                                                         PointIndices planePointIndices = pp2->getInliers();
01607                                                                         sort(planePointIndices.begin(), planePointIndices.end());
01608                                                                         set_difference(CCIndices.begin(), CCIndices.end(), planePointIndices.begin(),
01609                                                                                         planePointIndices.end(), std::back_inserter(pointIndices));
01610                                                                         Vec3 color2 = Vec3(1.f, 0.f, 0.f);
01611                                                                         if (mVis) mVis->publishPoints(getPointsFromIndices(pointIndices, *pointCloud),
01612                                                                                         std::string(nameApp), color2);
01613 
01614                                                                         char name[255];
01615                                                                         sprintf(name, "RANSACPlane CC(%d) DEBUG HT(%d) depth(%d)", cc, HTCounter, depth);
01616                                                                         color2 = Vec3(0.f, 1.f, 0.1f);
01617                                                                         if (mVis) mVis->publishPoints(getPointsFromIndices(pp2->getInliers(), *pointCloud), std::string(
01618                                                                                         name), color2);
01619                                                                 }
01621 //                                                              if (mDebugSteps < 0 || depth <= maxDepth) {
01622                                                                         for (PointIndices::const_iterator in_it = pp2->getInliers().begin(); in_it
01623                                                                                         != pp2->getInliers().end(); in_it++) {
01624                                                                                 pointMapping[*in_it] = pp2;
01625                                                                         }
01626 //                                                              }
01627 //ROS_ERROR("plane: added plane patch (%zu with %zu points) to collection. normal = (%f, %f, %f), distance = %f", extractedPlanes.size()-1 , pp2->getInliers().size(), pp2->getPlane3D().getPlaneNormal().x(), pp2->getPlane3D().getPlaneNormal().y(), pp2->getPlane3D().getPlaneNormal().z(), pp2->getPlane3D().getPlaneDistanceToOrigin());
01628                                                         }
01629                                                 }
01630                                         }
01631                                 }
01633                                 HTCounter++;
01635                         } while (((inlierNodes.size() >= mParams.mMinOctreeNodes) && (numberPoints > mParams.mMinPointsInCC)) || (failcounter++
01636                                         < mParams.mTriesOnEachDepth));
01637                         //                      break;
01638                 }//uncomment to speed-up as above
01639         }
01640         if (mVis) {
01641                 mVis->publishHTBinCloud(histogramPC);
01642         }
01643 }
01644 
01645 /*****************************************************************************/
01646 
01647 void StructureColoring::assignNodesToCylinders(NodePointers& octreeNodes, CylinderPatches& extractedCylinders,
01648                 CylinderPatchVector& pointMapping, const OcTree& octree, const PointCloud& pointCloud){
01649         typedef std::list<NodePtr> NodeList;
01650         typedef std::vector<NodeList::iterator> NodeListIterators;
01651         NodeList nodeList;
01652     std::copy(octreeNodes.begin(), octreeNodes.end(), std::back_inserter(nodeList));
01653         for(CylinderPatches::iterator cit = extractedCylinders.begin(); cit != extractedCylinders.end(); ++cit){
01654                 NodePointers nodesToAdd;
01655                 NodeListIterators nodesToBeErased;
01656                 for(NodeList::iterator node_it = nodeList.begin(); node_it != nodeList.end(); ++node_it){
01657                         if((*cit)->checkDistance((*node_it)->value_.meanPos)
01658                                         && (*cit)->checkNormal((*node_it)->value_.normal, (*node_it)->value_.meanPos, mParams.mAngleEps)
01659                                         && (*cit)->checkHeight((*node_it)->value_.meanPos, mParams.mCylinderHeightDev))
01660             {
01661                                 nodesToAdd.push_back(*node_it);
01662                                 nodesToBeErased.push_back(node_it);
01663                         }
01664                 }
01665                 for(NodeListIterators::const_iterator nit_it = nodesToBeErased.begin(); nit_it != nodesToBeErased.end(); ++nit_it){
01666                         nodeList.erase(*nit_it);
01667                 }
01668                 PointIndices pointIndicesToAdd;
01669                 getPointsFromNodes(pointIndicesToAdd, nodesToAdd, octree, pointCloud, pointMapping);
01670                 updatePointMapping(pointMapping, pointIndicesToAdd, *cit);
01671                 (*cit)->addPoints(pointIndicesToAdd, pointCloud);
01672         }
01673         octreeNodes.clear();
01674     std::copy(nodeList.begin(), nodeList.end(), std::back_inserter(octreeNodes));
01675 }
01676 
01677 /*****************************************************************************/
01678 
01679 void StructureColoring::extractOctreeCylindersFromCloud(CylinderPatches& extractedCylinders, CylinderPatchVector& pointMapping,
01680                 const OcTree& octree, const PointCloudPtr& pointCloud){
01681         NodePointers octreeNodes;
01682         unsigned int startDepth = 0;
01683         unsigned int maxDepth = octree.getMaxDepth();
01684         unsigned int cylinderPairNeighborhoodSize = mParams.mCylinderPairNeighbors;
01685         if (mParams.mDebugSteps >= 0 && (unsigned int) mParams.mDebugSteps <= maxDepth * 2)
01686                 maxDepth = mParams.mDebugSteps / 2;
01687         PointCloud histogramPC;
01688         if(mParams.mOnlyDepth){
01689                 startDepth = mParams.mOnlyDepth;
01690                 maxDepth = mParams.mOnlyDepth;
01691         }
01692         for (unsigned int depth = startDepth; depth <= maxDepth; depth++) 
01693     {
01694                 float sacDist = getSACDistanceFromDepth(depth, octree);
01695                 float minRadius = 0.f, maxRadius = 0.f;
01696                 getMinMaxRadiusFromDepth(minRadius, maxRadius, octree, depth);
01697                 ROS_INFO("minRadius = %f, maxRadius = %f", minRadius, maxRadius);
01698                 SphereUniformSampling cylinderOrientationBins(mParams.mPhi_resolution);
01699                 SphereBinsVec binNeighborhood;
01700                 NodePairs nodePairs;
01701                 octreeNodes.clear();
01702                 octreeNodes = octree.getNodesOnDepth(depth);
01703         size_t nrNodesOnDepth = octreeNodes.size();
01704                 if(octreeNodes.size() < mParams.mMinNodesInCylinder) continue;
01705                 assignNodesToCylinders(octreeNodes, extractedCylinders, pointMapping, octree, *pointCloud);
01706                 if(octreeNodes.size() < mParams.mMinNodesInCylinder) continue;
01707                 generateNeighboringNodePairs(nodePairs, octreeNodes, cylinderPairNeighborhoodSize, depth, octree);
01708                 if(mVis){
01709                         mVis->publishPairMarker(nodePairs);
01710                 }
01711                 ROS_INFO("depth %d: %zu cylinders, %zu octreeNodes, %zu not assigned, %zu node pairs", depth, extractedCylinders.size(), nrNodesOnDepth, octreeNodes.size(), nodePairs.size());
01712                 if (nodePairs.size() < mParams.mMinNodesInCylinder) continue;
01713                 generateCylinderOrientationHB(cylinderOrientationBins, binNeighborhood, nodePairs);
01714 //              ROS_INFO("cylinder orientation histogram generated, binNeighborhood has %zu entries", binNeighborhood.size());
01715 
01716                 if (mVis) {
01717                         PointCloud tmpPointCloud;
01718                         cylinderOrientationBins.getHistogramAsPointCloud(tmpPointCloud, .05f, Vec3(-.5f, 1.f - 0.125f * depth, 0.f));
01719                         histogramPC += tmpPointCloud;
01720                 }
01721 
01722                 unsigned int failcounter = 0;
01723                 unsigned int numberPoints;
01724 //              float htDist = getHTDistanceFromDepth(depth, octree);
01725 
01726                 PairIndices pairIndices;
01727                 do{
01728 //                      ROS_ERROR("starting new cylinder HT (max orientation extraction), %d fails yet", failcounter);
01729                         numberPoints = 0;
01730                         CylinderPatchPtr cylinder;
01731                         NodePointers nodePointers;
01732                         pairIndices.clear();
01733                         estimateCylinderHT(cylinderOrientationBins, nodePairs, pairIndices, cylinder, depth, octree, pointMapping, *pointCloud, minRadius, maxRadius);
01734                         updateCylinderHTBins(cylinderOrientationBins, pairIndices, binNeighborhood);
01735                         if(!cylinder || pairIndices.size() < mParams.mMinOctreeNodes || (!checkCylinderDimensions(cylinder))){
01736                                 continue;
01737                         }
01738                         Vec3 htAxisDirection(cylinder->getAxisDirection());
01739                         Vec3 htMidPoint(cylinder->getMidPoint());
01740                         float htRadius(cylinder->getRadius());
01741                         float cellSize(octree.getCellSizeFromDepth(depth));
01742                         //filterCylinderConnectedNodes();
01743                         unsigned int htNumPoints = cylinder->getInliers().size();
01744             if (!mParams.mNoRansacStep)
01745             {
01746                 estimateCylinderNNNormals(cylinder, pointCloud, sacDist, mParams.mNormalDistanceWeight,
01747                                 0.001, 10.0,
01748                                 1.0*cellSize, htAxisDirection);
01749                 if (!cylinder){
01750                     ROS_WARN("estimateCylinderNNNormals() removed cylinder");
01751                     continue;
01752                 }
01753                 //some check helper
01754                 float cosAngle = htAxisDirection.dot(cylinder->getAxisDirection());
01755                 //ransac result similar to ht result check
01756 
01757                 if(fabsf(cosAngle) < cosf(2.f * mParams.mAngleEps)) {
01758                     ROS_WARN("results of HT and RANSAC were too different (angle) %f %f", fabsf(cosAngle), cosf(2.f * mParams.mAngleEps) );
01759                     continue;
01760                 }
01761 
01762                 if(cylinder->getRadius() / htRadius > 2 || htRadius / cylinder->getRadius() > 2) {
01763                     ROS_WARN("results of HT and RANSAC were too different (radius) %f", cylinder->getRadius() / htRadius );
01764                     continue;
01765                 }
01766 
01767                 if((cylinder->getInliers().size() < htNumPoints * mParams.mSACOutlierRatioThreshold)){
01768                     ROS_WARN("results of HT and RANSAC were too different (num inliers)");
01769                     continue;
01770                 }
01771             }
01772             if (!checkCylinder(cylinder, pointCloud)){
01773                 ROS_WARN("not enough area on cylinder");
01774                 continue;
01775             }
01776                         updatePointMapping(pointMapping, cylinder->getInliers(), cylinder);
01777                         extractedCylinders.push_back(cylinder);
01778                         numberPoints = cylinder->getInliers().size();
01779                 } while (((pairIndices.size() >= mParams.mMinOctreeNodes) && (numberPoints > mParams.mMinPointsInCC)) || (failcounter++ < mParams.mTriesOnEachDepth));
01780                 ROS_INFO("no more cylinders on depth %d", depth);
01781         }
01782         ROS_INFO("cylinder HT completed for all depths");
01783         if(mVis){
01784                 mVis->publishHTBinCloud(histogramPC);
01785         }
01786 }
01787 
01788 /*****************************************************************************/
01789 
01790 void StructureColoring::getNodesFromPairs(NodePointers& nodePointers, const PairIndices& pairIndices, const NodePairs& nodePairs){
01791         nodePointers.reserve(pairIndices.size() * 2);
01792         for(PairIndices::const_iterator pair_it = pairIndices.begin(); pair_it != pairIndices.end(); ++pair_it){
01793                 nodePointers.push_back(nodePairs[*pair_it].getFirst());
01794                 nodePointers.push_back(nodePairs[*pair_it].getSecond());
01795         }
01796 }
01797 
01798 /*****************************************************************************/
01799 
01800 void StructureColoring::determineCandidatePlanes(NodeIndexToPlanePatchPointers& nodeToPlaneCandidates,
01801                 const NodePointers& octreeNodes, PlanePatches& extractedPlanes) {
01802 #pragma omp parallel for schedule(dynamic,1)
01803         for (size_t nodeCount = 0; nodeCount < octreeNodes.size(); ++nodeCount) {
01804                 for (PlanePatches::iterator planes_iter = extractedPlanes.begin(); planes_iter != extractedPlanes.end(); ++planes_iter) {
01805                         if ((*planes_iter)->getPlane3D().checkDistance(octreeNodes[nodeCount]->value_.meanPos,
01806                                         (*planes_iter)->getDistanceThreshold()))
01807                         {
01808                                 const Vec3& nodeCoG = octreeNodes[nodeCount]->value_.meanPos;
01809                                 if (((*planes_iter)->distanceToOBB(nodeCoG) < std::sqrt((*planes_iter)->getArea()) * mParams.mNodeToBBDistance))
01810                                 {
01811                                         if((*planes_iter)->checkPointConnection(nodeCoG, mParams.mConnectionNeighbors))
01812                                         {
01813                                                 nodeToPlaneCandidates[nodeCount].push_back(*planes_iter);
01814                                         }
01815                                 }
01816                         }
01817                 }
01818         }
01819 }
01820 
01821 /*****************************************************************************/
01822 
01823 void StructureColoring::determineCandidatePlanes(PatchToNodeIndicesMap& outIndicesMap,
01824                 PatchToNodePointersMap& outPointersMap, const NodePointers& octreeNodes, PlanePatches& extractedPlanes) {
01825         // reserve memory:
01826         for (PlanePatches::iterator planes_iter = extractedPlanes.begin(); planes_iter != extractedPlanes.end(); ++planes_iter) {
01827                 unsigned int possSize = std::min(octreeNodes.size(), (*planes_iter)->getInliers().size());
01828                 outIndicesMap[*planes_iter].reserve(possSize);
01829                 outPointersMap[*planes_iter].reserve(possSize);
01830         }
01831         // determine candidates:
01832         for (size_t nodeCount = 0; nodeCount < octreeNodes.size(); ++nodeCount) {
01833                 for (PlanePatches::iterator planes_iter = extractedPlanes.begin(); planes_iter != extractedPlanes.end(); ++planes_iter) {
01834                         if ((*planes_iter)->getPlane3D().checkDistance(octreeNodes[nodeCount]->value_.meanPos,
01835                                         (*planes_iter)->getDistanceThreshold())) {
01836                                 outIndicesMap[*planes_iter].push_back(nodeCount);
01837                                 outPointersMap[*planes_iter].push_back(octreeNodes[nodeCount]);
01838                         }
01839                 }
01840         }
01841 }
01842 
01843 /*****************************************************************************/
01844 
01845 void StructureColoring::refineAssignmentWithCCs(NodeIndexToPlanePatchPointers& nodeToPlaneCandidates,
01846                 const PatchToNodeIndicesMap& nodeIndicesMap, const PatchToNodePointersMap& nodePointersMap,
01847                 const NodePointers& octreeNodes, PlanePatches& extractedPlanes) {
01848         for (PlanePatches::iterator planes_iter = extractedPlanes.begin(); planes_iter != extractedPlanes.end(); ++planes_iter) {
01849                 const NodePointers& nodePointers = nodePointersMap.find(*planes_iter)->second;
01850                 size_t nodeCount = 0;
01851                 for (NodePointers::const_iterator nit = nodePointers.begin(); nit != nodePointers.end(); ++nit) {
01852                         const Vec3& nodeCoG = (*nit)->value_.meanPos;
01853                         if ((*planes_iter)->distanceToOBB(nodeCoG) < std::sqrt((*planes_iter)->getArea()) * mParams.mNodeToBBDistance
01854                                         && (*planes_iter)->checkPointConnection(nodeCoG, mParams.mConnectionNeighbors)) {
01855                                 const NodeIndices& nodeIndices = nodeIndicesMap.find(*planes_iter)->second;
01856                                 nodeToPlaneCandidates[nodeIndices[nodeCount]].push_back(*planes_iter);
01857                         }
01858                         ++nodeCount;
01859                 }
01860         }
01861 }
01862 
01863 /*****************************************************************************/
01864 
01865 void StructureColoring::calculateMiddlePlane(Plane3D& outParams, const PlanePatch& firstPPP,
01866                 const PlanePatch& secondPPP) {
01867         Vec3 viewport(Vec3::Zero());
01868         Vec3 p1Norm = firstPPP.getPlane3D().getPlaneNormal();
01869         flipToViewport(p1Norm, firstPPP.getPlaneCoG() - viewport);
01870         Vec3 p2Norm = secondPPP.getPlane3D().getPlaneNormal();
01871         flipToViewport(p2Norm, secondPPP.getPlaneCoG() - viewport);
01872         Vec3 tang1(p2Norm.cross(p1Norm));
01873         Vec3 tang2((p1Norm + p2Norm));
01874         tang2.normalize();
01875         Vec3 normal = tang1.cross(tang2);
01876         normal.normalize();
01877         Vec3 v = tang1.cross(p1Norm);
01878         Vec3 pointOnPlane(firstPPP.getPlane3D().getOrthogonalProjectionOntoPlane(firstPPP.getPlaneCoG()));
01879         float lambda = (secondPPP.getPlane3D().getPlaneDistanceToOrigin() - pointOnPlane.dot(secondPPP.getPlane3D().getPlaneNormal()))
01880                         / secondPPP.getPlane3D().getPlaneNormal().dot(v);
01881         Vec3 pointOnLineOfIntersection(pointOnPlane + lambda * v);
01882         if (pointOnLineOfIntersection.dot(normal) < 0) {
01883                 normal *= -1.f;
01884         }
01885         outParams.setPlaneNormal(normal);
01886         outParams.setPlaneDistanceToOrigin(pointOnLineOfIntersection.dot(normal));
01887 }
01888 
01889 /*****************************************************************************/
01890 
01891 void StructureColoring::refineEdges(PatchToNodePointersMap& finalPlaneNodeAssignmentMap,
01892                 PatchToPointIndicesMap& finalPlanePointAssignmentMap, const NodeIndexToPlanePatchPointers& nodeToPlaneCandidates,
01893                 const NodePointers& octreeNodes, const OcTree& octree, const PointCloud& pointCloud) {
01894         typedef std::pair<PlanePatchPtr, PlanePatchPtr> PlanePatchPointerPair;
01895         typedef std::map<PlanePatchPointerPair, Plane3D, CompPlanePtrPair> MiddlePlaneMap;
01896         typedef std::map<PlanePatchPointerPair, PointIndices, CompPlanePtrPair> MiddlePlaneIndicesMap;
01897         MiddlePlaneMap middlePlaneMap;
01898         MiddlePlaneIndicesMap middlePlaneIndicesMap;
01899         size_t nodeIndex = 0;
01900         for (NodeIndexToPlanePatchPointers::const_iterator node_idx_it = nodeToPlaneCandidates.begin(); node_idx_it
01901                         != nodeToPlaneCandidates.end(); ++node_idx_it) {
01902                 if (node_idx_it->size() > 1) {//node has more than one possible Plane
01903                         PointIndices pointIndices;
01904                         getAllPointsFromNodes(pointIndices, NodePointers(1, octreeNodes[nodeIndex]), octree, pointCloud);
01905                         for (PointIndices::const_iterator point_it = pointIndices.begin(); point_it != pointIndices.end(); ++point_it) {
01906                                 PlanePatchPtr firstPPP, secondPPP;
01907                                 float firstDist = std::numeric_limits<float>::max(), secondDist = std::numeric_limits<float>::max();
01908                                 for (PlanePatchVector::const_iterator pp_it = node_idx_it->begin(); pp_it != node_idx_it->end(); ++pp_it) {
01909                                         float currDist = (*pp_it)->getPlane3D().distance(octreeNodes[nodeIndex]->value_.meanPos);
01910                                         if (currDist <= firstDist) {
01911                                                 secondDist = firstDist;
01912                                                 secondPPP = firstPPP;
01913                                                 firstPPP = *pp_it;
01914                                                 firstDist = currDist;
01915                                         } else if (currDist <= secondDist) {
01916                                                 secondPPP = *pp_it;
01917                                                 secondDist = currDist;
01918                                         }
01919                                 }
01920                                 //look for middle plane in map
01921                                 bool notInList = true;
01922                                 PlanePatchPointerPair pppp(std::make_pair(firstPPP, secondPPP));
01923                                 PlanePatchPointerPair ppppSwap(std::make_pair(secondPPP, firstPPP));
01924                                 MiddlePlaneMap::iterator mpm_it = middlePlaneMap.find(pppp);
01925                                 MiddlePlaneMap::iterator mpmSwap_it = middlePlaneMap.find(ppppSwap);
01926                                 if (mpm_it != middlePlaneMap.end()) {
01927                                         notInList = false;
01928                                 } else if (mpmSwap_it != middlePlaneMap.end()) {
01929                                         notInList = false;
01930                                         mpm_it = mpmSwap_it;
01931                                         pppp = ppppSwap;
01932                                 }
01933                                 Plane3D planeParams;
01934                                 if (notInList) {
01935                                         //generate new middle plane
01936                                         calculateMiddlePlane(middlePlaneMap[pppp], *firstPPP, *secondPPP);
01937                                         planeParams = middlePlaneMap.find(pppp)->second;
01938                                         //                                      calculateMiddlePlane(params, firstPPP, secondPPP);
01939                                         //                                      middlePlaneMap.find(pppp)->second = params;
01940                                         if (middlePlaneIndicesMap.find(pppp) != middlePlaneIndicesMap.end()) {
01941                                                 middlePlaneIndicesMap.find(pppp)->second.push_back(*point_it);
01942                                         } else {
01943                                                 middlePlaneIndicesMap[pppp] = PointIndices(1, *point_it);
01944                                         }
01945                                 } else {
01946                                         //get "old" middle plane params
01947                                         planeParams = mpm_it->second;
01948                                         PointIndices pointIndices;
01949                                         getAllPointsFromNodes(pointIndices, NodeIndices(1, nodeIndex), octreeNodes, octree, pointCloud);
01950                                         if (middlePlaneIndicesMap.find(pppp) != middlePlaneIndicesMap.end()) {
01951                                                 middlePlaneIndicesMap.find(pppp)->second.push_back(*point_it);
01952                                         } else {
01953                                                 middlePlaneIndicesMap[pppp] = PointIndices(1, *point_it);
01954                                         }
01955                                 }
01956                                 //decide on which side of the middleplane the points mean lies
01957 
01958                                 if (planeParams.signedDistance(firstPPP->getPlaneCoG()) * planeParams.signedDistance(secondPPP->getPlaneCoG()) > 0) {
01959                                         //special T-Case (both cog on the same side of middleplane)
01960                                         //1-prefer "first" plane in pair - this may look random
01961                                         //                                      if(pppp.first->signedDistance(PlanePatch::getEigenVecFromPCL(mPointCloud.points[*point_it]))
01962                                         //                                                      * pppp.first->signedDistance(pppp.second->getPlaneCoG()) > 0)
01963                                         //                                              finalPlanePointAssignmentMap[firstPPP].push_back(*point_it);
01964                                         //                                      else finalPlanePointAssignmentMap[pppp.first].push_back(*point_it);
01965                                         //2-prefer small distance
01966                                         finalPlanePointAssignmentMap[firstPPP].push_back(*point_it);
01967                                 } else {
01968 
01969                                         if (planeParams.signedDistance(firstPPP->getPlaneCoG()) < 0.f) {
01970                                                 if (planeParams.signedDistance(pointCloud.points[*point_it].getVector3fMap()) < 0.f) {
01971                                                         finalPlanePointAssignmentMap[firstPPP].push_back(*point_it);
01972                                                 } else
01973                                                         finalPlanePointAssignmentMap[secondPPP].push_back(*point_it);
01974                                         } else {
01975                                                 if (planeParams.signedDistance(pointCloud.points[*point_it].getVector3fMap()) > 0.f) {
01976                                                         finalPlanePointAssignmentMap[firstPPP].push_back(*point_it);
01977                                                 } else
01978                                                         finalPlanePointAssignmentMap[secondPPP].push_back(*point_it);
01979                                         }
01980                                 }
01981                         }
01982                 } else {
01983                         if (node_idx_it->size() == 1) {//node has exactly one plane candidate, that it my lie in
01984                                 //assign node to plane
01985                                 finalPlaneNodeAssignmentMap[*(node_idx_it->begin())].push_back(octreeNodes[nodeIndex]);
01986                         }
01987                         //no plane candidate -> no assignment for this node!
01988                 }
01989                 nodeIndex++;
01990         }
01991         PlanePatches planes;
01992         for (MiddlePlaneMap::const_iterator mapit = middlePlaneMap.begin(); mapit != middlePlaneMap.end(); ++mapit) {
01993                 const Plane3D& params = mapit->second;
01994                 PointIndices pointIndices;
01995                 MiddlePlaneIndicesMap::const_iterator mpimIt = middlePlaneIndicesMap.find(mapit->first);
01996                 if (mpimIt != middlePlaneIndicesMap.end())
01997                         pointIndices = mpimIt->second;
01998                 if (pointIndices.size() > 3) {
01999                         PlanePatchPtr plane(new PlanePatch(params.getPlaneNormal(), params.getPlaneDistanceToOrigin(), pointIndices, pointCloud,
02000                                         getSACDistanceFromDepth(octree.getMaxDepth(), octree)));
02001                         planes.push_back(plane);
02002                 }
02003         }
02004         if (mVis) mVis->publishPlaneMarker(planes, "middleplane");
02005 }
02006 
02007 /*****************************************************************************/
02008 
02009 void StructureColoring::spreadNodes(const OcTree& octree, PlanePatches& extractedPlanes, PlanePatchVector& pointMapping,
02010                 const PointCloud& pointCloud) {
02011         const NodePointers& octreeNodes = octree.getNodesOnDepth(octree.getMaxDepth());
02012         NodeIndexToPlanePatchPointers nodeToPlaneCandidates(octreeNodes.size());
02013 
02014         //determine candidate planes for each node (saved in nodePointersMap)
02015         //check against distance only
02016         PatchToNodePointersMap nodePointersMap;
02017         PatchToNodeIndicesMap nodeIndicesMap;
02018         //determineCandidatePlanes(nodeIndicesMap, nodePointersMap, octreeNodes);
02019 
02020         //refine node-to-plane multi-assignment through CC-filtering
02021         //save results in nodeToPlaneCandidates(n* -> p*)
02022         determineCandidatePlanes(nodeToPlaneCandidates, octreeNodes, extractedPlanes);
02023 
02024         //decide for each node, which planes are the best candidates and generate middleplane (if not already in map)
02025         //refine edges with middle plane sign check
02026         PatchToNodePointersMap finalPlaneNodeAssignmentMap;
02027         PatchToPointIndicesMap finalPlanePointAssignmentMap;
02028         refineEdges(finalPlaneNodeAssignmentMap, finalPlanePointAssignmentMap, nodeToPlaneCandidates, octreeNodes, octree, pointCloud);
02029 
02030         // reset mSegmented to false
02031         for (PlanePatchVector::iterator seg_iter = pointMapping.begin(); seg_iter != pointMapping.end(); ++seg_iter)
02032                 seg_iter->reset();
02033 
02034         PlanePatches newPlanes;
02035         // add point-vectors to planes update mSegmented
02036         for (PatchToNodePointersMap::iterator it = finalPlaneNodeAssignmentMap.begin(); it != finalPlaneNodeAssignmentMap.end(); ++it) {
02037                 const PlanePatch& pRef = *(it->first);
02038                 PointIndices inliers;
02039                 getAllPointsFromNodes(inliers, it->second, octree, pointCloud);
02040                 PatchToPointIndicesMap::iterator pointIndicesMap_it = finalPlanePointAssignmentMap.find(it->first);
02041                 if (pointIndicesMap_it != finalPlanePointAssignmentMap.end()) {
02042                         inliers.reserve(inliers.size() + pointIndicesMap_it->second.size());
02043                         for (PointIndices::const_iterator point_indices_it = pointIndicesMap_it->second.begin(); point_indices_it
02044                                         != pointIndicesMap_it->second.end(); ++point_indices_it)
02045                                 inliers.push_back(*point_indices_it);
02046                 }
02047                 if (inliers.size() > mParams.mMinPointsInCC) {
02048                         PlanePatchPtr ppp(new PlanePatch(inliers, pointCloud, pRef.getDistanceThreshold()));
02049                         if (ppp) {
02050                                 ppp->newGrid(octree.getCellSizeFromDepth(octree.getMaxDepth()));
02051                                 ppp->grid()->blindPopulate(inliers, pointCloud);
02052                                 ppp->grid()->calculateStartPos();
02053                                 newPlanes.push_back(ppp);
02054                         }
02055                 }
02056         }
02057         extractedPlanes.clear();
02058         addPlanePatchesAndUpdateSegmented(extractedPlanes, pointMapping, newPlanes);
02059 }
02060 
02061 /*****************************************************************************/
02068 void StructureColoring::mergePlanes(PlanePatches& extractedPlanes, PlanePatchVector& pointMapping, const PointCloud& pointCloud) {
02069         PlanePatches merged;
02070         CompArea compArea;
02071         extractedPlanes.sort(compArea);
02072         PlanePatches::iterator plane_it_it = extractedPlanes.begin();
02073         while (plane_it_it != extractedPlanes.end()) {
02074                 float sacDist = (*plane_it_it)->getDistanceThreshold();
02075                 std::vector<PlanePatches::iterator> mergeWithPlane;
02076                 for (PlanePatches::iterator filteredPlane_it = extractedPlanes.begin(); filteredPlane_it
02077                                 != extractedPlanes.end(); filteredPlane_it++) {
02078                         if (filteredPlane_it != plane_it_it) {
02079                                 sacDist = std::max((*filteredPlane_it)->getDistanceThreshold(), sacDist);
02080                                 if (((*plane_it_it)->getPlane3D().checkNormal((*filteredPlane_it)->getPlane3D().getPlaneNormal(),
02081                                                 mParams.mMergePlanesSimilarityFactor * mParams.mAngleEps))
02082                                                 && (*plane_it_it)->getPlane3D().checkDistance((*filteredPlane_it)->getPlaneCoG(), mParams.mMergePlanesSimilarityFactor * sacDist)
02083                                                 && (*filteredPlane_it)->getPlane3D().checkDistance((*plane_it_it)->getPlaneCoG(), mParams.mMergePlanesSimilarityFactor * sacDist)) {
02084                                         if (planesAreConnected(**plane_it_it, **filteredPlane_it, pointCloud)) {
02085                                                 mergeWithPlane.push_back(filteredPlane_it);
02086                                         }
02087                                 }
02088                         }
02089                 }
02090                 if (!mergeWithPlane.empty()) {
02091                         pclPointIndices pinliers, outInliers;
02092                         pinliers.indices = (*plane_it_it)->getInliers();
02093                         std::sort(pinliers.indices.begin(), pinliers.indices.end());
02094                         float cellSize = (*plane_it_it)->grid()->getCellSize();
02095                         for (unsigned int i = 0; i < mergeWithPlane.size(); i++) {
02096                                 cellSize = std::min(cellSize, (*mergeWithPlane[i])->grid()->getCellSize());
02097                                 pclPointIndices pinliers2;
02098                                 pinliers2.indices = (*mergeWithPlane[i])->getInliers();
02099                                 std::sort(pinliers2.indices.begin(), pinliers2.indices.end());
02100 
02101                                 std::merge(pinliers.indices.begin(), pinliers.indices.end(), pinliers2.indices.begin(),
02102                                                 pinliers2.indices.end(), std::back_inserter(outInliers.indices));
02103                                 pinliers.indices.clear();
02104                                 pinliers.indices.swap(outInliers.indices);
02105                                 extractedPlanes.erase(mergeWithPlane[i]);
02106                         }
02107                         for (PointIndices::const_iterator point_it = pinliers.indices.begin(); point_it != pinliers.indices.end(); point_it++) {
02108                                 pointMapping[*point_it].reset();
02109                         }
02110                         PlanePatchPtr pp;
02111                         if (pinliers.indices.size() >= 3)
02112                                 pp.reset(new PlanePatch(pinliers.indices, pointCloud, sacDist));
02113                         if (pp) {
02114                                 pp->newGrid(cellSize);
02115                                 pp->grid()->blindPopulate(pp->getInliers(), pointCloud);
02116                                 pp->grid()->calculateStartPos();
02117                                 merged.push_front(pp);
02118                                 plane_it_it = extractedPlanes.erase(plane_it_it);
02119                         }
02120                 } else
02121                         ++plane_it_it;
02122         }
02123         addPlanePatchesAndUpdateSegmented(extractedPlanes, pointMapping, merged);
02124 }
02125 
02126 /*****************************************************************************/
02127 
02128 bool StructureColoring::planesAreConnected(const PlanePatch& pp1, const PlanePatch& pp2, const PointCloud& pointCloud) {
02129         const PointIndices& pp2Inliers = pp2.getInliers();
02130         for (PointIndices::const_iterator pp2Inliers_it = pp2Inliers.begin(); pp2Inliers_it != pp2Inliers.end(); ++pp2Inliers_it) {
02131                 if (pp1.checkPointConnection(pointCloud.points[*pp2Inliers_it].getVector3fMap(),
02132                                 mParams.mConnectionNeighbors))
02133                         return true;
02134         }
02135         return false;
02136 }
02137 
02138 /*****************************************************************************/
02139 
02140 void StructureColoring::addPlanePatchesAndUpdateSegmented(PlanePatches& extractedPlanes, PlanePatchVector& pointMapping,
02141                 const PlanePatches& planePatches) {
02142         for (PlanePatches::const_iterator plane_it = planePatches.begin(); plane_it != planePatches.end(); ++plane_it) {
02143                 extractedPlanes.push_front(*plane_it);
02144                 const PointIndices& indices = (*plane_it)->getInliers();
02145                 for (PointIndices::const_iterator it = indices.begin(); it != indices.end(); ++it) {
02146                         if (pointMapping[*it])
02147                                 ROS_WARN("plane inliers are not disjunct anymore!");
02148                         pointMapping[*it] = *plane_it;
02149                 }
02150         }
02151 }
02152 
02153 /*****************************************************************************/
02154 
02155 float StructureColoring::getSACDistanceFromDepth(const unsigned int& depth, const OcTree& octree) {
02156         float currentOctreeBinSize = octree.getCellSizeFromDepth(depth);
02157         float dist = std::max(mParams.mMinSACDistanceThreshold, std::min(mParams.mMaxSACDistanceThreshold, mParams.mSACOctreeFactor
02158                         * currentOctreeBinSize));
02159         return dist;
02160 }
02161 
02162 /*****************************************************************************/
02163 
02164 float StructureColoring::getHTDistanceFromDepth(const unsigned int& depth, const OcTree& octree) {
02165         float currentOctreeBinSize = octree.getCellSizeFromDepth(depth);
02166         float dist = std::min(mParams.mMaxHTDistanceThreshold, mParams.mHTOctreeBinSizeFactor * currentOctreeBinSize);
02167         return dist;
02168 }
02169 
02170 /*****************************************************************************/
02171 
02172 void StructureColoring::getMinMaxRadiusFromDepth(float& minRadius, float& maxRadius, const OcTree& octree, const float& depth) {
02173         minRadius = mParams.mMinRadiusFactor * octree.getCellSizeFromDepth(depth);
02174         maxRadius = mParams.mMaxRadiusFactor * octree.getCellSizeFromDepth(depth);
02175 }
02176 
02177 /*****************************************************************************/
02178 
02179 float StructureColoring::getAngleEpsFromDepth(const unsigned int& depth, const OcTree& octree) {
02180         float angleEps = mParams.mAngleEps * (1.f - (float) depth / (float) octree.getMaxDepth()) + mParams.mAngleEpsOnMinOctreeRes
02181                         * ((float) depth / (float) octree.getMaxDepth());
02182         return angleEps;
02183 }
02184 
02185 /*****************************************************************************/
02186 
02187 void StructureColoring::flipToViewport(Vec3& vec, const Vec3& viewport) {
02188         if (viewport.dot(vec) > 0) {
02189                 vec *= -1.f;
02190         }
02191 }
02192 
02193 /*****************************************************************************/
02194 
02195 double StructureColoring::segmentPlanesSAC(PlanePatches& extractedPlanes, PlanePatchVector& pointMapping, const PointCloudPtr& pointCloud)
02196 {
02197     ROS_INFO("segmentPlanesSAC");
02198     ros::Time start = ros::Time::now();
02199 
02200     mLastCellSizeWithNormals = mParams.mMinSACDistanceThreshold;
02201     pcl::ModelCoefficients coefficients;
02202     pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
02203     pcl::PointIndices::Ptr indices (new pcl::PointIndices);
02204     size_t nrPoints = pointCloud->points.size();
02205     indices->indices.reserve(nrPoints);
02206     for (size_t i = 0; i < nrPoints; ++i)
02207     {
02208         indices->indices.push_back(i);
02209     }
02210     // Create the segmentation object
02211     pcl::SACSegmentation<PointT> seg;
02212     // Optional
02213     seg.setOptimizeCoefficients (true);
02214         seg.setMaxIterations(mParams.mPclSACmaxIter);
02215     // Mandatory
02216     seg.setModelType (pcl::SACMODEL_PLANE);
02217     seg.setMethodType (pcl::SAC_RANSAC);
02218     seg.setDistanceThreshold (mParams.mMinSACDistanceThreshold);
02219         seg.setInputCloud(pointCloud);
02220 
02221     ros::Time end = ros::Time::now();
02222     ros::Duration dt = end - start;
02223     ROS_INFO("preprocessing time: %f\n", dt.toSec());
02224 
02225     unsigned int failcounter = 0;
02226     unsigned int maxIter = 100;
02227 
02228     while (indices->indices.size () > mParams.mMinPointsInCC && failcounter < maxIter)
02229     {
02230         ros::Time start2 = ros::Time::now();
02231         seg.setIndices(indices);
02232         seg.segment (*inliers, coefficients);
02233         end = ros::Time::now();
02234         dt = end - start2;
02235         if (mParams.mVerbose)
02236             ROS_INFO("segmentation time: %f", dt.toSec());
02237 
02238         if (inliers->indices.size() >= mParams.mMinPointsInCC)
02239         {
02240 
02241             Vec3 norm(coefficients.values[0], coefficients.values[1], coefficients.values[2]);
02242             // RANSAC model Coefficients: ax + by + cz + d = 0
02243             // my model: n*p - d = 0 with d > 0
02244             // thus i must switch the distance's sign!
02245             float distance = -1.f * coefficients.values[3];
02246             if (distance < 0) {
02247                 distance *= -1.f;
02248                 norm *= -1.f;
02249             }
02250             PlanePatchPtr pp = boost::make_shared<PlanePatch>(norm, distance, inliers->indices, *pointCloud, mParams.mMinSACDistanceThreshold);
02251 
02252             // segment plane into connected components
02253             // fake octree nodes for the points..
02254                         std::vector<NodePointers> CCInliers;
02255                         OcTreePtr octreePtr(new OcTree(mParams.mMinOctreeResolution, mParams.mRho_max, mParams.mPrincipalVarFactor,
02256                                         mParams.mMinPointsForNormal, mParams.mCurvThreshold, mParams.mCurv2Threshold, mParams.mSqDistFactor, 5));
02257                         NodePointers inlierOctreeNodes;
02258                         for (PointIndices::const_iterator in_it = pp->getInliers().begin();
02259                                         in_it != pp->getInliers().end(); ++in_it) {
02260                                 NodePtr n = new spatialaggregate::OcTreeNode<float, ValueClass>();
02261 //
02262 //                              float minpx = pointCloud->points[*in_it].x - mMinSACDistanceThreshold;
02263 //                              float minpy = pointCloud->points[*in_it].y - mMinSACDistanceThreshold;
02264 //                              float minpz = pointCloud->points[*in_it].z - mMinSACDistanceThreshold;
02265 //                              OcTree::OctreeKey minpos(minpx, minpy, minpz, octreePtr->getOctreePtr());
02266 //
02267 //                              float maxpx = pointCloud->points[*in_it].x + mMinSACDistanceThreshold;
02268 //                              float maxpy = pointCloud->points[*in_it].y + mMinSACDistanceThreshold;
02269 //                              float maxpz = pointCloud->points[*in_it].z + mMinSACDistanceThreshold;
02270 //                              OcTree::OctreeKey maxpos(maxpx, maxpy, maxpz, octreePtr->getOctreePtr());
02271 //
02272 //                              float px = pointCloud->points[*in_it].x;
02273 //                              float py = pointCloud->points[*in_it].y;
02274 //                              float pz = pointCloud->points[*in_it].z;
02275 //                              OcTree::OctreeKey pos(px, py, pz, octreePtr->getOctreePtr());
02276 
02277                                 n->depth_ = 0;
02278                                 n->value_.meanPos(0) = pointCloud->points[*in_it].x;
02279                                 n->value_.meanPos(1) = pointCloud->points[*in_it].y;
02280                                 n->value_.meanPos(2) = pointCloud->points[*in_it].z;
02281 
02282                                 n->value_.normal = norm;
02283                                 n->value_.stable = true;
02284 
02285                                 // store index in numPoints....
02286                                 n->value_.numPoints = *in_it;
02287 
02288                                 inlierOctreeNodes.push_back(n);
02289                         }
02290 
02291                         filterConnectedNodes(CCInliers, pp->getPlane3D(), inlierOctreeNodes, mParams.mMinSACDistanceThreshold);
02292 
02293                         bool ccextracted = false;
02294                         ROS_INFO("found %zu connected components", CCInliers.size());
02295                         for (unsigned int cc = 0; cc < CCInliers.size(); cc++) {
02296 
02297                                 PointIndices CCIndices;
02298 
02299                                 for( unsigned int ccn = 0; ccn < CCInliers[cc].size(); ccn++ )
02300                                         CCIndices.push_back( CCInliers[cc][ccn]->value_.numPoints );
02301 
02302                                 size_t sizeOfInliers = CCIndices.size();
02303                                 if (sizeOfInliers >= mParams.mMinPointsInCC) {
02304 //                                      ROS_INFO("connected component has enough points :)");
02305                                         ccextracted = true;
02306                                         PlanePatchPtr ccpp;
02307                                         ccpp.reset(new PlanePatch(pp->getPlane3D().getPlaneNormal(), pp->getPlane3D().getPlaneDistanceToOrigin(), CCIndices, *pointCloud, pp->getDistanceThreshold()));
02308 
02309                                         extractedPlanes.push_back(ccpp);
02310                                         for (PointIndices::const_iterator in_it = CCIndices.begin();
02311                                                         in_it != CCIndices.end(); ++in_it)
02312                                         {
02313                                                 pointMapping[*in_it] = ccpp;
02314                                         }
02315 
02316                                 // remove indices of plane inliers from the indices used for the next iteration:
02317                                 start2 = ros::Time::now();
02318                                 PointIndices current = indices->indices;
02319                                 std::sort(CCIndices.begin(), CCIndices.end());
02320                                 indices->indices.clear();
02321                                 std::set_difference(current.begin(), current.end(), CCIndices.begin(), CCIndices.end(), std::back_inserter(indices->indices));
02322                                 end = ros::Time::now();
02323                                 dt = end - start2;
02324                                 if (mParams.mVerbose)
02325                                     ROS_INFO("extraction time: %f, %zu left", dt.toSec(), indices->indices.size());
02326 
02327                                 } else {
02328 //                                      ROS_INFO("connected component did not have enough points :(");
02329                                 }
02330 
02331                         }
02332                         if (!ccextracted)
02333                                 failcounter++;
02334 
02335                         for( unsigned int i = 0; i < inlierOctreeNodes.size(); i++ )
02336                                 delete inlierOctreeNodes[i];
02337 
02338         }
02339         else
02340         {
02341             ROS_ERROR("Could not estimate a planar model for the given dataset.\n");
02342             break;
02343         }
02344 
02345     }
02346     dt = end - start;
02347     ROS_INFO("segmentPlanesSAC time: %f", dt.toSec());
02348     return dt.toSec();
02349 }
02350 
02351 double StructureColoring::segmentCylindersSAC(CylinderPatches& cylinderPatches, CylinderPatchVector& pointMapping, OcTree& octree, const PointCloudPtr& pointCloud)
02352 {
02353         typedef pcl::PointCloud<pcl::Normal> NormalCloud;
02354 
02355     ROS_INFO("segmentCylinderSAC");
02356     double start = pcl::getTime();
02357 
02358         pcl::ModelCoefficients coefficients;
02359     pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
02360     pcl::PointIndices::Ptr indices (new pcl::PointIndices);
02361     size_t nrPoints = pointCloud->points.size();
02362     indices->indices.reserve(nrPoints);
02363     for (size_t i = 0; i < nrPoints; ++i)
02364     {
02365         indices->indices.push_back(i);
02366     }
02367 
02368     NormalCloud::Ptr normalCloud(new NormalCloud);
02369         pcl::NormalEstimation<PointT, pcl::Normal> ne;
02370         // Create an empty kdtree representation, and pass it to the normal estimation object.
02371         // Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).
02372         pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZRGB>);
02373         tree->setInputCloud (pointCloud);
02374         ne.setSearchMethod (tree);
02375         // Use all neighbors in a sphere of radius ..
02376         ne.setRadiusSearch (mParams.mMinOctreeResolution); // im normalen Verfahren wird die CellSize durch 2 genommen, um auf den Radius zu kommen, das könnte hier zu klein sein
02377         //ne.setKSearch (50);
02378         ne.setViewPoint(0.f, 0.f, 0.f);
02379         // Compute the features
02380         ne.setInputCloud (pointCloud);
02381         ne.compute (*normalCloud);
02382     ROS_INFO("segmentCylinderSAC: normals computed.");
02383 
02384         pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg;
02385         seg.setOptimizeCoefficients(true);
02386         seg.setModelType(pcl::SACMODEL_CYLINDER);
02387         seg.setMethodType(pcl::SAC_RANSAC);
02388         seg.setMaxIterations(mParams.mPclSACmaxIter);
02389 
02390         //seg.setDistanceThreshold(sacDist);
02391         seg.setDistanceThreshold(mParams.mMinSACDistanceThreshold);
02392         seg.setNormalDistanceWeight(mParams.mNormalDistanceWeight);
02393         seg.setRadiusLimits (mParams.mMinCylinderRadius, mParams.mMaxCylinderRadius);
02394 
02395         seg.setInputCloud(pointCloud);
02396         seg.setInputNormals(normalCloud);
02397 
02398     unsigned int failcounter = 0;
02399     while ((indices->indices.size () > (nrPoints/2)) && (failcounter < mParams.mTriesOnEachDepth))
02400     {
02401         ROS_INFO("segmentCylinderSAC: segmenting, %zu points left ...", indices->indices.size());
02402         seg.setIndices(indices);
02403         seg.segment(*inliers, coefficients);
02404 
02405         if (inliers->indices.size() >= mParams.mMinPointsInCC)
02406         {
02407             Vec3 pointOnAxis(coefficients.values[0], coefficients.values[1], coefficients.values[2]);
02408             Vec3 axisDirection(coefficients.values[3], coefficients.values[4], coefficients.values[5]);
02409             float radius(coefficients.values[6]);
02410             CylinderPatchPtr cylinder = boost::make_shared<CylinderPatch>(inliers->indices, *pointCloud, pointOnAxis, axisDirection, radius, mParams.mMinSACDistanceThreshold);
02411             if (checkCylinder(cylinder, pointCloud))
02412             {
02413                 cylinderPatches.push_back(cylinder);
02414                 for (PointIndices::const_iterator in_it = cylinder->getInliers().begin();
02415                         in_it != cylinder->getInliers().end(); ++in_it)
02416                 {
02417                     pointMapping[*in_it] = cylinder;
02418                 }
02419             }
02420             else
02421                 failcounter++;
02422         }
02423         else {
02424             ROS_ERROR("RANSAC: no cylinder found, aborting");
02425             break;
02426         }
02427         // remove indices of plane inliers from the indices used for the next iteration:
02428         PointIndices current = indices->indices;
02429         indices->indices.clear();
02430         std::set_difference(current.begin(), current.end(), inliers->indices.begin(), inliers->indices.end(), std::back_inserter(indices->indices));
02431     }
02432     double end = pcl::getTime();
02433     double elapsedTime = end - start;
02434     ROS_INFO("segmentCylinderSAC time: %f", elapsedTime);
02435     return elapsedTime;
02436 }
02437 
02438 bool StructureColoring::checkCylinderDimensions(const CylinderPatchPtr& cylinder) const
02439 {
02440     return ((cylinder->getRadius() > mParams.mMinCylinderRadius) && (cylinder->getRadius() < mParams.mMaxCylinderRadius));
02441 }
02442 
02443 bool StructureColoring::checkCylinder(const CylinderPatchPtr& cylinder, const PointCloudPtr& pointCloud) const
02444 {
02445     float cellSize = mParams.mMinOctreeResolution;
02446     CylinderGridMap grid(cellSize, cylinder, *pointCloud);
02447     size_t nrCells = grid.getCells().size();
02448     assert(nrCells == (grid.getWidth()*grid.getHeight()));
02449             
02450     int count = 0;
02451     for (size_t i = 0; i < nrCells; ++i)
02452         if (grid.getCells()[i]) ++count;
02453     float occupied = (float)count/(float)nrCells;
02454     return occupied > mParams.mOccupiedRatio;
02455 }
02456 


structure_coloring_fkie
Author(s): Bastian Gaspers
autogenerated on Sun Jan 5 2014 11:38:09