Consolidation of Unorganized Point Clouds for Surface Reconstruction(WLOP)的代码

论文:: Consolidation of Unorganized Point Clouds for Surface Reconstruction(WLOP)

主要的核心思想:输入一组点云,然后随机选取最后保留下来的点云,通过加权距离去调整输出点云的位置

更新点云:

 

 

#ifndef DDX_WLOP_HEADER
#define DDX_WLOP_HEADER
#pragma once 

#include <vector>
#include <memory>
#include <Eigen/Dense>
#include "KDTreeFlann.h"
#include "KDTreeSearchParam.h"
#include <random>
#include <omp.h>
#include <iostream>
#include <fstream>

namespace DDX {

class WLOP
{
public:
	EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
private:

	double mRadius;
	double mMu;
	int mSelect_percentage;
	bool require_uniform_sampling;
	
	std::vector<Eigen::Vector3d>& original_point;
	std::vector<Eigen::Vector3d> sample_points ;



public:
	WLOP(std::vector<Eigen::Vector3d>& point , double radius ,int percentage  ,double mu = 0.45 ,bool density = false)
		:
		original_point(point),
		mRadius (radius) ,
		mMu(mu) ,
		mSelect_percentage(percentage) ,
		require_uniform_sampling (density)
	{};
	
	void Run (int iter_number) 
	{
		size_t number_of_original = original_point.size() ;

		size_t number_of_sample = static_cast<size_t> (float(number_of_original) * 
																(mSelect_percentage / float(100.0))) ;

		std::vector<Eigen::Vector3d> update_sample_points(number_of_sample);

		// 1 按照百分比生成下采样的点
		sample_points.reserve (number_of_sample);
		generate_sample_points(number_of_original ,number_of_sample);
		std::cout << "number_of_sample " << number_of_sample << std::endl;
		std::cout << "sample_points size " << sample_points.size() << std::endl;
		// 2 初始化一个原始的kd tree 
		const auto original_kd_tree = create_Kdtree (original_point);
		
		std::vector<double> original_density (number_of_original);
		std::vector<double> samples_density (number_of_sample);
		if (require_uniform_sampling) 
		{
			for (int i = 0 ; i < (int)original_point.size() ;++i)
			{
				original_density[i] = compute_density_weight_for_original_point (original_kd_tree ,original_point[i] ,mRadius);
				
			}
		}
		
		// 3 迭代更新
		for (int iter_n = 0; iter_n < iter_number; ++iter_n) 
		{
			std::cout << "iter " << iter_n << std::endl;

			// 创建采样点的kd tree 
			const auto sample_kd_tree = create_Kdtree (sample_points);
			
			
			for (int i = 0 ; i < (int)sample_points.size() ; ++i)
			{
				samples_density[i] = compute_density_weight_for_sample_point (sample_kd_tree ,sample_points[i] ,mRadius);
			}
			
			for (int i = 0 ; i < (int)sample_points.size() ; ++i) {
				update_sample_points[i] = compute_update_sample_point (
											i ,
											original_kd_tree ,
											sample_kd_tree ,
											original_density ,
											samples_density ,
											mRadius);
			}

			for (int i = 0 ; i < (int)update_sample_points.size() ; ++i) 
			{
				sample_points[i] = update_sample_points[i];
			}
		}
	} ;
	
	void write_obj (const std::string& path) 
	{
		std::ofstream delaunay3d (path.c_str());
		for (int i = 0 ; i < sample_points.size() ; ++i) {
			delaunay3d << "v " 
					<< sample_points[i][0] << " "
					<< sample_points[i][1] << " "
					<< sample_points[i][2] << std::endl ;
		}
		delaunay3d.close ();
	}
private:	
	std::unique_ptr<KDTreeFlann> create_Kdtree (std::vector<Eigen::Vector3d>& point) 
	{
		Eigen::MatrixXd dataset0 = Eigen::Map<Eigen::MatrixXd>(reinterpret_cast<double*>(point.data()),3,point.size());
		return std::make_unique<KDTreeFlann> (dataset0) ;
	};

	void generate_sample_points (size_t number_of_original, size_t number_of_sample ) 
	{
		size_t diff_number = number_of_original - number_of_sample;
		std::random_device rd ; 
		std::mt19937 gen(rd()) ; 
		constexpr int int_max = std::numeric_limits<int>::max () ;
		std::uniform_int_distribution<int> dis(int(0),int_max) ;
		std::vector<int> vist (number_of_original ,-1);
		int count_indx = 0;
		while (count_indx < diff_number )
		{
			int randint = dis (gen) ;
			const auto i13x = randint % (int)number_of_original ;
			if (vist[i13x] < 0) {
				vist[i13x] = 1;
				count_indx++;
			}
		}

		for (size_t i = 0 ; i < number_of_original ; ++i) 
		{
			if (vist[i] < 0)
				sample_points.push_back (original_point[i]);
		}
	}
	

