PCL八叉树学习总结+可视化程序

pcl八叉树总共有以下几个部分:节点,迭代器,八叉树点云,容器,键值
八叉树点云包含节点,容器;迭代器是用来检索的;键值时管理数据的。

节点:主要分为叶子节点和分支节点

迭代器:分为深度优先,广度(宽度)优先。
注:1.12.0版本有新的迭代器,固定深度迭代器,并且叶子节点迭代器是深度和广度迭代器的子类。

八叉树点云:包含许多不同类型的八叉树点云,主要是存储的数据不同,和下面的容器有很大的关系。

容器:容器就是八叉树叶子节点存储的数据,可以是空的、一个点索引、全部点索引,密度信息,体素中心,近邻关系。

键值:就是整型坐标系,用于表示八叉树的空间相对位置

针对不同的需求使用不同的八叉树点云进行处理。

八叉树点云生成的一些细节:
1.当定义包围盒时,使用的是点云的getMinMax3D函数求包围盒,以包围盒的中心作为八叉树的中心,还会根据体素大小和深度来调整(扩大)包围盒,一般只是微调,但必不可少。

2.当未定义包围盒时,以点云数据中第一个点云数据作为包围盒的中心,以体素大小的边长的两倍简历包围盒,此时为第一层,八个立方体,之后根据每个点进行调整包围盒。当出现点在包围盒外面的话(紧挨着),就会拓展包围盒,直接把包围盒变成原来的二倍边长。

3.容器可以在定义八叉树点云的时候指定,默认分支节点为空容器,叶子节点为所有索引容器。

4.遍历八叉树时,是从第一层遍历到指定深度的层,通过获取当前迭代器的深度可以获取相应深度的信息。(不知道最新版的固定深度迭代器是什么效果)。

5.八叉树生成的时候是按照索引,一个一个将点加入到八叉树中,会根据加入的点更新树的深度和节点信息;如果未定义包围盒,直接比较加入的点是否在现存包围盒内,在的话不更新深度,只更新节点信息;如果定义了包围盒,则根据key计算相应的深度和节点信息,通过递归生成叶子节点和分支节点。

6.八叉树的键值是将体素内的点向下取整得到的(左后角),键值和节点的ID是一一对应的关系:如(0,0,0)对应0,(0,0,1)对应1,(1,1,1)对应7,当自己设定八叉树深度时,上述的关系就不成立了。

7.生成八叉树时,先确定八叉树的包围盒,然后递归将每个点通过根节点(本身就是一个分支节点)、深度信息(depth_mask信息?)加入到树中,得到叶子节点和叶子节点的父节点。

8.如果设置书的深度的话,并不影响树的生成,树还是那么大,只不过只能访问到设置的深度而已。会影响id的生成,最好不要设置这个选项。

9.单个点索引的容器存储的是该体素中最后一个出现的索引点。

暂时只想到这么多,有机会再补充,欢迎讨论。

附上可视化八叉树的程序:

#include 
#include 
#include 
#include 
#include 

#include 

#include 
#include
#include
#include "boost.h"

#include 
#include 
#include 
#include 
#include
VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkInteractionStyle);
//=============================
// Displaying cubes is very long!
// so we limit their numbers.
const int MAX_DISPLAYED_CUBES(15000);
//=============================

class OctreeViewer
{
public:
	OctreeViewer(std::string &filename, double resolution) :
		viz("Octree visualizator"), cloud(new pcl::PointCloud<pcl::PointXYZ>()),
		displayCloud(new pcl::PointCloud<pcl::PointXYZ>()), octree(resolution), displayCubes(false),
		showPointsWithCubes(false), wireframe(true)
	{

		//try to load the cloud
		if (!loadCloud(filename))
			return;

		//register keyboard callbacks
		viz.registerKeyboardCallback(&OctreeViewer::keyboardEventOccurred, *this, 0);



		//set current level to half the maximum one
		displayedDepth = static_cast<int> (floor(octree.getTreeDepth() / 2.0));
		if (displayedDepth == 0)
			displayedDepth = 1;

		//show octree at default depth
		extractPointsAtLevel(displayedDepth);

		//reset camera
		viz.resetCameraViewpoint("cloud");

		//run main loop
		run();

	}

private:
	//========================================================
	// PRIVATE ATTRIBUTES
	//========================================================
	//visualizer
	pcl::PointCloud<pcl::PointXYZ>::Ptr xyz;
	pcl::PointCloud<pcl::PointXYZRGB>::Ptr xyz_rgb;

