PCLVisualizer是PCL的全功能可视化类。虽然使用比CloudViewer更复杂,但功能也更强大,提供了显示法线,绘图形状和多个视口等功能。
本教程将使用代码示例来说明PCLVisualizer的一些功能,从显示单个点云开始。大部分代码示例都是样板文件,用于设置将被可视化的点云。每个样本的相关代码都包含在特定于该样本的函数中。代码如下所示。将其复制保存到文件名为pcl_visualizer_demo.cpp
中。
/* \author Geoffrey Biggs */
#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"
<< "-i Interaction Customization example\n"
<< "\n\n";
}
boost::shared_ptr<pcl::visualization::PCLVisualizer> simpleVis (pcl::PointCloud<pcl::PointXYZ>::ConstPtr cloud)
{
// --------------------------------------------
// -----Open 3D viewer and add point cloud-----
// --------------------------------------------
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)
{
// --------------------------------------------
// -----Open 3D viewer and add point 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)
{
// --------------------------------------------
// -----Open 3D viewer and add point 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)
{
// --------------------------------------------------------
// -----Open 3D viewer and add point cloud and 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)
{
// --------------------------------------------
// -----Open 3D viewer and add point 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)
{
// --------------------------------------------------------
// -----Open 3D viewer and add point cloud and normals-----
// --------------------------------------------------------
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.01", 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);
}
unsigned int text_id = 0;
void keyboardEventOccurred (const pcl::visualization::KeyboardEvent &event,
void* viewer_void)
{
pcl::visualization::PCLVisualizer *viewer = static_cast<pcl::visualization::PCLVisualizer *> (viewer_void);
if (event.getKeySym () == "r" && event.keyDown ())
{
std::cout << "r was pressed => removing all text" << std::endl;
char str[512];
for (unsigned int i = 0; i < text_id; ++i)
{
sprintf (str, "text#%03d", i);
viewer->removeShape (str);
}
text_id = 0;
}
}
void mouseEventOccurred (const pcl::visualization::MouseEvent &event,
void* viewer_void)
{
pcl::visualization::PCLVisualizer *viewer = static_cast<pcl::visualization::PCLVisualizer *> (viewer_void);
if (event.getButton () == pcl::visualization::MouseEvent::LeftButton &&
event.getType () == pcl::visualization::MouseEvent::MouseButtonRelease)
{
std::cout << "Left mouse button released at position (" << event.getX () << ", " << event.getY () << ")" << std::endl;
char str[512];
sprintf (str, "text#%03d", text_id ++);
viewer->addText ("clicked here", event.getX (), event.getY (), str);
}
}
boost::shared_ptr<pcl::visualization::PCLVisualizer> interactionCustomizationVis ()
{
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
viewer->setBackgroundColor (0, 0, 0);
viewer->addCoordinateSystem (1.0);
viewer->registerKeyboardCallback (keyboardEventOccurred, (void*)viewer.get ());
viewer->registerMouseCallback (mouseEventOccurred, (void*)viewer.get ());
return (viewer);
}
// --------------
// -----Main-----
// --------------
int
main (int argc, char** argv)
{
// --------------------------------------
// -----Parse Command Line Arguments-----
// --------------------------------------
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 if (pcl::console::find_argument (argc, argv, "-i") >= 0)
{
interaction_customization = true;
std::cout << "Interaction Customization example\n";
}
else
{
printUsage (argv[0]);
return 0;
}
// ------------------------------------
// -----Create example point cloud-----
// ------------------------------------
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 << "Genarating example point clouds.\n\n";
// We're going to make an ellipse extruded along the z-axis. The colour for
// the XYZRGB cloud will gradually go from red to green to blue.
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;
// ----------------------------------------------------------------
// -----Calculate surface normals with a search radius of 0.05-----
// ----------------------------------------------------------------
pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> ne;
ne.setInputCloud (point_cloud_ptr);
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>);
ne.setRadiusSearch (0.05);
ne.compute (*cloud_normals1);
// ---------------------------------------------------------------
// -----Calculate surface normals with a search radius of 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);
}
else if (interaction_customization)
{
viewer = interactionCustomizationVis();
}
//--------------------
// -----Main loop-----
//--------------------
while (!viewer->wasStopped ())
{
viewer->spinOnce (100);
boost::this_thread::sleep (boost::posix_time::microseconds (100000));
}
}
#编译和运行程序
将下面的行添加到您的CMakeLists.txt
文件中:
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
project(pcl_visualizer_viewports)
find_package(PCL 1.2 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable (pcl_visualizer_demo pcl_visualizer_demo.cpp)
target_link_libraries (pcl_visualizer_demo ${PCL_LIBRARIES})
在创建可执行文件之后,可以像这样运行它:
./pcl_visualizer_demo -h
更改选项以更改执行的演示。有关详情,请参阅帮助输出。
要退出查看器应用程序,请按q
。按下r
可以居中放大查看器,以便可以看到整个云。通过点击和拖动鼠标来旋转视点。您可以使用滚轮,或者右键单击并上下拖动以放大和缩小。中点击并拖动将移动相机。
#可视化单个云
本示例使用PCLVisualizer来
显示单个PointXYZ云
。它还说明改变背景颜色和显示轴。代码在函数simpleVis
中。
_images/pcl_visualizer_simple.png
说明
该simpleVis
函数显示如何执行点云的最基本的可视化。让我们一行一行地看看这个函数。
...
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
...
这创建了查看器对象,给它一个不错的名字并显示在标题栏中。我们将它存储在一个boost::shared_ptr
中,所以它可以在演示程序中传递。通常情况下,你不需要这样做。
...
viewer->setBackgroundColor (0, 0, 0);
...
查看器的背景颜色可以设置为任何你喜欢的RGB颜色。在这种情况下,我们将其设置为黑色。
...
viewer->addPointCloud<pcl::PointXYZ> (cloud, "sample cloud");
...
这是最重要的一条线。我们将点云添加到查看器,给它一个ID字符串,可用于识别其他方法的云。多点云可以添加多个呼叫addPointCloud()
,每次提供一个新的ID。如果要更新已显示的点云,则必须先调用removePointCloud()
并提供要更新的云的ID。(注意:PCL1.1及以上版本提供了一种新的API方法, updatePointCloud()
允许在不手动调用removePointCloud()
的情况下更新点云。)
这是addPointCloud()
许多变化中最基本的。其他用于处理不同的点类型,显示法线等等。在本教程中,我们将介绍其他一些功能,或者您可以查看PCLVisualizer文档以获取更多详细信息。
...
viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
...
改变渲染点的大小。您可以使用此方法控制在查看器中渲染点云的方式。
...
viewer->addCoordinateSystem (1.0);
...
查看复杂的点云通常会让人迷失方向。为了让自己与世界保持一致,可以显示轴。这些将沿X(红色),Y(绿色)和Z(蓝色)轴显示为三个圆柱体。可以使用scale
参数来控制圆柱体的大小。在这种情况下,我们将其设置为1.0(如果没有给定值,这也是默认值)
。这种方法的另一个版本可以用来放置世界上任何一点的坐标轴。
...
viewer->initCameraParameters ();
...
This final call sets up some handy camera parameters to make things look nice.
最后有一段代码与所有样本相关。它可以在示例的底部找到:
...
while (!viewer->wasStopped ())
{
viewer->spinOnce (100);
boost::this_thread::sleep (boost::posix_time::microseconds (100000));
}
...
These lines are running an event loop. Each call to spinOnce
gives the viewer time to process events, allowing it to be interactive. There is also a spin
method, which only needs to be called once.
#添加一些颜色
通常,点云不会使用简单的PointXYZ
类型。一个常见的点类型是PointXYZRGB
,它也包含颜色数据。除此之外,您可能希望对特定的点云进行着色,以使其在观察者中可以区分。PCLVizualizer
提供了用于显示存储在其中的颜色数据或将颜色分配给点云的点云的功能。
RGB点云
许多设备(如Microsoft Kinect
)都会生成带有RGB
数据的点云。PCLVisualizer
可以使用这些数据来显示云,为每个点着色。rgbVis
函数中的代码显示了如何执行此操作。
_images / pcl_visualizer_color_rgb.png
说明
这个示例中的代码跟早期的示例相比没有太多更改。
...
boost::shared_ptr<pcl::visualization::PCLVisualizer> rgbVis (pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr cloud)
...
首先,注意点类型已经从简单的例子改变了。我们现在使用的点类型也为RGB
数据提供了空间。这个很重要; 没有RGB
字段的点(点类型不一定必须PointXYZRGB
,只要它有三个颜色字段),PCLVisualizer
将不知道使用什么颜色。
...
pcl::visualization::PointCloudColorHandlerRGB<pcl::PointXYZRGB> rgb(point_cloud_ptr);
...
接下来,在设置查看器的背景颜色后,我们创建一个颜色处理程序对象。PCLVisualizer
使用这样的对象来显示自定义数据。在这种情况下,对象将从每个点获取RGB
颜色字段供查看器绘制时使用。存在许多其他处理程序用于广泛的目的。我们将在下一个代码示例中看到另一个颜色处理程序,但处理程序也存在用于从点云中绘制颜色和绘制几何图形等其他字段的目的。详细信息请参阅文档。
...
viewer->addPointCloud<pcl::PointXYZRGB> (cloud, rgb, "sample cloud");
...
最后,当我们添加点云时,我们在向查看器添加点云时指定颜色处理程序。
自定义颜色
第二个代码示例演示给点云一个单一的颜色。我们可以使用这种技术为特定的点云提供自己的颜色,使我们能够区分单个的点云。在这个customColourVis
函数中给出的例子中,我们已经将点云的颜色设置为绿色。(我们也增加了点的大小,使颜色更清晰可见。)
_images/pcl_visualizer_color_custom.png
说明
再一次,这个示例中的代码跟早期的示例相比没有太多更改。
...
boost :: shared_ptr < pcl :: visualization :: PCLVisualizer > customColourVis (pcl :: PointCloud < pcl :: PointXYZ > :: ConstPtr cloud )
...
这次使用的点类型再次返回到PointXYZ
。为点云设置自定义颜色处理程序时,底层数据类型是什么并不重要。使用自定义颜色处理程序时,没有任何点字段用于颜色。
...
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> single_color (cloud, 0, 255, 0);
...
我们创建一个自定义颜色处理程序,并为其分配一个漂亮,明亮的绿色色彩。
...
viewer->addPointCloud<pcl::PointXYZ> (cloud, single_color, "sample cloud");
...
和前面的例子一样,我们在调用的时候会传递颜色处理函数 addPointCloud<>()
。
#法线和其他信息
显示法线是了解点云的重要一步。PCLVisualizer类
可以绘制法线,以及其他有趣的点云信息,例如主曲率和几何图形。
normalsVis
函数中的代码示例显示如何显示点云的法线。计算法线的代码将不会在本教程中解释。有关详细信息,请参阅法线计算教程。
_images / pcl_visualizer_normals.png
说明
相关的代码行放在绘制点云的线后面。
...
viewer->addPointCloudNormals<pcl::PointXYZRGB, pcl::Normal> (cloud, normals, 10, 0.05, "normals");
...
一旦你有了法线,在查看器中显示它们只需要一条额外的线。此方法的参数设置要显示的法线数(此处显示每十个法线),以及为每个法线绘制的线的长度(在本例中为0.05)。
#绘图形状
PCLVisualizer
允许您在视图中绘制各种原始形状。这通常用于可视化点云处理算法的结果,例如,通过在其周围绘制透明球体来可视化将哪些点集群视为地标。
shapesVis
函数中的示例代码演示了向查看器添加形状的一些方法。它增加了四个形状:
从云中的第一个点到云中的最后一个点的一条线。
在起源的飞机。
一个以云中第一个点为中心的球体。
沿着Y轴的一个锥体。
_images / pcl_visualizer_shapes.png
说明
将点云添加到查看器后,绘制形状的代码示例的相关部分开始。
...
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");
...
下一行添加了一个以半径为0.2,云中第一个点为中心的球体。它也给球体一个颜色。
...
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");
...
接下来,我们为绘图添加一架平面。在这种情况下,我们使用标准平面方程(ax + by + cz + d = 0)
来指定平面。我们的平面将以原点为中心,沿着Z轴定向。许多形状绘制函数以这种方式获取系数。
...
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");
...
最后,我们添加一个锥体。我们再次使用模型系数来指定锥的参数。
#Multiple viewports
您经常需要并排比较多个点云。虽然你可以在同一个视图端口绘制它们,但这可能会让人困惑。PCLVisualizer
允许您在单独的视口中绘制多个点云,使比较变得简单。
viewportsVis
函数中的代码使用视口来演示比较为点云计算的法线。计算相同云的两组法线,但使用不同的搜索半径。第一次,搜索半径是0.05。第二次是0.1。0.05半径搜索的法线将显示在黑色背景的视口中。0.1半径搜索的法线将显示在灰色背景的视口中。
并排比较这两组法线使得立即明白不同算法参数的效果如何。通过这种方式,您可以尝试使用算法的参数来查找良好设置,快速查看结果。
_images/pcl_visualizer_viewports.png
说明
...
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.01", 10, 10, "v1 text", v1);
pcl::visualization::PointCloudColorHandlerRGBField<pcl::PointXYZRGB> rgb (cloud);
viewer->addPointCloud<pcl::PointXYZRGB> (cloud, rgb, "sample cloud1", v1);
...
下一步是创建一个新的viewport。这四个参数是X和Y轴上的viewport的最小和最大范围,介于0和1之间。我们正在创建一个viewport,以填充窗口的左半部分。我们必须存储在第五个参数中传回的视口ID号,并将其用于所有其他只影响该viewport的调用。
我们还设置了这个viewport的背景颜色,根据我们使用viewport区分的内容给它一个标签,并且使用一个RGB颜色处理器来添加我们的点云。
...
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);
...
这三行为全部viewport设置了一些属性。大多数PCLVisualizer
方法接受可选的viewport ID参数。指定时,它们只影响该viewport。如果不是,就像在这种情况下一样,它们影响所有的viewport。
...
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);
...
最后,我们添加法线,每个viewport一个。
#交互定制
您有时会觉得默认的鼠标和键绑定提供的交互选项不能满足您的需求,您可能需要扩展功能,例如在按下按钮或注释特定位置时可能保存当前显示的点云用鼠标绘制窗口等等,比如,在这个interactionCustomizationVis
方法中可以找到一个非常简单的例子。
注意
在Mac平台上,如果使用7.0以前的VTK版本,则需要将可执行文件构建为应用程序包,以便获得适当的鼠标和键盘交互支持。有关如何执行此操作的更多说明,请参阅Cocoa VTK Wiki。
在本教程的这一部分,您将看到如何捕捉鼠标和键盘事件。通过右键单击窗口,将出现一个2D文本,您可以通过按r
来删除所有文本实例。结果应该是这样的:
_images/pcl_visualizer_interaction_customization.png
说明
...
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
viewer->initCameraParameters ();
...
这是实例化查看器的标准代码。
...
viewer->registerKeyboardCallback (keyboardEventOccurred, (void*)&viewer);
viewer->registerMouseCallback (mouseEventOccurred, (void*)&viewer);
...
这两行代码将分别注册两个方法,keyboardEventOccurred
以及mouseEventOccurred
键盘和鼠标事件回调。这两个方法调用的第二个参数是所谓的cookie。这些是您可能要传递给回调函数的任何参数。在我们的情况下,我们想要传递查看器本身,以便在用户交互的情况下对其进行修改。请注意,这些参数必须是单个void*
实例的形式 ,所以我们需要将指针指向我们的boost::shared_ptrto void*
。
...
void mouseEventOccurred (const pcl::visualization::MouseEvent &event,
void* viewer_void)
{
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer = *static_cast<boost::shared_ptr<pcl::visualization::PCLVisualizer> *> (viewer_void);
if (event.getButton () == pcl::visualization::MouseEvent::LeftButton && event.getType () == pcl::visualization::MouseEvent::MouseButtonRelease)
{
std::cout << "Left mouse button released at position (" << event.getX () << ", " << event.getY () << ")" << std::endl;
char str[512];
sprintf (str, "text#%03d", text_id ++);
viewer->addText ("clicked here", event.getX (), event.getY (), str);
}
}
...
这是处理鼠标事件的方法。每当任何一种鼠标事件被注册时,这个函数都会被调用。为了确切地看到事件是什么,我们需要从event
实例中提取这些信息。在我们的例子中,我们正在寻找鼠标左键释放。每当发生这种事件时,我们将在鼠标点击的位置写一个小文本。
...
void keyboardEventOccurred (const pcl::visualization::KeyboardEvent &event,
void* viewer_void)
{
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer = *static_cast<boost::shared_ptr<pcl::visualization::PCLVisualizer> *> (viewer_void);
if (event.getKeySym () == "r" && event.keyDown ())
{
std::cout << "r was pressed => removing all text" << std::endl;
char str[512];
for (unsigned int i = 0; i < text_id; ++i)
{
sprintf (str, "text#%03d", i);
viewer->removeShape (str);
}
text_id = 0;
}
}
...
键盘事件也适用同样的方法。我们检查按下了什么按键,我们所做的动作是删除鼠标点击所创建的所有文本。请注意,当按下r
时,3D摄像机仍按照PCLVisualizer
中r
的原始绑定进行重置。所以,我们的键盘事件不会覆盖基类的功能。