00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #ifndef _PlanePatch_h_
00037 #define _PlanePatch_h_
00038
00039 #include "pcl/point_types.h"
00040 #include "pcl/point_cloud.h"
00041 #include <structureColoring/grids/GridMap.h>
00042 #include <structureColoring/structures/Plane3D.h>
00043 #include <vector>
00044 #include <cmath>
00045 #include <opencv2/core/core.hpp>
00046 #include <opencv2/imgproc/imgproc.hpp>
00047 #include <Eigen/Dense>
00048 #include <Eigen/QR>
00049 #include <Eigen/StdVector>
00050 #include <boost/shared_ptr.hpp>
00051 #include <stdexcept>
00052 #include <list>
00053
00054 class PlanePatch{
00055 public:
00056 typedef boost::shared_ptr<PlanePatch> PlanePatchPtr;
00057 typedef boost::shared_ptr<const PlanePatch> PlanePatchConstPtr;
00058 typedef std::list<PlanePatchPtr> PlanePatches;
00059
00060 typedef std::vector<int> PointIndices;
00061 typedef pcl::PointXYZ PointT;
00062 typedef pcl::PointXYZRGB ColoredPointT;
00063 typedef pcl::PointXYZI IntensityPointT;
00064 typedef pcl::PointCloud<PointT> PointCloud;
00065 typedef pcl::PointCloud<ColoredPointT> ColoredPointCloud;
00066 typedef pcl::PointCloud<IntensityPointT> IntensityPointCloud;
00067 typedef std::pair<unsigned int, unsigned int> Pair2ui;
00068 typedef Eigen::Vector3f Vec3;
00069 typedef std::vector<Vec3, Eigen::aligned_allocator<Vec3> > Points;
00070 typedef boost::shared_ptr<GridMap> GridMapPtr;
00071 typedef boost::shared_ptr<const GridMap> GridMapConstPtr;
00072
00073 template<typename PointCloudType>
00074 PlanePatch(const Eigen::Vector3f& normal, const float distance, const PointIndices& inliers,
00075 const PointCloudType& pointCloud, const float distanceThreshold = -1.f);
00076
00077 template<typename PointCloudType>
00078 PlanePatch(const PointIndices& inliers, const PointCloudType& pointCloud, const float distanceThreshold);
00079
00080 PlanePatch(const Vec3& normal, const float distance, const float distanceThreshold, const Points& brVertices,
00081 const float texWidthRatio, const float texHeightRatio, const cv::Mat& heightMap, const cv::Mat& textureMap);
00082
00083 PlanePatch();
00084
00085
00086
00087
00088 template<typename PointCloudType>
00089 void addPoints(const PointIndices& pointIndices, const PointCloudType& pointCloud);
00090
00091 float& xMin() { return mXMin; }
00092 float& yMin() { return mYMin; }
00093 float& xMax() { return mXMax; }
00094 float& yMax() { return mYMax; }
00095
00096 GridMapPtr grid() { return mGrid; }
00097 void setGrid(GridMap* newGridMapPtr){ mGrid.reset(newGridMapPtr); }
00098
00099 void setId(size_t id) { mPlaneId = id; }
00100
00101
00102 const Points& getBRVertices() const { return mBRVertices; }
00103 const Points& getBBVertices() const { return mBBVertices;}
00104
00105 const cv::Mat& getTextureMap() const {
00106 assert(mTextureMap.cols != 0 && mTextureMap.rows != 0);
00107 return mTextureMap;
00108 }
00109 const cv::Mat& getHeightMap() const {
00110 assert(mHeightMap.cols != 0 && mHeightMap.rows != 0);
00111 return mHeightMap;
00112 }
00113 const cv::Mat& getNormalMap() const {
00114 assert(mNormalMap.cols != 0 && mNormalMap.rows != 0);
00115 return mNormalMap;
00116 }
00117 float getTextureWidthRatio() const { return mTextureWidthRatio; }
00118 float getTextureHeightRatio() const { return mTextureHeightRatio; }
00119
00120 const Vec3& getPlaneCoG() const { return mCoG; }
00121 const Plane3D& getPlane3D() const { return mPlane; }
00122
00123 void getLimitsXY(float& xMin, float& xMax, float& yMin, float& yMax) const;
00124 const float& xMin() const { return mXMin; }
00125 const float& yMin() const { return mYMin; }
00126 const float& xMax() const { return mXMax; }
00127 const float& yMax() const { return mYMax; }
00128 float getArea() const { return (mXMax - mXMin) * (mYMax - mYMin); }
00129 const PointIndices& getInliers() const { return mInlierIndices; }
00130 float getDistanceThreshold() const { return mDistanceThreshold; }
00131
00132 GridMapConstPtr grid() const { return mGrid; }
00133 bool hasGrid() const{ return mGrid; }
00134
00135 size_t getId() const { return mPlaneId; }
00136
00137
00138
00139 bool checkPointConnection(const Vec3& p, const int connectionNeighbors) const;
00140
00141 float distanceToOBB(const Vec3& p) const;
00142
00143 void newGrid(const float cellSize);
00144
00145 void computeOrientedBoundingBox();
00146 void computeBoundingRectangle();
00147
00148
00149 void computeTextureSize(float& texPixSize, unsigned int& wPot, unsigned int& hPot, const float texelSizeFactor);
00150 static void compute2PotTexSize(float& widthRatio, float& heightRatio, unsigned int& wPot, unsigned int& hPot,
00151 const unsigned int width, const unsigned int height);
00152 void computeRGBTextureMap(const ColoredPointCloud& pointCloud, const float texelSizeFactor = 2.f,
00153 const unsigned int dilateIterations = 0);
00154 void computeIntensityTextureMap(const IntensityPointCloud& pointCloud, const float texelSizeFactor = 2.f,
00155 const unsigned int dilateIterations = 0);
00156 void computeAlphaMap(const PointCloud& pointCloud, const float texelSizeFactor = 2.f,
00157 const unsigned int dilateIterations = 0);
00158
00159 template<typename PointCloudType>
00160 void computeHeightMap(const float texturePixelSize, const PointCloudType& pointCloud,
00161 const unsigned int dilateIterations);
00162
00163 void computeNormalMap();
00164
00165
00166 private:
00167 PlanePatch(const PlanePatch&) :
00168 mPlane(){
00169 throw std::runtime_error("Copy Constructor not implemented");
00170 }
00171 private:
00172 PlanePatch& operator=(const PlanePatch&) {
00173 throw std::runtime_error("operator= not implemented");
00174 }
00175
00176 private:
00177 template<typename PointCloudType>
00178 void initializeTransformationsWithoutPCA(const PointCloudType& pointCloud);
00179
00180 template<typename PointCloudType>
00181 void initializeTransformationsWithPCA(const PointCloudType& pointCloud);
00182
00183 template<typename PointCloudType>
00184 void initializeWithoutPCA(const PointCloudType& pointcloud);
00185
00186 template<typename PointCloudType>
00187 void initializeWithPCA(const PointCloudType& pointCloud);
00188
00189 template<typename PointCloudType>
00190 void calculateMinMax(const PointCloudType& pointCloud);
00191
00192
00193 template<typename PointCloudType>
00194 void rotateToPrincipalAxis(Eigen::Matrix3f& m, const PointCloudType& pointCloud, const Vec3& greatestEigenVector =
00195 Vec3::Zero()) const;
00196
00197
00198 Plane3D mPlane;
00199 Vec3 mCoG;
00200 float mXMin, mXMax, mYMin, mYMax, mZMin, mZMax;
00201 PointIndices mInlierIndices;
00202 Points mBRVertices;
00203 Points mBBVertices;
00204 GridMapPtr mGrid;
00205 cv::Mat mTextureMap;
00206 cv::Mat mHeightMap;
00207 cv::Mat mNormalMap;
00208 float mTextureWidthRatio, mTextureHeightRatio;
00209 float mDistanceThreshold;
00210 size_t mPlaneId;
00211 };
00212
00213
00214
00215 class CompArea
00216 {
00217 public:
00218 bool operator()(PlanePatch::PlanePatchConstPtr pp1, PlanePatch::PlanePatchConstPtr pp2){
00219 return pp2->getArea() < pp1->getArea();
00220 }
00221 };
00222
00223
00224
00225 class CompPlanePtr
00226 {
00227 public:
00228 bool operator()(const PlanePatch::PlanePatchConstPtr pp1, const PlanePatch::PlanePatchConstPtr pp2) const {
00229 return pp1.get() < pp2.get();
00230 }
00231 };
00232
00233
00234
00235 class CompPlanePtrPair
00236 {
00237 typedef std::pair<PlanePatch::PlanePatchConstPtr, PlanePatch::PlanePatchConstPtr> PlaneConstPtrPair;
00238 public:
00239 bool operator()(const PlaneConstPtrPair ppp1, const PlaneConstPtrPair ppp2) const {
00240 if (ppp1.first.get() != ppp2.first.get()) return ppp1.first.get() < ppp2.first.get();
00241 return ppp1.second.get() < ppp2.second.get();
00242 }
00243 };
00244
00245
00246
00247 template<typename PointCloudType>
00248 PlanePatch::PlanePatch(const Eigen::Vector3f& normal, const float distance, const PointIndices& inliers,
00249 const PointCloudType& pointCloud, const float distanceThreshold)
00250 : mPlane(normal, distance), mInlierIndices(inliers),
00251 mDistanceThreshold(distanceThreshold) {
00252 assert(inliers.size()>= 3);
00253 initializeWithoutPCA(pointCloud);
00254 }
00255
00256
00257
00258 template<typename PointCloudType>
00259 PlanePatch::PlanePatch(const PointIndices& inliers, const PointCloudType& pointCloud, const float distanceThreshold)
00260 : mInlierIndices(inliers),
00261 mDistanceThreshold(distanceThreshold) {
00262 assert(inliers.size()>= 3);
00263 initializeWithPCA(pointCloud);
00264 }
00265
00266
00267
00268 template<typename PointCloudType>
00269 void PlanePatch::addPoints(const PointIndices& pointIndices, const PointCloudType& pointCloud) {
00270 mInlierIndices.reserve(mInlierIndices.size() + pointIndices.size());
00271 for (PointIndices::const_iterator pit = pointIndices.begin(); pit != pointIndices.end(); ++pit) {
00272 mInlierIndices.push_back(*pit);
00273 Vec3 tp = mPlane.transformToXYPlane(pointCloud.points[*pit].getVector3fMap());
00274 if (tp.x() < mXMin) mXMin = tp.x();
00275 if (tp.x() > mXMax) mXMax = tp.x();
00276 if (tp.y() < mYMin) mYMin = tp.y();
00277 if (tp.y() > mYMax) mYMax = tp.y();
00278 }
00279 computeOrientedBoundingBox();
00280 computeBoundingRectangle();
00281 }
00282
00283
00284
00285 template<typename PointCloudType>
00286 void PlanePatch::computeHeightMap(const float texturePixelSize, const PointCloudType& pointCloud,
00287 const unsigned int dilateIterations) {
00288 unsigned int hPot = mTextureMap.rows;
00289 unsigned int wPot = mTextureMap.cols;
00290 mHeightMap = cv::Mat::zeros(hPot, wPot, CV_32FC1);
00291 cv::Mat texCounter(cv::Mat::zeros(hPot, wPot, CV_8UC1));
00292 float distThresh = getDistanceThreshold();
00293 for (PointIndices::const_iterator point_it = mInlierIndices.begin(); point_it != mInlierIndices.end(); ++point_it) {
00294 float distanceToPlane = mPlane.signedDistance(pointCloud.points[*point_it].getVector3fMap());
00295 float distToMaxDistRatio = distanceToPlane / distThresh;
00296 float normalizedRatio = 0.5 * distToMaxDistRatio;
00297 Vec3 p = mPlane.transformToXYPlane(pointCloud.points[*point_it].getVector3fMap());
00298 unsigned int x = fabs(p[0] - mXMin) / texturePixelSize;
00299 unsigned int y = fabs(p[1] - mYMin) / texturePixelSize;
00300 mHeightMap.at<float> (y, x) += normalizedRatio + 0.5f;
00301 texCounter.at<char> (y, x) += 1;
00302 }
00303 for (unsigned int hind = 0; hind < hPot; ++hind) {
00304 for (unsigned int wind = 0; wind < wPot; ++wind) {
00305 char count = texCounter.at<char> (hind, wind);
00306 if (count != 0) {
00307 mHeightMap.at<float> (hind, wind) /= count;
00308 }
00309 }
00310 }
00311
00312 if (dilateIterations)
00313 cv::dilate(mHeightMap, mHeightMap, cv::Mat(), cv::Point(-1, -1), dilateIterations);
00314 cv::GaussianBlur(mHeightMap, mHeightMap, cv::Size(3, 3), 2, 2);
00315 computeNormalMap();
00316 }
00317
00318
00319
00320 template<typename PointCloudType>
00321 void PlanePatch::initializeTransformationsWithoutPCA(const PointCloudType& pointCloud) {
00322 mCoG = Eigen::Vector3f(0, 0, 0);
00323 for (PointIndices::const_iterator it = mInlierIndices.begin(); it != mInlierIndices.end(); ++it) {
00324 mCoG += pointCloud.points[*it].getVector3fMap();
00325 }
00326 mCoG /= (float) mInlierIndices.size();
00327 }
00328
00329
00330
00331 template<typename PointCloudType>
00332 void PlanePatch::initializeTransformationsWithPCA(const PointCloudType& pointCloud) {
00333 Points points;
00334 mCoG = Eigen::Vector3f(0, 0, 0);
00335 for (PointIndices::const_iterator it = mInlierIndices.begin(); it != mInlierIndices.end(); ++it) {
00336 const Vec3& p = pointCloud.points[*it].getVector3fMap();
00337 points.push_back(p);
00338 mCoG += p;
00339 }
00340 mCoG /= (float) mInlierIndices.size();
00341
00342 Eigen::Matrix3f cov(Eigen::Matrix3f::Zero());
00343 for (Points::const_iterator it = points.begin(); it != points.end(); ++it) {
00344 Vec3 p = *it - mCoG;
00345 cov += p * p.transpose();
00346 }
00347 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> es;
00348 es.compute(cov);
00349 const Eigen::Matrix<float, 3, 3>& eigen_vectors = es.eigenvectors();
00350
00351 mPlane = Plane3D(Vec3(eigen_vectors.col(0)), eigen_vectors.col(0).dot(mCoG));
00352 }
00353
00354
00355
00356 template<typename PointCloudType>
00357 void PlanePatch::initializeWithoutPCA(const PointCloudType& pointCloud) {
00358 initializeTransformationsWithoutPCA(pointCloud);
00359 calculateMinMax(pointCloud);
00360 computeOrientedBoundingBox();
00361 computeBoundingRectangle();
00362 }
00363
00364
00365
00366 template<typename PointCloudType>
00367 void PlanePatch::initializeWithPCA(const PointCloudType& pointCloud) {
00368 initializeTransformationsWithPCA(pointCloud);
00369 calculateMinMax(pointCloud);
00370 computeOrientedBoundingBox();
00371 computeBoundingRectangle();
00372 }
00373
00374
00375
00376 template<typename PointCloudType>
00377 void PlanePatch::calculateMinMax(const PointCloudType& pointCloud) {
00378 mXMin = mYMin = mZMin = std::numeric_limits<float>::max();
00379 mXMax = mYMax = mZMax = -std::numeric_limits<float>::max();
00380
00381
00382
00383 for (PointIndices::const_iterator it = mInlierIndices.begin(); it != mInlierIndices.end(); ++it) {
00384 const Eigen::Vector3f& p = mPlane.transformToXYPlane(pointCloud.points[*it].getVector3fMap());
00385 if (p(0) < mXMin) {
00386 mXMin = p(0);
00387 }
00388 if (p(0) > mXMax) {
00389 mXMax = p(0);
00390 }
00391 if (p(1) < mYMin) {
00392 mYMin = p(1);
00393 }
00394 if (p(1) > mYMax) {
00395 mYMax = p(1);
00396 }
00397 if (p(2) < mZMin)
00398 mZMin = p(2);
00399 if (p(2) > mZMax)
00400 mZMax = p(2);
00401 }
00402 }
00403
00404
00405
00406 template<typename PointCloudType>
00407 void PlanePatch::rotateToPrincipalAxis(Eigen::Matrix3f& m, const PointCloudType& pointCloud, const Vec3& greatestEigenVector) const {
00408 Vec3 v(Vec3::Zero());
00409 if (greatestEigenVector == v) {
00410
00411 Eigen::Matrix3f cov(Eigen::Matrix3f::Zero());
00412 for (PointIndices::const_iterator it = mInlierIndices.begin(); it != mInlierIndices.end(); ++it) {
00413 Eigen::Vector3f p = getEigenVecFromPCL(pointCloud.points[*it]) - mCoG;
00414 cov += p * p.transpose();
00415 }
00416 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> es;
00417 es.compute(cov);
00418 v = es.eigenvectors().col(2);
00419
00420 } else
00421 v = greatestEigenVector;
00422 Vec3 e1(1, 0, 0);
00423 e1 = m * e1;
00424 float rotAngle = acos(e1.dot(v));
00425 m = m * Eigen::AngleAxisf(-rotAngle, mPlane.getPlaneNormal());
00426 }
00427
00428 #endif