	pcl::visualization::PCLVisualizer viz;
	//original cloud
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
	//displayed_cloud
	pcl::PointCloud<pcl::PointXYZ>::Ptr displayCloud;
	//octree
	pcl::octree::OctreePointCloudVoxelCentroid<pcl::PointXYZ> octree;
	//level
	int displayedDepth;
	//bool to decide if we display points or cubes
	bool displayCubes, showPointsWithCubes, wireframe;
	double size = 4;
	//========================================================

	/* \brief Callback to interact with the keyboard
	*
	*/
	void keyboardEventOccurred(const pcl::visualization::KeyboardEvent &event, void *)
	{

		if (event.getKeySym() == "a" && event.keyDown())
		{
			IncrementLevel();
		}
		else if (event.getKeySym() == "z" && event.keyDown())
		{
			DecrementLevel();
		}
		else if (event.getKeySym() == "d" && event.keyDown())
		{
			displayCubes = !displayCubes;
			update();
		}
		else if (event.getKeySym() == "x" && event.keyDown())
		{
			showPointsWithCubes = !showPointsWithCubes;
			update();
		}
		else if (event.getKeySym() == "w" && event.keyDown())
		{
			if (!wireframe)
				wireframe = true;
			update();
		}
		else if (event.getKeySym() == "s" && event.keyDown())
		{
			if (wireframe)
				wireframe = false;
			update();
		}
		//else if (event.getKeySym()=="1"&&event.keyDown())
		//{
		//	viz.getPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, size, "cloud");
		//	size++;
		//	update();
		//}
		//else if (event.getKeySym()=="down"&&event.keyDown())
		//{
		//	viz.getPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, size, "cloud");
		//	if (size==1)
		//	{
		//		return;
		//	}
		//	size--;
		//	update();
		//}
	}

	/* \brief Graphic loop for the viewer
	*
	*/
	void run()
	{
		while (!viz.wasStopped())
		{
			//main loop of the visualizer
			viz.spinOnce(100);
			boost::this_thread::sleep(boost::posix_time::microseconds(100000));
		}
	}

	/* \brief Helper function that read a pointcloud file (returns false if pbl)
	*  Also initialize the octree
	*
	*/
	bool loadCloud(std::string &filename)
	{
		std::cout << "Loading file " << filename.c_str() << std::endl;
		//read cloud
		if (pcl::io::loadPCDFile(filename, *cloud))
		{
			std::cerr << "ERROR: Cannot open file " << filename << "! Aborting..." << std::endl;
			return false;
		}

		//remove NaN Points
		std::vector<int> nanIndexes;
		pcl::removeNaNFromPointCloud(*cloud, *cloud, nanIndexes);
		std::cout << "Loaded " << cloud->points.size() << " points" << std::endl;

		//create octree structure
		octree.setInputCloud(cloud);
		//update bounding box automatically
		octree.defineBoundingBox();
		//add points in the tree
		octree.addPointsFromInputCloud();
		return true;
	}

