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 鍵居中並縮放以可見整個點雲