1. 程式人生 > >PCL——Visualzer視覺化類

PCL——Visualzer視覺化類

目錄

程式碼

1. 視覺化單個點雲

建立視窗物件並給標題欄定義名稱"3D Viewer"

【注】定義"boost :: shared_ptr"智慧共享指標,保證該指標在整個程式全域性使用。

boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));

視窗背景色設定

viewer->setBackgroundColor(0, 0, 0);

點雲新增到視窗物件並定義唯一字串作為ID

利用此字串保證在其他成員方法中也能標誌引用該點雲

多次呼叫 addPointCloud() ,可實現多個點雲的新增,每呼叫一次就建立一個新的ID

更新一個已經顯示的點雲,使用者必須呼叫 removePointCloud() ,並提供需要更新的點雲ID

viewer->addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");

改變點雲的尺寸,控制點雲在視窗中的顯示方式

通過使用 X(紅色)、Y(綠色)、Z(藍色)圓柱體代表座標軸來顯示座標系統的方向

圓柱體的大小通過 scale 引數控制

本例將 scale 引數設定為1.0,該值為預設值

viewer->addCoordinateSystem(1.0);

設定照相機引數,使使用者從預設的角度和方向觀察點雲

viewer->initCameraParameters();

執行一個 while 迴圈,每次呼叫 spinOnce 都給視窗處理事件的時間,允許滑鼠鍵盤等互動操作

	while (!viewer->wasStopped())
	{
		viewer->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}

顯示如下:

2. 視覺化點雲顏色特徵

常用點雲型別:XYZRGB

【注】PCL Visualizer 可根據所儲存的顏色資料為點雲賦色,或者按照使用者自定義的顏色為點雲著色。

建立顏色處理物件 PointCloudColorHandlerRGB ,PCL Visualizer 類利用這樣的物件顯示自定義顏色資料

本例中,PointCloudColorHandlerRGB 物件得到每個點雲的 RGB 顏色欄位

pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(cloud);

新增點雲,可以指定新增到視窗中點雲的 PointCloudColorHandlerRGB 著色處理物件

viewer->addPointCloud<pcl::PointXYZRGB>(cloud, rgb, "sample cloud");

顯示如下:

3. 視覺化點雲自定義顏色特徵

本例中,所使用的點雲型別是 XYZ 型別

【注】在自定義著色處理物件 PointCloudColorHandlerCustom 中,沒有 RGB 顏色欄位,不論所用點雲是什麼型別,都可以為點雲著自定義顏色

建立自定義顏色處理器 PointCloudColorHandlerCustom ,設定顏色為純綠色(0, 255, 0)

pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(cloud, 0, 255, 0);

顯示如下:

4. 視覺化點雲法線和其他特徵

【注】PCL Visualizer 視覺化類可用於繪製法線,也可繪製表徵點雲的其他特徵,比如主曲率和幾何特徵。

使用者一旦得到法線,需要另一行程式在視窗中顯示這些法線

本例中,法線顯示的個數(10個點顯示一個),每個法線的長度(0.05)

viewer->addPointCloudNormals<pcl::PointXYZRGB, pcl::Normal>(cloud, normals, 10, 0.05, "normals");

顯示如下:

5. 繪製普通形狀

1. 繪製點之間連線

【注】此方法可以使得在顯示兩組點雲之間的對應點關係時,方便使用者直觀的觀看點雲之間的對應關係

本例中,新增從點雲第一個點到最後一個點的連線,線用預設顏色

viewer->addLine<pcl::PointXYZRGB>(cloud->points[0],cloud->points[cloud->size() - 1],"line");

2. 新增球體

本例中,新增以點雲中第一個點 points[0] 為中心,半徑為 0.2 的球體,也可以為該球體進行自定義顏色設定。

viewer->addSphere(cloud->points[0], 0.2, 0.5, 0.5, 0.0, "sphere");

3. 繪製平面