	/* \brief Helper function that draw info for the user on the viewer
	*
	*/
	void showLegend(bool showCubes)
	{
		//key legends
		viz.addText("Keys:", 0, 170, 0.0, 1.0, 0.0, "keys_t");
		viz.addText("a -> Increment displayed depth", 10, 155, 0.0, 1.0, 0.0, "key_a_t");
		viz.addText("z -> Decrement displayed depth", 10, 140, 0.0, 1.0, 0.0, "key_z_t");
		viz.addText("d -> Toggle Point/Cube representation", 10, 125, 0.0, 1.0, 0.0, "key_d_t");
		viz.addText("x -> Show/Hide original cloud", 10, 110, 0.0, 1.0, 0.0, "key_x_t");
		viz.addText("s/w -> Surface/Wireframe representation", 10, 95, 0.0, 1.0, 0.0, "key_sw_t");

		char dataDisplay[256];
		sprintf(dataDisplay, "Displaying data as %s", (showCubes) ? ("CUBES") : ("POINTS"));
		viz.removeShape("disp_t");
		viz.addText(dataDisplay, 0, 60, 1.0, 0.0, 0.0, "disp_t");

		char level[256];
		sprintf(level, "Displayed depth is %d on %d", displayedDepth, octree.getTreeDepth());
		viz.removeShape("level_t1");
		viz.addText(level, 0, 45, 1.0, 0.0, 0.0, "level_t1");

		viz.removeShape("level_t2");
		sprintf(level, "Voxel size: %.4fm [%lu voxels]", sqrt(octree.getVoxelSquaredSideLen(displayedDepth)),
			displayCloud->points.size());
		viz.addText(level, 0, 30, 1.0, 0.0, 0.0, "level_t2");

		viz.removeShape("org_t");
		if (showPointsWithCubes)
			viz.addText("Displaying original cloud", 0, 15, 1.0, 0.0, 0.0, "org_t");
	}