	double compute_density_weight_for_original_point (const std::unique_ptr<KDTreeFlann>& original_kd_tree ,
													  Eigen::Vector3d const&p ,
													  double radius )
	{
		
		double radius2 = radius * radius;
		double density_weight = (double)1.0;
		double iradius16 = -(double)4.0 / radius2;

		std::vector<int> index ;
		std::vector<double> distance ;
		const auto k = original_kd_tree->SearchRadius (p ,radius ,index ,distance) ;

		for (int i = 0 ; i < k ; ++i) 
		{
			if (distance[i] < 1e-8) continue;
			density_weight += std::exp(distance[i] * iradius16);
		}

		return double(1.0) / density_weight;
	};

	double compute_density_weight_for_sample_point (const std::unique_ptr<KDTreeFlann>& sample_kd_tree  ,
													Eigen::Vector3d const&p ,
													double radius)
	{
		//Compute density weight
		double radius2 = radius * radius;
		double density_weight = (double)1.0;
		double iradius16 = -(double)4.0 / radius2;

		std::vector<int> index ;
		std::vector<double> distance ;
		const auto k = sample_kd_tree->SearchRadius (p ,radius ,index ,distance) ;

		for (int i = 0 ; i < k ; ++i) 
		{
			density_weight += std::exp(distance[i] * iradius16);
		}

		return density_weight;

	};

	Eigen::Vector3d compute_update_sample_point (int indx ,
									  const std::unique_ptr<KDTreeFlann>& original_kd_tree,
									  const std::unique_ptr<KDTreeFlann>& sample_kd_tree ,
									  const std::vector<double>& sample_densities ,
									  const std::vector<double> original_densities ,
									  double radius) 
	{
		bool is_original_densities_empty = original_densities.empty();
		bool is_sample_densities_empty = sample_densities.empty();

		double radius2 = radius * radius;
		double iradius16 = -(double)4.0 / radius2;
		

		// Compute Average Term
		Eigen::Vector3d average (0 , 0 ,0);
		if (true) 
		{	
			
			double average_weight_sum = (double)0.0;

			std::vector<int> index ;
			std::vector<double> distance ; 
			const auto k = original_kd_tree->SearchRadius (sample_points[indx] , radius ,index ,distance);

			for (int j = 0 ; j < k ; j++)
			{
				double dist2 = distance[j];
				if (dist2 < 1e-10) continue;

				double weight = (double)0.0;

				weight = std::exp(dist2 * iradius16);

				if (!is_original_densities_empty)
				{
					weight *= original_densities[index[j]];
				}
				average_weight_sum += weight;
    			average += original_point[index[j]] * weight;
			}

			if (k == 0 || average_weight_sum < 1e-20)
			{
				average = sample_points[indx] ;
			}
			else
			{
				average = average / average_weight_sum;
			}
		}

		//Compute repulsion term
		Eigen::Vector3d repulsion (0.0 , 0.0 ,0.0);
		if (true) 
		{
			double weight = (double)1.0;
			double repulsion_weight_sum = (double)0.0;
			std::vector<int> index ;
			std::vector<double> distance ; 
			const auto k = sample_kd_tree->SearchRadius (sample_points[indx] , radius ,index ,distance);

			for (int j = 0 ; j < k ; j++)
			{
				double dist2 = distance[j];
				if (dist2 < 1e-10) continue;
				double dist = std::sqrt(dist2);
				weight = std::exp(dist2 * iradius16) * std::pow(double(1.0) / dist ,2); // L1
				if (!is_sample_densities_empty)
				{
					weight *= sample_densities[index[j]];
				}

				Eigen::Vector3d diff = sample_points[indx] - sample_points[index[j]];
				repulsion_weight_sum += weight;
    			repulsion = repulsion + diff * weight;
			}
			
			if (k < 3 || repulsion_weight_sum < double(1e-20)) 
			{
				repulsion = Eigen::Vector3d(0.0 ,0.0 ,0.0);
			}

			else 
			{
				repulsion = repulsion / repulsion_weight_sum;
			}
			
		}

		return average + mMu * repulsion ;	
	};

};

}

#endif	/* DDX_WLOP_HEADER */

githut: GitHub - xiandenis/WLOP: Consolidation of Unorganized Point Clouds for Surface Reconstruction

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值