CloudCompare——计算点云的八叉树并可视化

在这里插入图片描述

本文由CSDN点云侠原创,原文链接。爬虫网站自重。博客长期更新,本文最新更新时间为:2023年8月10日。

1.Octree

  通过菜单栏的'Edit > Octree > Compute'找到该功能。
在这里插入图片描述

设置相关参数
在这里插入图片描述
  八叉树空间区段可以通过多种方式设置:

  • Default:包含实体的最小立方体
  • cell size at max level:用户可以在最小的细分级别上定义单元格大小为 N N N,那么八叉树的体素个数则为 2 N 2^N 2N
  • Custom bounding box:用户可以使用专用的子对话框定义自定义边界框。

  最大八叉树级别(或细分的数量)在32位版本中是 N N N=10,在64位版本中是 N N N=21。
注意:这个操作通常是不必要的(即八叉树计算是由CloudCompare在必要时自动完成的)。

  CloudCompare默认以面片的形式显示mesh网格模型,因此放大之后也看不到所谓的“网格”

2.可视化八叉树

  选中Octree,可以看到显示的是默认的包含实体的最小包围框
在这里插入图片描述
在这里插入图片描述
  在属性选项中,设置八叉树的显示层级,操作如下:
在这里插入图片描述

  以线框的形式显示八叉树,八叉树的层级为:4。
在这里插入图片描述
  以面片的形式显示八叉树。
在这里插入图片描述
在这里插入图片描述
  以点的形式显示八叉树,看不出来效果。不做展示。

3.CC源码

