39 #include <unordered_map> 50 nbSample{Parametrizable::get<std::size_t>(
"nbSample")},
51 seed{Parametrizable::get<std::size_t>(
"seed")},
52 epsilon{Parametrizable::get<T>(
"epsilon")},
72 const std::size_t featDim = cloud.
features.rows();
75 std::cerr <<
"ERROR: NormalSpaceDataPointsFilter does not support 2D point cloud yet (does nothing)" << std::endl;
81 if(
nbSample >= std::size_t(nbPoints))
86 throw InvalidField(
"OrientNormalsDataPointsFilter: Error, cannot find normals in descriptors.");
90 std::mt19937 gen(
seed);
93 std::vector<std::vector<int> > idBuckets;
96 std::vector<std::size_t> keepIndexes;
100 std::vector<std::size_t> randIdcs(nbPoints);
101 std::iota(randIdcs.begin(), randIdcs.end(), 0);
102 std::random_shuffle(randIdcs.begin(), randIdcs.end());
105 for (
auto randIdx : randIdcs)
108 assert(normals.col(randIdx).head(3).norm() >= 1.0-0.00001);
109 assert(normals.col(randIdx).head(3).norm() <= 1.0+0.00001);
111 assert((normals(2,randIdx) <= 1.0) && (normals(2,randIdx) >= -1.0));
114 const T theta = std::acos(normals(2, randIdx));
116 const T phi = std::fmod(std::atan2(normals(1, randIdx), normals(0, randIdx)) + 2. * M_PI, 2. * M_PI);
120 idBuckets[
bucketIdx(theta, phi)].push_back(randIdx);
124 idBuckets.erase(std::remove_if(idBuckets.begin(), idBuckets.end(),
125 [](
const std::vector<int>& bucket) {
return bucket.empty(); }),
129 for (std::size_t i=0; i<
nbSample; i++)
132 std::uniform_int_distribution<std::size_t> uniBucket(0,idBuckets.size()-1);
133 std::size_t curBucketIdx = uniBucket(gen);
134 std::vector<int>& curBucket = idBuckets[curBucketIdx];
137 int idToKeep = curBucket[curBucket.size()-1];
138 curBucket.pop_back();
139 keepIndexes.push_back(static_cast<std::size_t>(idToKeep));
142 if (curBucket.empty()) {
143 idBuckets.erase(idBuckets.begin()+curBucketIdx);
149 std::unordered_map<std::size_t, std::size_t> mapidx;
153 for(std::size_t
id : keepIndexes)
168 template <
typename T>
172 assert( (theta >= 0.0) && (theta <= static_cast<T>(M_PI)) &&
"Theta not in [0, Pi]");
173 assert( (phi >= 0) && (phi <= 2*static_cast<T>(M_PI)) &&
"Phi not in [0, 2Pi]");
176 if (theta == static_cast<T>(M_PI)) { theta = 0.0; };
178 if (phi == 2*static_cast<T>(M_PI)) { phi = 0.0; };
180 return static_cast<std::size_t
>( floor(theta/
epsilon) * ceil(2.0*M_PI/
epsilon) + floor(phi/
epsilon) );
NormalSpaceDataPointsFilter(const Parameters ¶ms=Parameters())
virtual void inPlaceFilter(DataPoints &cloud)
Apply these filters to a point cloud without copying.
ConstView getDescriptorViewByName(const std::string &name) const
Get a const view on a descriptor by name, throw an exception if it does not exist.
PointMatcher< T >::DataPoints::InvalidField InvalidField
unsigned getNbPoints() const
Return the number of points contained in the point cloud.
const std::size_t nbSample
std::size_t bucketIdx(T theta, T phi) const
Parametrizable::Parameters Parameters
Functions and classes that are dependant on scalar type are defined in this templatized class...
bool descriptorExists(const std::string &name) const
Look if a descriptor with a given name exist.
A data filter takes a point cloud as input, transforms it, and produces another point cloud as output...
void swapCols(Index iCol, Index jCol)
Swap column i and j in the point cloud, swap also features and descriptors if any. Assumes sizes are similar.
const std::size_t nbBucket
void conservativeResize(Index pointCount)
Resize the cloud to pointCount points, conserving existing ones.
Matrix features
features of points in the cloud
virtual DataPoints filter(const DataPoints &input)
Apply filters to input point cloud. This is the non-destructive version and returns a copy...