内容主要来自于PCL官方教程、3d特征法向量。
PCL教程大多在linux系统实现,所以在windows下需要改编。
作者认为3D特征,最起码应该有3个特性:
1.刚体变换。也就是说该特征应当具有3D变换不变性。
2.采样密度。不受传感器采样密度限制。
3.抗噪音。
以3D特征中的法向量为例,写了一段程序。
法向量是几何渲染中的重要特征,一般会结合光照方向和视点,达到镜面反射、漫反射等的效果。如果对opengl有所了解,就知道没有法向量就无法完成光照渲染。opengl并没有提供关于法向量的计算,但PCL提供了计算法向量的算法,所以两者通常搭配使用,实现点云光照渲染。
主要方法是结合PCA方法的最小二乘法,也就是主成分分析,是一种降维和降噪方法,主要保留一些协方差较大的分量,并建立另一个相互正交的坐标系,来表示当前特征。
那为什么保留协方差较大的分量呢?测试技术中,通常认为方差小的是噪音,大的是信号。
#include "pch.h"
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/io/io.h>
#include <pcl/features/integral_image_normal.h>
#include <pcl/visualization/cloud_viewer.h>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
int main()
{
// load point cloud
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("table_scene_mug_stereo_textured.pcd", *cloud);
// estimate normals
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
pcl::IntegralImageNormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setNormalEstimationMethod(ne.AVERAGE_3D_GRADIENT);
ne.setMaxDepthChangeFactor(0.02f);
ne.setNormalSmoothingSize(10.0f);
ne.setInputCloud(cloud);
ne.compute(*normals);
pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> fildColor(cloud, "z"); // 按照z字段进行渲染
// visualize normals
pcl::visualization::PCLVisualizer viewer("PCL Viewer");
viewer.setBackgroundColor(0.0, 0.0, 0.5);
viewer.addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals);
//viewer.addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");
viewer.addPointCloud<pcl::PointXYZ>(cloud, fildColor, "1");
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "1");
while (!viewer.wasStopped())
{
viewer.spinOnce();
}
return 0;
}
需要注意三点问题:
第一点是报错问题,需要再源代码基础上加上
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
第二点是法向计算,只计算有组织点云,也就是height不为1的点云。
第三点是调用函数
addPointCloudpcl::PointXYZ(cloud, fildColor, “1”);
PCL库会在内部为其设置一个名叫1的点云块。
下次调用时,直接调用这个名叫1的点云块就可以。比如:
viewer.addPointCloudpcl::PointXYZ(cloud, fildColor, “1”);
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, “1”);
先存了一个叫做1的点云块,然后调用了函数设置了这块点云的点大小。
其中提及的Z渲染不重要,不过是为点云块赋色,所以没有详细说明。