bool computeOctree(const ccHObject::Container &selectedEntities, QWidget *parent)
	{
		ccBBox bbox;
		std::unordered_set<ccGenericPointCloud*> clouds;
		PointCoordinateType maxBoxSize = -1;
		for (ccHObject* ent : selectedEntities)
		{
			//specific test for locked vertices
			bool lockedVertices = false;
			ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(ent, &lockedVertices);
			
			if (cloud == nullptr)
			{
			   continue;
			}
			
			if (lockedVertices)
			{
				ccUtils::DisplayLockedVerticesWarning(ent->getName(), selectedEntities.size() == 1);
				continue;
			}
			clouds.insert(cloud);

			//we look for the biggest box so as to define the "minimum cell size"
			const ccBBox thisBBox = cloud->getOwnBB();
			if (thisBBox.isValid())
			{
				CCVector3 dd = thisBBox.maxCorner() - thisBBox.minCorner();
				PointCoordinateType maxd = std::max(dd.x, std::max(dd.y, dd.z));
				if (maxBoxSize < 0.0 || maxd > maxBoxSize)
					maxBoxSize = maxd;
			}
			bbox += thisBBox;
		}

		if (clouds.empty() || maxBoxSize < 0.0)
		{
			ccLog::Warning("[doActionComputeOctree] No eligible entities in selection!");
			return false;
		}

		//min(cellSize) = max(dim)/2^N with N = max subidivision level
		const double minCellSize = static_cast<double>(maxBoxSize) / (1 << ccOctree::MAX_OCTREE_LEVEL);

		ccComputeOctreeDlg coDlg(bbox, minCellSize, parent);
		if (!coDlg.exec())
			return false;

		ccProgressDialog pDlg(true, parent);
		pDlg.setAutoClose(false);

		//if we must use a custom bounding box, we update 'bbox'
		if (coDlg.getMode() == ccComputeOctreeDlg::CUSTOM_BBOX)
			bbox = coDlg.getCustomBBox();

		for (const auto cloud : clouds)
		{
			//we temporarily detach entity, as it may undergo
			//"severe" modifications (octree deletion, etc.) --> see ccPointCloud::computeOctree
			ccMainAppInterface* instance = dynamic_cast<ccMainAppInterface*>(parent);
			ccMainAppInterface::ccHObjectContext objContext;
			if (instance)
				objContext = instance->removeObjectTemporarilyFromDBTree(cloud);

			//computation
			QElapsedTimer eTimer;
			eTimer.start();
			ccOctree::Shared octree(nullptr);
			switch (coDlg.getMode())
			{
			case ccComputeOctreeDlg::DEFAULT:
				octree = cloud->computeOctree(&pDlg);
				break;
			case ccComputeOctreeDlg::MIN_CELL_SIZE:
			case ccComputeOctreeDlg::CUSTOM_BBOX:
			{
				//for a cell-size based custom box, we must update it for each cloud!
				if (coDlg.getMode() == ccComputeOctreeDlg::MIN_CELL_SIZE)
				{
					double cellSize = coDlg.getMinCellSize();
					PointCoordinateType halfBoxWidth = static_cast<PointCoordinateType>(cellSize * (1 << ccOctree::MAX_OCTREE_LEVEL) / 2.0);
					CCVector3 C = cloud->getOwnBB().getCenter();
					bbox = ccBBox(	C - CCVector3(halfBoxWidth, halfBoxWidth, halfBoxWidth),
									C + CCVector3(halfBoxWidth, halfBoxWidth, halfBoxWidth));
				}
				cloud->deleteOctree();
				octree = ccOctree::Shared(new ccOctree(cloud));
				if (octree->build(bbox.minCorner(), bbox.maxCorner(), nullptr, nullptr, &pDlg) > 0)
				{
					ccOctreeProxy* proxy = new ccOctreeProxy(octree);
					proxy->setDisplay(cloud->getDisplay());
					cloud->addChild(proxy);
				}
				else
				{
					octree.clear();
				}
			}
			break;
			default:
				Q_ASSERT(false);
				return false;
			}
			qint64 elapsedTime_ms = eTimer.elapsed();

			//put object back in tree
			if (instance)
				instance->putObjectBackIntoDBTree(cloud, objContext);

			if (octree)
			{
				ccConsole::Print("[doActionComputeOctree] Timing: %2.3f s", static_cast<double>(elapsedTime_ms) / 1000.0);
				cloud->setEnabled(true); //for mesh vertices!
				ccOctreeProxy* proxy = cloud->getOctreeProxy();
				assert(proxy);
				proxy->setVisible(true);
				proxy->prepareDisplayForRefresh();
			}
			else
			{
				ccConsole::Warning(QString("Octree computation on cloud '%1' failed!").arg(cloud->getName()));
			}
		}

		return true;
	}

4.相关代码

[1] PCL 可视化八叉树
[2] Open3D 从点云中构建八叉树
[3] Open3D (C++) 八叉树的使用

  • 10
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Cloud Compare是一个用于点云数据处理和分析的开源软件。它提供了多种功能来对点云数据进行处理和分割。其中一种常用的方法是使用分割和标记相连组件来将点云分割成更小的部分,每一部分相互连接,并按照最小距离将点云分割。这种方法可以通过设置最小距离来进行操作。 另一种方法是先手动分割代表每个类的几组点,然后将这些点重新分组到单个云中。在Cloud Compare中,可以使用剪刀工具手动分割每个类的几组点,并使用编辑->合并功能将它们重新组合到单个云中。然后,可以使用Cloud Compare中的canupo插件创建训练集,并保存用于对原始点云进行分类的训练集。 对于表面较为平坦和具有适当定向的点云,也可以考虑使用'Mesh->Delaunay 2.5D(best fitting plane)'方法进行处理。这种方法适用于点云没有正确定向但在某个方向上仍然相当平坦的情况。 总的来说,Cloud Compare是一个功能强大的点云数据处理和分析工具,可以根据需要选择适当的方法和功能来处理和分割点云数据。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [CloudCompare软件操作学习笔记(二)](https://blog.csdn.net/qq_69150050/article/details/131118381)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

点云侠

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

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

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

打赏作者

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

抵扣说明:

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

余额充值