使用標準平面方程 ax+by+cz+d=0 來定義平面

本例中,這個平面以原點為中心,方向沿 Z 方向

pcl::ModelCoefficients coeffs;
coeffs.values.push_back(0.0);
coeffs.values.push_back(0.0);
coeffs.values.push_back(1.0);
coeffs.values.push_back(0.0);
viewer->addPlane(coeffs, "plane");

4. 繪製錐形

新增錐形,利用模型係數指定錐形的引數

coeffs.values.clear();
coeffs.values.push_back(0.3);
coeffs.values.push_back(0.3);
coeffs.values.push_back(0.0);
coeffs.values.push_back(0.0);
coeffs.values.push_back(1.0);
coeffs.values.push_back(0.0);
coeffs.values.push_back(5.0);
viewer->addCone(coeffs, "cone");

顯示如下:

6. 多視口顯示

【注】PCL Visualizer 視覺化類允許使用者通過不同視口 Viewport 繪製多個點雲

在本例中,利用不同的搜尋半徑,基於同一點雲計算出對應不同的兩組法線

第一組搜尋半徑為0.05,基於該半徑計算的法線用黑色背景顯示

第二組搜尋半徑為0.1,基於該半徑計算的法線用灰色背景顯示

建立新的視口 v1(0)

所需要的4個引數:X軸的最小值、最大值、Y軸的最小值、最大值,取值在 0 ~ 1

建立的視口在視窗的左半部分

最後一個字串引數,用來唯一標誌該視口

利用 RGB 顏色著色並新增至點雲到當前視口

int v1(0);
viewer->createViewPort(0.0, 0.0, 0.5, 1.0, v1);
viewer->setBackgroundColor(0, 0, 0, v1);
viewer->addText("Radius: 0.05", 10, 10, "v1 text", v1);
pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(cloud);
viewer->addPointCloud<pcl::PointXYZRGB>(cloud, rgb, "sample cloud1", v1);

建立第二視口 v2(0)

建立的視口在視窗的右半部分

將視口背景賦予灰色

利用自定義顏色著色並新增至點雲到當前視口

int v2(0);
viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);
viewer->setBackgroundColor(0.3, 0.3, 0.3, v2);
viewer->addText("Radius: 0.1", 10, 10, "v2 text", v2);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> single_color(cloud, 0, 255, 0);
viewer->addPointCloud<pcl::PointXYZRGB>(cloud, single_color, "sample cloud2", v2);

為所有視口設定屬性

【注】大多數 PCL Visualizer 類的方法成員都有一個可以選擇的視口 ID 引數。當設定該引數時,該方法值作用於所設定的視口,不設定該引數的話,該方法作用於所有視口。

viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud1");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud2");
viewer->addCoordinateSystem(1.0);

為每個視口新增其對應的一組法線

viewer->addPointCloudNormals<pcl::PointXYZRGB, pcl::Normal>(cloud, normals1, 10, 0.05, "normals1", v1);
viewer->addPointCloudNormals<pcl::PointXYZRGB, pcl::Normal>(cloud, normals2, 10, 0.05, "normals2", v2);

顯示如下:

7. 表面法線估計

對所有輸入點雲資料集中的點估計一組表面法線

建立法線估計物件(ne),並將輸入資料集(point_cloud_ptr)傳遞給這個物件

pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;// 建立法線估計物件 ne
ne.setInputCloud(point_cloud_ptr);// 將輸入資料集傳遞給這個物件

建立空的 Kd-tree 物件(tree),並將它傳遞給法線估計物件(ne

pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZRGB>());
ne.setSearchMethod(tree);

