#ifndef CGAL_EFFICIENT_RANSAC_PRIMITIVE_H #define CGAL_EFFICIENT_RANSAC_PRIMITIVE_H #include #include #include #include #include #include extern int ccTime; extern int ccCount; namespace CGAL { namespace Efficient_ransac { template class Primitive_ab { template friend class Efficient_ransac; template friend class Octree; public: //--------------------------------------------typedef typedef typename std::vector::iterator inputIterator; typedef typename std::vector::const_iterator InputConstIterator; typedef typename Kernel::FT FT; // basic geometric types typedef typename Kernel::Point_3 Point; typedef typename Kernel::Vector_3 Vector; typedef typename Kernel::Plane_3 Plane_3; //more advance container for geometric types typedef typename std::pair Pwn; typedef Primitive_ab Primitive; Primitive_ab() {init();} Primitive_ab(FT _ep, FT _t) {m_epsilon=_ep; m_normalThresh =_t; init();} static Primitive_ab* create(int id, FT _m_epsilon = 0.9f, FT _normalThresh = 0.9f); enum TYPE : int {PLANE = 0, SPHERE = 1, CYLINDER = 2, CONE = 3, TORUS = 4}; public: FT m_epsilon; FT m_normalThresh; //deviation of normal, used during first check of the 3 normal protected: TYPE m_type; std::string m_type_name; bool m_isValid; FT m_lowerBound; FT m_upperBound; unsigned int m_score; FT m_sum_ExpectedValue; int m_nb_subset_used; //count the number of subset used so far for the score, and thus indicate the next one to use bool m_hasConnectedComponent; std::vector m_indices; //indices of the points fitting to the candidate public: TYPE type() {return m_type;} FT ExpectedValue() const {return (m_lowerBound + m_upperBound) / 2.f;} FT inline minBound() const {return m_lowerBound;} FT inline maxBound() const {return m_upperBound;} FT inline score() const {return m_score;} //return last computed score, or -1 if no score yet int inline subsets() const {return m_nb_subset_used;} operator FT() const {return ExpectedValue();}//so we can sort by expected value void updatePoints(const std::vector &shapeIndex); bool isValid() const {return m_isValid;} std::vector *getPointsIndices() {return &m_indices;} void save(const char* _n, const inputIterator _data/*, const bool _withAllPoints = false*/) { std::ofstream plyFile(_n); plyFile << "ply" << std::endl; plyFile << "format ascii 1.0" << std::endl; plyFile << "element vertex " << m_indices.size() << std::endl; plyFile << "property float x" << std::endl; plyFile << "property float y" << std::endl; plyFile << "property float z" << std::endl; plyFile << "property uchar red" << std::endl; plyFile << "property uchar green" << std::endl; plyFile << "property uchar blue" << std::endl; plyFile << "end_header" << std::endl; plyFile << std::setprecision(6); unsigned char r, g, b; r = 64 + getRandomInt()%192; g = 64 + getRandomInt()%192; b = 64 + getRandomInt()%192; for (unsigned int i = 0;i &dists, const std::vector &shapeIndex, const std::vector &indices) = 0; virtual FT cos_to_normal(const Point &_p, const Vector &_n) const = 0; virtual void cos_to_normal(InputConstIterator first, std::vector &angles, const std::vector &shapeIndex, const std::vector &indices) const = 0; virtual void parameterExtend(const Point ¢er, FT width, FT min[2], FT max[2]) const = 0; virtual void parameters(InputConstIterator first, std::vector> ¶meterSpace, const std::vector &indices, FT min[2], FT max[2]) const = 0; unsigned int connectedComponent(InputConstIterator first, FT m_bitmapEpsilon, const Point ¢er, FT width); virtual void compute(std::set &l_list_index_selected, InputConstIterator &m_it_Point_Normal) = 0; virtual std::string info() = 0; virtual std::string type_str() const = 0; inline bool operator<(const Primitive &c) const { return ExpectedValue() < c.ExpectedValue(); } private: unsigned int cost_function(InputConstIterator &first, const std::vector &shapeIndex, FT epsilon, FT normal_threshold, const std::vector &indices); static bool default_cost_function (const Primitive_ab *_this, const Point &_p, const Vector &_n, const FT epsilon_distance, const FT delta_dev_normal); template bool isfinite(T arg) { return arg == arg && arg != std::numeric_limits::infinity() && arg != -std::numeric_limits::infinity(); } void init() { m_isValid = true; m_hasConnectedComponent = false; m_score = 0; m_nb_subset_used = 0; m_sum_ExpectedValue = 0; m_lowerBound = std::numeric_limits::min(); m_upperBound = std::numeric_limits::min(); }; void computeBound(const int sizeS1, const int sizeP) { hypergeometricalDist(-2 - sizeS1, -2 - sizeP, -1 - signed(m_indices.size()), m_lowerBound, m_upperBound); m_lowerBound = -1 - m_lowerBound; m_upperBound = -1 - m_upperBound; } void hypergeometricalDist(const int UN, const int x, const FT n, FT &low, FT &high) { if (UN == 1 || UN == 0) printf("something wrong here, denominator is zero (UN %d)!! \n", UN); if (x > UN) printf("SizeP1 smaller than sizeP, something wrong (and sqrt may be negative !!!!"); FT sq = sqrtf(x * n * (UN- x) * (UN - n) / (UN - 1)); low = (x * n - sq) / UN; high = (x * n + sq)/UN; if (!isfinite( low ) || !isfinite( high )) { low = high = 0; } } virtual bool supportsConnectedComponent() = 0; virtual bool wrapsU() const = 0; virtual bool wrapsV() const = 0; }; template Primitive_ab* Primitive_ab::create(int id, FT _epsilon, FT _normalThresh) { switch (id) { case PLANE: return new Plane(_epsilon, _normalThresh); case SPHERE: return new Sphere(_epsilon, _normalThresh); case CYLINDER: return new Cylinder(_epsilon, _normalThresh); default: return NULL; } }; template unsigned int Primitive_ab::cost_function(InputConstIterator &first, const std::vector &shapeIndex, FT epsilon, FT normal_threshold, const std::vector &indices) { std::vector dists, angles; dists.resize(indices.size()); squared_distance(first, dists, shapeIndex, indices); angles.resize(indices.size()); cos_to_normal(first, angles, shapeIndex, indices); unsigned int scoreBefore = m_indices.size(); FT eps = epsilon * epsilon; int i = 0; for (unsigned int i = 0;i normal_threshold) m_indices.push_back(indices[i]); } } return m_indices.size() - scoreBefore; } template bool Primitive_ab::default_cost_function( const Primitive_ab *_this, const Point &_p, const Vector &_n, const FT epsilon_distance, const FT delta_dev_normal) { if (_this->squared_distance(_p) > epsilon_distance * epsilon_distance) return false; if (_this->cos_to_normal(_p, _n) > delta_dev_normal ) return false; return true; } template void Primitive_ab::updatePoints(const std::vector &shapeIndex) { int start = 0, end = m_indices.size() - 1; while (start < end) { while (shapeIndex[m_indices[start]] == -1 && start < end) start++; while (shapeIndex[m_indices[end]] != -1 && start < end) end--; if (shapeIndex[m_indices[start]] != -1 && shapeIndex[m_indices[end]] == -1 && start < end) { unsigned int tmp = m_indices[start]; m_indices[start] = m_indices[end]; m_indices[end] = tmp; } } m_indices.resize(end); m_score = m_indices.size(); } template unsigned int Primitive_ab::connectedComponent(InputConstIterator first, FT m_bitmapEpsilon, const Point ¢er, FT width) { if (m_indices.size() == 0) return 0; // if (m_hasConnectedComponent) // return m_score; m_hasConnectedComponent = true; if (!supportsConnectedComponent()) return m_indices.size(); ccCount++; clock_t s, e; s = clock(); FT min[2], max[2]; //parameterExtend(center, width, min, max); std::vector> parameterSpace; parameterSpace.resize(m_indices.size()); parameters(first, parameterSpace, m_indices, min, max); int iMin[2], iMax[2]; iMin[0] = min[0] / m_bitmapEpsilon; iMin[1] = min[1] / m_bitmapEpsilon; iMax[0] = max[0] / m_bitmapEpsilon; iMax[1] = max[1] / m_bitmapEpsilon; int uExtend = abs(iMax[0] - iMin[0]) + 2; int vExtend = abs(iMax[1] - iMin[1]) + 2; std::vector> bitmap; std::vector visited; bitmap.resize(uExtend * vExtend); visited.resize(uExtend * vExtend, false); int maxIndex = uExtend * vExtend; bool wrapU = wrapsU(); bool wrapV = wrapsV(); for (unsigned int i = 0;i= uExtend) { if (wrapU) { while (u < 0) u += uExtend; while (u >= uExtend) u-= uExtend; } else { std::cout << "cc: u out of bounds: " << u << std::endl; u = (u < 0) ? 0 : (u >= uExtend) ? uExtend - 1 : u; } } if (v < 0 || v >= vExtend) { if (wrapV) { while (v < 0) v += vExtend; while (v >= vExtend) v-= vExtend; } else { std::cout << "cc: v out of bounds: " << u << std::endl; v = (v < 0) ? 0 : (v >= vExtend) ? vExtend - 1 : v; } } bitmap[v * uExtend + u].push_back(m_indices[i]); } std::vector> cluster; for (unsigned int i = 0;i<(uExtend * vExtend);i++) { cluster.push_back(std::vector()); if (bitmap[i].empty()) continue; if (visited[i]) continue; std::stack fields; fields.push(i); while (!fields.empty()) { int f = fields.top(); fields.pop(); if (visited[f]) continue; visited[f] = true; if (bitmap[f].empty()) continue; // copy indices std::copy(bitmap[f].begin(), bitmap[f].end(), std::back_inserter(cluster.back())); // grow 8-neighborhood int vIndex = f / uExtend; int uIndex = f % uExtend; bool upperBorder = vIndex == 0; bool lowerBorder = vIndex == (vExtend - 1); bool leftBorder = uIndex == 0; bool rightBorder = uIndex == (uExtend - 1); int n; if (!upperBorder) { n = f - uExtend; if (!visited[n]) fields.push(n); } else if (wrapV) { n = f + (vExtend - 1) * uExtend; if (!visited[n]) fields.push(n); } if (!leftBorder) { n = f - 1; if (!visited[n]) fields.push(n); } else if (wrapU) { n = f + uExtend - 1; if (!visited[n]) fields.push(n); } if (!lowerBorder) { n = f + uExtend; if (!visited[n]) fields.push(n); } else if (wrapV) { n = f - (vExtend - 1) * uExtend; if (!visited[n]) fields.push(n); } if (!rightBorder) { n = f + 1; if (!visited[n]) fields.push(n); } else if (wrapU) { n = f - uExtend + 1; if (!visited[n]) fields.push(n); } } } int maxCluster = 0; for (unsigned int i = 1;i cluster[maxCluster].size()) { maxCluster = i; } } m_indices = cluster[maxCluster]; e = clock(); ccTime += e - s; return m_score = m_indices.size(); } } } #endif