目录
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 键居中并缩放以可见整个点云