@@ -62,6 +62,23 @@ struct VoxelGaussian {
6262
6363using VoxelMap = std::unordered_map<VoxelKey, VoxelGaussian, VoxelKeyHash>;
6464
65+ struct VoxelAccumulator {
66+ int count = 0 ;
67+ Eigen::Vector3d mean = Eigen::Vector3d::Zero();
68+ Eigen::Matrix3d covariance_accumulator = Eigen::Matrix3d::Zero();
69+
70+ void AddPoint (const Eigen::Vector3d &point) {
71+ ++count;
72+ const Eigen::Vector3d delta = point - mean;
73+ mean += delta / static_cast <double >(count);
74+ const Eigen::Vector3d delta_after_update = point - mean;
75+ covariance_accumulator += delta * delta_after_update.transpose ();
76+ }
77+ };
78+
79+ using VoxelAccumulatorMap =
80+ std::unordered_map<VoxelKey, VoxelAccumulator, VoxelKeyHash>;
81+
6582struct NDTLinearSystem {
6683 Eigen::Matrix6d JTJ = Eigen::Matrix6d::Zero();
6784 Eigen::Vector6d JTr = Eigen::Vector6d::Zero();
@@ -152,39 +169,24 @@ void ValidateNDTOption(const NormalDistributionsTransformOption &option) {
152169VoxelMap BuildVoxelGaussians (const geometry::PointCloud &target,
153170 const NormalDistributionsTransformOption &option) {
154171 const double inv_voxel_size = 1.0 / option.voxel_size_ ;
155- std::unordered_map<VoxelKey, std::vector<int >, VoxelKeyHash> voxel_indices;
156- for (int i = 0 ; i < static_cast <int >(target.points_ .size ()); ++i) {
157- voxel_indices[GetVoxelKey (target.points_ [i], inv_voxel_size)].push_back (
158- i);
172+ VoxelAccumulatorMap voxel_accumulators;
173+ for (const Eigen::Vector3d &point : target.points_ ) {
174+ voxel_accumulators[GetVoxelKey (point, inv_voxel_size)].AddPoint (point);
159175 }
160176
161177 VoxelMap voxel_map;
162- for (const auto &item : voxel_indices ) {
163- const auto &indices = item.second ;
164- if (static_cast < int >(indices. size ()) < option.min_points_per_voxel_ ) {
178+ for (const auto &item : voxel_accumulators ) {
179+ const VoxelAccumulator &accumulator = item.second ;
180+ if (accumulator. count < option.min_points_per_voxel_ ) {
165181 continue ;
166182 }
167183
168184 VoxelGaussian gaussian;
169- gaussian.count = static_cast <int >(indices.size ());
170- for (const int idx : indices) {
171- gaussian.mean += target.points_ [idx];
172- }
173- gaussian.mean /= static_cast <double >(indices.size ());
174-
175- Eigen::Matrix3d covariance = Eigen::Matrix3d::Zero ();
176- double representative_distance2 = std::numeric_limits<double >::max ();
177- for (const int idx : indices) {
178- const Eigen::Vector3d centered =
179- target.points_ [idx] - gaussian.mean ;
180- covariance += centered * centered.transpose ();
181- const double distance2 = centered.squaredNorm ();
182- if (distance2 < representative_distance2) {
183- representative_distance2 = distance2;
184- gaussian.representative_index = idx;
185- }
186- }
187- covariance /= static_cast <double >(indices.size () - 1 );
185+ gaussian.count = accumulator.count ;
186+ gaussian.mean = accumulator.mean ;
187+ const Eigen::Matrix3d covariance =
188+ accumulator.covariance_accumulator /
189+ static_cast <double >(accumulator.count - 1 );
188190
189191 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> solver (covariance);
190192 if (solver.info () != Eigen::Success) {
@@ -205,6 +207,22 @@ VoxelMap BuildVoxelGaussians(const geometry::PointCloud &target,
205207 solver.eigenvectors ().transpose ();
206208 voxel_map.emplace (item.first , gaussian);
207209 }
210+
211+ for (int i = 0 ; i < static_cast <int >(target.points_ .size ()); ++i) {
212+ const Eigen::Vector3d &point = target.points_ [i];
213+ auto voxel_itr = voxel_map.find (GetVoxelKey (point, inv_voxel_size));
214+ if (voxel_itr == voxel_map.end ()) {
215+ continue ;
216+ }
217+ VoxelGaussian &gaussian = voxel_itr->second ;
218+ const double distance2 = (point - gaussian.mean ).squaredNorm ();
219+ if (gaussian.representative_index < 0 ||
220+ distance2 < (target.points_ [gaussian.representative_index ] -
221+ gaussian.mean )
222+ .squaredNorm ()) {
223+ gaussian.representative_index = i;
224+ }
225+ }
208226 return voxel_map;
209227}
210228
0 commit comments