点云进行模型拟合分割

本文介绍了如何利用pcl库的SACSegmentation接口对点云数据进行模型拟合和分割。通过设置最大分割次数为3,可以得到分割后的点云列表、拟合参数以及剩余点云信息。进一步,文章展示了提取地面点云和相关模型参数的过程,同时提供了扩展klib插件的代码示例。

pcl库中,对点云进行模型拟合的接口是 SACSegmentation。

对其进行可视化显示效果如下:

 设置最多分割3次拟合平面,得到分割的点云列表、拟合参数、剩余点云

 提取地面点云、模型参数、剩余的点云

扩展klib的插件代码如下:

struct SegSACSegmentation
{
    bool random = false;
    int model = pcl::SACMODEL_PLANE;
	int method = pcl::SAC_RANSAC;
    double distanceThreshold = 0.01;
    int max_iterations = 50;
    double probability = 0.99;
    bool optimizeCoefficients = true;
    double min_radius = -(std::numeric_limits<double>::max)();
    double max_radius = (std::numeric_limits<double>::max)();
    double radius = 0.0;
    double samplesMaxDist = 0.0;
    Eigen::Vector3f axis = Eigen::Vector3f::Zero();
    double epsAngle = 0;

	//////////////////////////////////////////////////////////////////////////
	int minPointCount = 100;
	int maxRunCount = 1;
	template<class PT> inline
	KArbit operator()(const pcl::shared_ptr<PointCloud<PT> >& cloud)
	{
		KArbitList resList;
		KShapeModelList modelList;

		SACSegmentation<PT> seg(random);
		seg.setModelType(model);
		seg.setMethodType(method);
		seg.setDistanceThreshold(distanceThreshold);
		seg.setMaxIterations(max_iterations);
		seg.setProbability(probability);
		seg.setOptimizeCoefficients(optimizeCoefficients);
		seg.setRadiusLimits(min_radius, max_radius);
		seg.setAxis(axis);
		seg.setEpsAngle(epsAngle);
		if (samplesMaxDist > 0)
			seg.setSamplesMaxDist(samplesMaxDist, pcl::search::KdTree<PT>::Ptr(new pcl::search::KdTree<PT>));

		ModelCoefficients  coefficients;
		PointIndicesPtr indicesPtr = pcl::make_shared<pcl::PointIndices>();

		pcl::ExtractIndices<PT> extract;
		pcl::shared_ptr<PointCloud<PT>> leftCld = cloud;
		for(int cnt = 0; cnt < maxRunCount; ++cnt)
		{	
			seg.setInputCloud(leftCld);
			seg.segment(*indicesPtr, coefficients);

			if (indicesPtr->indices.size() < minPointCount)
				break;

			extract.setInputCloud(leftCld);
			extract.setIndices(indicesPtr);

			auto cld0 = pcl::make_shared<PointCloud<PT>>();
			extract.setNegative(true);
			extract.filter(*cld0);
			leftCld = cld0;

			auto cld1 = pcl::make_shared<PointCloud<PT>>();
			extract.setNegative(false);
			extract.filter(*cld1);
			resList += cld1;
			KShapeModel shapeModel;
			shapeModel.coeffs = coefficients.values;
			shapeModel.type = model;
			modelList += shapeModel;
		}

		std::sort(resList.begin(), resList.end(), [](const pcl::shared_ptr<pcl::PointCloud<PT>>& v1, const pcl::shared_ptr<pcl::PointCloud<PT>>& v2) {
			return v1->size() > v2->size();
			});
		return KArbitList{ resList, modelList, leftCld };
	}
};

struct KPclSegSacModel : KPlugBase
{
	SegSACSegmentation p;

	KPclSegSacModel()
	{
		addProp("minPointCount").setType(PropTypeInt32).setValueAddr(&p.minPointCount);
		addProp("maxRunCount").setType(PropTypeInt32).setValueAddr(&p.maxRunCount);
		addProp("random").setType(PropTypeBool).setValueAddr(&p.random);
		addProp("model").setType(PropTypeEnumList).setValueAddr(&p.model).setEnumList({
			{"plane",SACMODEL_PLANE,},{"line",SACMODEL_LINE,},{"circle2d",SACMODEL_CIRCLE2D,},{"circle3d",SACMODEL_CIRCLE3D,},
			{"sphere",SACMODEL_SPHERE,},{"cylinder",SACMODEL_CYLINDER,},{"cone",SACMODEL_CONE,},{"torus",SACMODEL_TORUS,},
			{"paral_line",SACMODEL_PARALLEL_LINE,},{"perpendicular_plane",SACMODEL_PERPENDICULAR_PLANE,},{"paral_lines",SACMODEL_PARALLEL_LINES,},{"norm_plane",SACMODEL_NORMAL_PLANE,},
			{"norm_sphere",SACMODEL_NORMAL_SPHERE,},{"registration",SACMODEL_REGISTRATION,},{"registration_2d",SACMODEL_REGISTRATION_2D,},{"paral_plane",SACMODEL_PARALLEL_PLANE,},
			{"norm_paral_plane",SACMODEL_NORMAL_PARALLEL_PLANE,},{"stick",SACMODEL_STICK,},
		});
		addProp("method").setType(PropTypeEnumList).setValueAddr(&p.method).setEnumList({
			{"ransac",SAC_RANSAC,},{"lmeds",SAC_LMEDS,},{"msac",SAC_MSAC,},{"rransac",SAC_RRANSAC,},
			{"rmsac",SAC_RMSAC,},{"mlesac",SAC_MLESAC,},{"prosac",SAC_PROSAC,},
		});
		addProp("distanceThreshold").setType(PropTypeDouble).setValueAddr(&p.distanceThreshold);
		addProp("max_iterations").setType(PropTypeInt32).setValueAddr(&p.max_iterations);
		addProp("probability").setType(PropTypeDouble).setValueAddr(&p.probability);
		addProp("optimizeCoefficients").setType(PropTypeBool).setValueAddr(&p.optimizeCoefficients);
		addProp("min_radius").setType(PropTypeDouble).setValueAddr(&p.min_radius);
		addProp("max_radius").setType(PropTypeDouble).setValueAddr(&p.max_radius);
		addProp("radius").setType(PropTypeDouble).setValueAddr(&p.radius);
		addProp("samplesMaxDist").setType(PropTypeDouble).setValueAddr(&p.samplesMaxDist);
		addProp("epsAngle").setType(PropTypeDouble).setValueAddr(&p.epsAngle);
	}

	int __exec(const KArbit& src, KArbit& dst) override
	{
		dst = cld_op(src, p);
		return true;
	}
};

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值