建立儲存輸出資料集(cloud_normals1

pcl::PointCloud<pcl::Normal>::Ptr cloud_normals1(new pcl::PointCloud<pcl::Normal>);

設定以查詢點為原點半徑為 5 cm 範圍內的所有鄰元素進行計算(同理 10 cm

ne.setRadiusSearch(0.05);

計算特徵值,並存儲在輸出資料集(cloud_normals1)內(將10 cm 對應結果儲存在 cloud_normals2

ne.compute(*cloud_normals1);

程式碼

#include <iostream>
#include <boost/thread/thread.hpp>
#include <pcl/common/common_headers.h>
#include <pcl/features/normal_3d.h>				// 法線估計類標頭檔案宣告
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/parse.h>

// --------------
// -----Help-----
// --------------
void
printUsage(const char* progName)
{
	std::cout << "\n\nUsage: " << progName << " [options]\n\n"
		<< "Options:\n"
		<< "-------------------------------------------\n"
		<< "-h           this help\n"
		<< "-s           Simple visualisation example\n"
		<< "-r           RGB colour visualisation example\n"
		<< "-c           Custom colour visualisation example\n"
		<< "-n           Normals visualisation example\n"
		<< "-a           Shapes visualisation example\n"
		<< "-v           Viewports example\n"
		<< "\n\n";
}

/*視覺化單個點雲*/
boost::shared_ptr<pcl::visualization::PCLVisualizer> simpleVis(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud)
{
	/*建立檢視物件並定義標題欄“3D Viewer”*/
	//boost::shared_ptr 智慧共享指標,保證該指標在整個程式全域性使用
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
	viewer->setBackgroundColor(0, 0, 0);//視窗背景色設定
	viewer->addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");//新增點雲到視窗物件
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");//渲染屬性
	viewer->addCoordinateSystem(1.0);//顯示點雲的尺寸設定
	viewer->initCameraParameters();//照相機引數設定
	return (viewer);
}

/*視覺化點雲顏色特徵*/
boost::shared_ptr<pcl::visualization::PCLVisualizer> rgbVis(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr cloud)
{
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
	viewer->setBackgroundColor(0, 0, 0);
	pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(cloud);
	viewer->addPointCloud<pcl::PointXYZRGB>(cloud, rgb, "sample cloud");
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");//渲染屬性
	viewer->addCoordinateSystem(1.0);
	viewer->initCameraParameters();
	return (viewer);
}

/*視覺化點雲自定義顏色特徵*/
boost::shared_ptr<pcl::visualization::PCLVisualizer> customColourVis(pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud)
{
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
	viewer->setBackgroundColor(0, 0, 0);
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color(cloud, 0, 255, 0);//顯示綠色
	viewer->addPointCloud<pcl::PointXYZ>(cloud, single_color, "sample cloud");
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");//渲染屬性
	viewer->addCoordinateSystem(1.0);
	viewer->initCameraParameters();
	return (viewer);
}


/*視覺化點雲法線和其他特徵*/
boost::shared_ptr<pcl::visualization::PCLVisualizer> normalsVis(
	pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr cloud, pcl::PointCloud<pcl::Normal>::ConstPtr normals)
{
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
	viewer->setBackgroundColor(0, 0, 0);
	pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(cloud);
	viewer->addPointCloud<pcl::PointXYZRGB>(cloud, rgb, "sample cloud");
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");
	viewer->addPointCloudNormals<pcl::PointXYZRGB, pcl::Normal>(cloud, normals, 10, 0.05, "normals");//顯示點雲法線
	viewer->addCoordinateSystem(1.0);
	viewer->initCameraParameters();
	return (viewer);
}

/*繪製普通形狀*/
boost::shared_ptr<pcl::visualization::PCLVisualizer> shapesVis(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr cloud)
{
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
	viewer->setBackgroundColor(0, 0, 0);
	pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(cloud);
	viewer->addPointCloud<pcl::PointXYZRGB>(cloud, rgb, "sample cloud");
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");
	viewer->addCoordinateSystem(1.0);
	viewer->initCameraParameters();

	//------------------------------------
	//-----Add shapes at cloud points-----
	//------------------------------------
	viewer->addLine<pcl::PointXYZRGB>(cloud->points[0],cloud->points[cloud->size() - 1], "line");//點之間連線
	viewer->addSphere(cloud->points[0], 0.2, 0.5, 0.5, 0.0, "sphere");//

	//---------------------------------------
	//-----Add shapes at other locations-----
	//---------------------------------------
	pcl::ModelCoefficients coeffs;
	coeffs.values.push_back(0.0);
	coeffs.values.push_back(0.0);
	coeffs.values.push_back(1.0);
	coeffs.values.push_back(0.0);
	viewer->addPlane(coeffs, "plane");
	coeffs.values.clear();
	coeffs.values.push_back(0.3);
	coeffs.values.push_back(0.3);
	coeffs.values.push_back(0.0);
	coeffs.values.push_back(0.0);
	coeffs.values.push_back(1.0);
	coeffs.values.push_back(0.0);
	coeffs.values.push_back(5.0);
	viewer->addCone(coeffs, "cone");

	return (viewer);
}

/*多視口顯示點雲法線*/
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewportsVis(
	pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr cloud, pcl::PointCloud<pcl::Normal>::ConstPtr normals1, pcl::PointCloud<pcl::Normal>::ConstPtr normals2)
{
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
	viewer->initCameraParameters();

	int v1(0);
	viewer->createViewPort(0.0, 0.0, 0.5, 1.0, v1);
	viewer->setBackgroundColor(0, 0, 0, v1);
	viewer->addText("Radius: 0.05", 10, 10, "v1 text", v1);
	pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb(cloud);
	viewer->addPointCloud<pcl::PointXYZRGB>(cloud, rgb, "sample cloud1", v1);

	int v2(0);
	viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);
	viewer->setBackgroundColor(0.3, 0.3, 0.3, v2);
	viewer->addText("Radius: 0.1", 10, 10, "v2 text", v2);
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZRGB> single_color(cloud, 0, 255, 0);
	viewer->addPointCloud<pcl::PointXYZRGB>(cloud, single_color, "sample cloud2", v2);

	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud1");
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud2");
	viewer->addCoordinateSystem(1.0);

	viewer->addPointCloudNormals<pcl::PointXYZRGB, pcl::Normal>(cloud, normals1, 10, 0.05, "normals1", v1);
	viewer->addPointCloudNormals<pcl::PointXYZRGB, pcl::Normal>(cloud, normals2, 10, 0.05, "normals2", v2);

	return (viewer);
}

int main(int argc, char** argv)
{
	// --------------------------------------
	// -----———解析命令列引數————-----
	// --------------------------------------
	if (pcl::console::find_argument(argc, argv, "-h") >= 0)
	{
		printUsage(argv[0]);
		return 0;
	}
	bool simple(false), rgb(false), custom_c(false), normals(false),
		shapes(false), viewports(false), interaction_customization(false);
	if (pcl::console::find_argument(argc, argv, "-s") >= 0)
	{
		simple = true;
		std::cout << "Simple visualisation example\n";
	}
	else if (pcl::console::find_argument(argc, argv, "-c") >= 0)
	{
		custom_c = true;
		std::cout << "Custom colour visualisation example\n";
	}
	else if (pcl::console::find_argument(argc, argv, "-r") >= 0)
	{
		rgb = true;
		std::cout << "RGB colour visualisation example\n";
	}
	else if (pcl::console::find_argument(argc, argv, "-n") >= 0)
	{
		normals = true;
		std::cout << "Normals visualisation example\n";
	}
	else if (pcl::console::find_argument(argc, argv, "-a") >= 0)
	{
		shapes = true;
		std::cout << "Shapes visualisation example\n";
	}
	else if (pcl::console::find_argument(argc, argv, "-v") >= 0)
	{
		viewports = true;
		std::cout << "Viewports example\n";
	}
	else
	{
		printUsage(argv[0]);
		return 0;
	}

	// ------------------------------------
	// -----———創造例子點雲————-----
	// ------------------------------------
	pcl::PointCloud<pcl::PointXYZ>::Ptr basic_cloud_ptr(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZRGB>::Ptr point_cloud_ptr(new pcl::PointCloud<pcl::PointXYZRGB>);
	std::cout << "Generating example point clouds.\n\n";
	// 做一個橢圓沿著z軸方向,XYZRGB 點雲的顏色會逐漸從紅到綠到藍
	uint8_t r(255), g(15), b(15);
	for (float z(-1.0); z <= 1.0; z += 0.05)
	{
		for (float angle(0.0); angle <= 360.0; angle += 5.0)
		{
			pcl::PointXYZ basic_point;
			basic_point.x = 0.5 * cosf(pcl::deg2rad(angle));
			basic_point.y = sinf(pcl::deg2rad(angle));
			basic_point.z = z;
			basic_cloud_ptr->points.push_back(basic_point);

			pcl::PointXYZRGB point;
			point.x = basic_point.x;
			point.y = basic_point.y;
			point.z = basic_point.z;
			uint32_t rgb = (static_cast<uint32_t>(r) << 16 |
				static_cast<uint32_t>(g) << 8 | static_cast<uint32_t>(b));
			point.rgb = *reinterpret_cast<float*>(&rgb);
			point_cloud_ptr->points.push_back(point);
		}
		if (z < 0.0)
		{
			r -= 12;
			g += 12;
		}
		else
		{
			g -= 12;
			b += 12;
		}
	}
	basic_cloud_ptr->width = (int)basic_cloud_ptr->points.size();
	basic_cloud_ptr->height = 1;
	point_cloud_ptr->width = (int)point_cloud_ptr->points.size();
	point_cloud_ptr->height = 1;

	// ----------------------------------------------------------------
	// -----——————計算搜尋半徑為0.05的曲面法線————————---
	// ----------------------------------------------------------------
	pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;// 建立法線估計物件 ne
	ne.setInputCloud(point_cloud_ptr);						// 將輸入資料集傳遞給這個物件
	// 建立空的Kd-tree物件,並將它傳遞給法線估計物件
	pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZRGB>());
	ne.setSearchMethod(tree);
	// 儲存輸出資料集
	pcl::PointCloud<pcl::Normal>::Ptr cloud_normals1(new pcl::PointCloud<pcl::Normal>);
	// 使用半徑為5cm範圍內的所有鄰元素
	ne.setRadiusSearch(0.05);
	//計算特徵值
	ne.compute(*cloud_normals1);

	// ---------------------------------------------------------------
	// -----——————計算搜尋半徑為0.1的曲面法線————————---
	// ---------------------------------------------------------------
	pcl::PointCloud<pcl::Normal>::Ptr cloud_normals2(new pcl::PointCloud<pcl::Normal>);
	ne.setRadiusSearch(0.1);
	ne.compute(*cloud_normals2);

	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;
	if (simple)
	{
		viewer = simpleVis(basic_cloud_ptr);
	}
	else if (rgb)
	{
		viewer = rgbVis(point_cloud_ptr);
	}
	else if (custom_c)
	{
		viewer = customColourVis(basic_cloud_ptr);
	}
	else if (normals)
	{
		viewer = normalsVis(point_cloud_ptr, cloud_normals2);
	}
	else if (shapes)
	{
		viewer = shapesVis(point_cloud_ptr);
	}
	else if (viewports)
	{
		viewer = viewportsVis(point_cloud_ptr, cloud_normals1, cloud_normals2);
	}

	//--------------------
	// -----—迴圈---——-
	//--------------------
	while (!viewer->wasStopped())
	{
		viewer->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}
}

【注】在執行時,要在CMD中輸入命令 “pcl_visualizer_demo.exe -h”

使用者可通過改變選項(h、s、r、c、r、a、v)改變所執行的不同視覺化特徵例項

按住 q 鍵退出視窗應用程式,按住 r 鍵居中並縮放以可見整個點雲