代码实践篇四 形状检测与规则重建

本节内容主要涉及形状检测(Shape Detection)与形状重建(Shape Reconstruction),具体算法步骤会在后续章节介绍。CGAL在6.0重点更新了形状重建部分的一些模块——动态空间分割与动态形状重建等,也会在后续详细介绍。官网上的效果和问题缺陷测试还需要一些时间验证,以及算法效率的实际测试。

题外话

泊松,前进,尺度这些重建算法本身都有相应的局限性,用CGAL测试或者其他任意的第三方库测试这些方法的时候我想也发现了,一些重建结果不理想或者出现问题是很容易发生的,所以需要嵌入0-3维的一些几何特征,之后也会介绍如何把这些与神经网络相结合,以及一些混合建模手段,比如多项式连续与离散结合,各种几何算子融合诸如此类等。

理论部分

形状检测

  1. 区域增长法
  2. 点云形状检测的高效ransac

形状重建

从点云重建多边形曲面

源码编译相关问题

  1. 添加形状检测头文件会报错
#include <CGAL/Shape_detection/Efficient_RANSAC.h>

报错:
报错结果

问题在模版定义部分有重复,注释掉这部分重复的代码即可
注释

  1. c++常见模版问题

  2. 多边形曲面重建部分需要SCIP/GLPK库,否则不能用。关于scip的库用2022编译好了,可以看:
    网盘 提取码:0212
    里面有zlib,tbb,soplex,scip,scip只编译了涉及的这部分相关的,其他的关联依赖自行编译

例子

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/IO/read_points.h>
#include <CGAL/property_map.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Shape_detection/Efficient_RANSAC.h>
#include <CGAL/Polygonal_surface_reconstruction.h>

#include <CGAL/Polygon_mesh_processing/orientation.h>

#include <CGAL/Timer.h>

#include <fstream>
#include <CGAL/IO/read_points.h>
#include <CGAL/property_map.h>
#include <CGAL/Point_with_normal_3.h>
#ifdef CGAL_USE_SCIP  // defined (or not) by CMake scripts, do not define by hand

#include <CGAL/SCIP_mixed_integer_program_traits.h>
typedef CGAL::SCIP_mixed_integer_program_traits<double>                        MIP_Solver;

#elif defined(CGAL_USE_GLPK)  // defined (or not) by CMake scripts, do not define by hand

#include <CGAL/GLPK_mixed_integer_program_traits.h>
typedef CGAL::GLPK_mixed_integer_program_traits<double>                        MIP_Solver;

#endif

using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Point_3 = Kernel::Point_3;
using Mesh = CGAL::Surface_mesh<Kernel::Point_3>;
// Point with normal, and plane index
typedef boost::tuple<Point, Vector, int>                                                        PNI;
typedef std::vector<PNI>                                                                                        Point_vector;
typedef CGAL::Nth_of_tuple_property_map<0, PNI>                                                Point_map;
typedef CGAL::Nth_of_tuple_property_map<1, PNI>                                                Normal_map;
typedef CGAL::Nth_of_tuple_property_map<2, PNI>                                                Plane_index_map;
 
typedef CGAL::Shape_detection::Efficient_RANSAC_traits<Kernel, Point_vector, Point_map, Normal_map>     Traits;
 
typedef CGAL::Shape_detection::Efficient_RANSAC<Traits>             Efficient_ransac;
typedef CGAL::Shape_detection::Plane<Traits>                                                Plane;
typedef CGAL::Shape_detection::Point_to_shape_index_map<Traits>     Point_to_shape_index_map;
 
typedef CGAL::Polygonal_surface_reconstruction<Kernel>                             Polygonal_surface_reconstruction;
typedef CGAL::Surface_mesh<Point>        Surface_mesh;                      

void test()
{
	Point_vector points;
	const std::string input_file =  CGAL::data_file_path("..\\data\\cube.pwn");
	if (!CGAL::IO::read_points(input_file.c_str(), std::back_inserter(points),
		CGAL::parameters::point_map(Point_map()).normal_map(Normal_map())))
	{
		std::cerr << "Error: cannot read file " << input_file << std::endl;
		return;
	}

	CGAL::Timer t;
	t.start();
	// Shape detection
	Efficient_ransac ransac;
	ransac.set_input(points);
	ransac.add_shape_factory<Plane>();

	std::cout << "Extracting planes...";
	t.reset();
	ransac.detect();

	Efficient_ransac::Plane_range planes = ransac.planes();
	std::size_t num_planes = planes.size();

	std::cout << " Done. " << num_planes << " planes extracted. Time: " << t.time() << " sec." << std::endl;

	// Stores the plane index of each point as the third element of the tuple.
	Point_to_shape_index_map shape_index_map(points, planes);
	for (std::size_t i = 0; i < points.size(); ++i) {
		// Uses the get function from the property map that accesses the 3rd element of the tuple.
		int plane_index = get(shape_index_map, i);
		points[i].get<2>() = plane_index;
	}


	std::cout << "Generating candidate faces...";
	t.reset();

	Polygonal_surface_reconstruction algo(
		points,
		Point_map(),
		Normal_map(),
		Plane_index_map()
	);

	std::cout << " Done. Time: " << t.time() << " sec." << std::endl;


	Mesh model;

	std::cout << "Reconstructing...";
	t.reset();

	if (!algo.reconstruct<MIP_Solver>(model)) {
		std::cerr << " Failed: " << algo.error_message() << std::endl;
		return ;
	}

	const std::string& output_file("without_input_planes_result.off");
	if (CGAL::IO::write_OFF(output_file, model))
		std::cout << " Done. Saved to " << output_file << ". Time: " << t.time() << " sec." << std::endl;
	else {
		std::cerr << " Failed saving file." << std::endl;
		return ;
	}


	// Also stores the candidate faces as a surface mesh to a file
	Mesh candidate_faces;
	algo.output_candidate_faces(candidate_faces);
	const std::string& candidate_faces_file("without_input_planes_cube_candidate_faces.off");
	std::ofstream candidate_stream(candidate_faces_file.c_str());
	if (CGAL::IO::write_OFF(candidate_stream, candidate_faces))
		std::cout << "Candidate faces saved to " << candidate_faces_file << "." << std::endl;

}      

结果

without_input_planes_result.off:

without_input_planes_result
without_input_planes_cube_candidate_faces.off:without_input_planes_cube_candidate_faces

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从零写一个几何内核

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值