	/* \brief Visual update. Create visualizations and add them to the viewer
	*
	*/
	void update()
	{
		//remove existing shapes from visualizer
		clearView();

		//prevent the display of too many cubes
		bool displayCubeLegend = displayCubes && static_cast<int> (displayCloud->points.size()) <= MAX_DISPLAYED_CUBES;

		showLegend(displayCubeLegend);

		if (displayCubeLegend)
		{
			//show octree as cubes
			showCubes(sqrt(octree.getVoxelSquaredSideLen(displayedDepth)));
			if (showPointsWithCubes)
			{
				//add original cloud in visualizer
				pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> color_handler(cloud, "z");
				viz.addPointCloud(cloud, color_handler, "cloud");
				viz.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, size, "cloud");
			}
		}
		else
		{
			//add current cloud in visualizer
			pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> color_handler(displayCloud, "z");
			viz.addPointCloud(displayCloud, color_handler, "cloud");
			viz.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, size, "cloud");
		}
	}

	/* \brief remove dynamic objects from the viewer
	*
	*/
	void clearView()
	{
		//remove cubes if any
		//vtkRenderer *renderer = viz.getRenderWindow()->GetRenderers()->GetFirstRenderer();
		//while (renderer->GetActors()->GetNumberOfItems() > 0)
		//	renderer->RemoveActor(renderer->GetActors()->GetLastActor());
		viz.removeAllShapes();
		//for (size_t i = 0; i < displayCloud->size(); i++)
		//{

		//	viz.removeShape("cube" + std::to_string(i));
		//}
		//remove point clouds if any
		viz.removePointCloud("cloud");
	}

	/* \brief Create a vtkSmartPointer object containing a cube
	*
	*/
	//vtkSmartPointer GetCuboid(double minX, double maxX, double minY, double maxY, double minZ, double maxZ)
	//{
	//	vtkSmartPointer cube = vtkSmartPointer::New();
	//	cube->SetBounds(minX, maxX, minY, maxY, minZ, maxZ);
	//	return cube->GetOutput();
	//}

	/* \brief display octree cubes via vtk-functions
	*
	*/
	void showCubes(double voxelSideLen)
	{


		//get the renderer of the visualizer object
		//vtkRenderer *renderer = viz.getRenderWindow()->GetRenderers()->GetFirstRenderer();
		//
		//vtkSmartPointer treeWireframe = vtkSmartPointer::New();
		size_t i;
		double s = voxelSideLen / 2.0;
		for (i = 0; i < displayCloud->points.size(); i++)
		{
			
			double x = displayCloud->points[i].x;
			double y = displayCloud->points[i].y;
			double z = displayCloud->points[i].z;
			viz.addCube(x - s, x + s, y - s, y + s, z - s, z + s,0.5,0.5,0.5,"cube"+std::to_string(i));
//#if VTK_MAJOR_VERSION < 6
//			treeWireframe->AddInput(GetCuboid(x - s, x + s, y - s, y + s, z - s, z + s));
//#else
//			treeWireframe->AddInputData(GetCuboid(x - s, x + s, y - s, y + s, z - s, z + s));
//#endif
		}
//
//		vtkSmartPointer treeActor = vtkSmartPointer::New();
//
//		vtkSmartPointer mapper = vtkSmartPointer::New();
//#if VTK_MAJOR_VERSION < 6
//		mapper->SetInput(treeWireframe->GetOutput());
//#else
//		mapper->SetInputData(treeWireframe->GetOutput());
//#endif
//		treeActor->SetMapper(mapper);
//
//		treeActor->GetProperty()->SetColor(1.0, 1.0, 1.0);
//		treeActor->GetProperty()->SetLineWidth(2);
		if (wireframe)
		{
			viz.setRepresentationToWireframeForAllActors();

			//treeActor->GetProperty()->SetRepresentationToWireframe();
			//treeActor->GetProperty()->SetOpacity(0.35);
		}
		else
			viz.setRepresentationToSurfaceForAllActors();
			//treeActor->GetProperty()->SetRepresentationToSurface();
//
//		renderer->AddActor(treeActor);
	}

	/* \brief Extracts all the points of depth = level from the octree
	*
	*/
	void extractPointsAtLevel(int depth)
	{
		displayCloud->points.clear();
		
		pcl::octree::OctreePointCloudVoxelCentroid<pcl::PointXYZ>::Iterator tree_it;
		pcl::octree::OctreePointCloudVoxelCentroid<pcl::PointXYZ>::Iterator tree_it_end = octree.end();
		//pcl::octree::OctreePointCloudVoxelCentroid::DepthFirstIterator tree_it;

		pcl::PointXYZ pt;
		std::cout << "===== Extracting data at depth " << depth << "... " << std::flush;
		double start = pcl::getTime();

		for (tree_it = octree.begin(depth); tree_it != tree_it_end; ++tree_it)
		{

			//if (tree_it.isBranchNode())
			//{
			//	pcl::octree::OctreeBranchNode* branch=tree_it.getCurrentOctreeNode();
			//}
			if (tree_it.getCurrentOctreeDepth()!=depth)
			{
				continue;
			}
			Eigen::Vector3f voxel_min, voxel_max;
			octree.getVoxelBounds(tree_it, voxel_min, voxel_max);

			pt.x = (voxel_min.x() + voxel_max.x()) / 2.0f;
			pt.y = (voxel_min.y() + voxel_max.y()) / 2.0f;
			pt.z = (voxel_min.z() + voxel_max.z()) / 2.0f;
			displayCloud->points.push_back(pt);
		}

		double end = pcl::getTime();
		printf("%lu pts, %.4gs. %.4gs./pt. =====\n", displayCloud->points.size(), end - start,
			(end - start) / static_cast<double> (displayCloud->points.size()));

		update();
	}

	/* \brief Helper function to increase the octree display level by one
	*
	*/
	bool IncrementLevel()
	{
		if (displayedDepth < static_cast<int> (octree.getTreeDepth()))
		{
			displayedDepth++;
			extractPointsAtLevel(displayedDepth);
			return true;
		}
		else
			return false;
	}

	/* \brief Helper function to decrease the octree display level by one
	*
	*/
	bool DecrementLevel()
	{
		if (displayedDepth > 0)
		{
			displayedDepth--;
			extractPointsAtLevel(displayedDepth);
			return true;
		}
		return false;
	}

};

int main(int argc, char ** argv)
{

	//防止VTK的警告
	//vtkOutputWindow::SetGlobalWarningDisplay(0);
	std::string cloud_path("bunny.pcd");
	OctreeViewer v(cloud_path, 0.01);
}

你可能感兴趣的:(算法,c++)