赞
踩
参考引用
当存在颜色信息时,点云变为 4D(下图一为 3D,下图二为 4D)
PCL 中的所有模块和算法都是通过 Boost 共享指针来传送数据,因而避免了多次复制系统中已存在的数据
# .PCD v.7 - Point Cloud Data file format
VERSION .7 # 版本号
FIELDS x y z rgb # 指定一个点可以有的每一个维度和字段的名字
SIZE 4 4 4 4 # 用字节数指定每一个维度的大小。例如:
TYPE F FFF # 用一个字符指定每一个维度的类型
COUNT 1 1 1 1 # 指定每一个维度包含的元素数目,默认情况下,如果没有COUNT,所有维度的数目被设置成1
WIDTH 640 # 像图像一样的有序结构,有640行和480列,
HEIGHT 480 # 这样该数据集中共有640*480=307200个点
VIEWPOINT 0 0 0 1 0 0 0 # 指定数据集中点云的获取视点 视点信息被指定为平移(tx ty tz)+ 四元数(qw qx qy qz)
POINTS 307200 # 指定点云中点的总数。从0.7版本开始,该字段就有点多余了
DATA ascii # 指定存储点云数据的数据类型。支持两种数据类型:ascii和二进制
0.93773 0.33763 0 4.2108e+06
0.90805 0.35641 0 4.2108e+06
- 根据激光测量原理得到的点云,包含三维坐标信息(xyz)和激光反射强度信息(intensity),其中:激光反射强度与仪器的激光发射能量、波长,目标的表面材质、粗糙程度、入射角相关
- 根据摄影测量原理得到的点云,包括三维坐标(xyz)和颜色信息(rgb)
- 结合两个原理的多传感器融合技术(多见于手持式三维扫描仪),能够同时得到这三种信息
PCL 基本类型 PointCloud:是一个 C++ 的模板类,包含以下字段
衍生类型
为了涵盖能想到的所有可能的情况,PCL 中定义了大量的 point 类型,如果你需要的类型已经存在于 PCL,那么就不需要重复定义了
点云数据转换
/*
ConstPtr:const pointer(常量指针),可理解为传递常量数据的共享指针
1. 为什么要用指针而不直接传数据,因为数据太大了,值传递需要进行对数据的复制
而指针引用不需要,因为涉及到右值传参和类型推断,不加引用的话类型可能发生变化
2. ::constPtr 可以理解为指向常量的共享指针,::Ptr 可以理解为指向一个(可修改的)共享指针
3. ::constPtr& 可以理解为对一个常量消息的共享指针的引用,::Ptr& 可以理解为对一个(可修改的)消息的共享指针的引用
4. 使用共享指针,它是一种智能指针,可以自动管理他指向的内存的存储时间,不必手动释放内存
*/
void elevatedCloudCallback(const sensor_msgs::PointCloud2::ConstPtr &input_cloud) {
pcl::PointCloud<PointT>::Ptr output_cloud(new pcl::PointCloud<PointT>());
pcl::fromROSMsg(*input_cloud, *output_cloud);
//pcl::toROSMsg(pcl::PointCloud<pcl::PointXYZ>, sensor_msgs::PointCloud2); // 逆过程
}
序列化
// 随机生成了 5 个点,并将之以 ASCII 形式保存(序列化)在 test_pcd.pcd 文件中:save_pcd.cpp
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
int main(int argc, char **argv) {
pcl::PointCloud<pcl::PointXYZ> cloud;
// Fill in the cloud data
cloud.width = 5;
cloud.height = 1;
cloud.is_dense = false;
cloud.points.resize(cloud.width * cloud.height);
std::cout << rand() << std::endl;
std::cout << rand() / (RAND_MAX + 1.0f) << std::endl;
std::cout << 1024 * rand() / (RAND_MAX + 1.0f) << std::endl;
// 随机生成5个点
for (size_t i = 0; i < cloud.points.size(); ++i) {
cloud.points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
cloud.points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
cloud.points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
}
pcl::io::savePCDFileASCII("test_pcd.pcd", cloud);
// pcl::io::savePCDFileBinary("test_pcd_binary.pcd", cloud);
std::cerr << "Saved " << cloud.points.size() << " data points to test_pcd.pcd." << std::endl;
for (size_t i = 0; i < cloud.points.size(); ++i)
std::cerr << " " << cloud.points[i].x << " " << cloud.points[i].y << " " << cloud.points[i].z << std::endl;
return (0);
}
// 输出
# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS x y z
SIZE 4 4 4
TYPE F F F
COUNT 1 1 1
WIDTH 5
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 5
DATA ascii
-0.3974061 -0.47310591 0.29260206
-0.73189831 0.66710472 0.44130373
-0.73476553 0.85458088 -0.036173344
-0.46070004 -0.2774682 -0.91676188
0.1837492 0.96880913 0.5120554
// 若保存指令改为 pcl::io::savePCDFileBinary("test_pcd_binary.pcd", cloud); 则输出如下
// 以 binary 的格式进行序列化可以节省空间并提高读写效率
# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS x y z
SIZE 4 4 4
TYPE F F F
COUNT 1 1 1
WIDTH 5
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 5
DATA binary
�x˾�:��ϕ>�];�`�*?���>�<���Z?�*����P���j��(<>�x??
反序列化
// 对一个点云进行反序列化操作,将之保存到 PointCloud 对象中:load_pcd.cpp
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
int main(int argc, char **argv) {
// 准备pcl::PointXYZ类型的点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
// 将pcd中的数据加载到cloud中
if (pcl::io::loadPCDFile<pcl::PointXYZ>("./data/bunny.pcd", *cloud) == -1) { //* load the file
PCL_ERROR ("Couldn't read file bunny.pcd \n");
return (-1);
}
std::cout << "Loaded "
<< cloud->width * cloud->height
<< " data points from test_pcd.pcd with the following fields: "
<< std::endl;
for (size_t i = 0; i < cloud->points.size(); ++i)
std::cout << " " << cloud->points[i].x
<< " " << cloud->points[i].y
<< " " << cloud->points[i].z << std::endl;
return (0);
}
基本使用
其他技巧
鼠标选点打印坐标
// 从弧度到角度
pcl::rad2deg(fllat alpha)
// 从角度到弧度
pcl::deg2rad(float aipha)
// 正则化角度在(-PI,PI)之间
pcl::normAngle(float alpha)
// 计算给定一群点的3D中心点,并且返回一个三维向量
pcl::compute3DCentroid (const pcl::PointCloud< PointT > &cloud, Eigen::Matrix< Scalar, 4, 1 > ¢roid)
// 计算给定的三维点云的协方差矩阵
pcl::computeCovarianceMatrix (const pcl::PointCloud< PointT > &cloud, const Eigen::Matrix< Scalar, 4, 1 > ¢roid, Eigen::Matrix< Scalar, 3, 3 > &covariance_matrix)
// 计算正则化的3*3的协方差矩阵以及给定点云数据的中心点
pcl::computeMeanAndCovarianceMatrix (const pcl::PointCloud< PointT > &cloud, Eigen::Matrix< Scalar, 3, 3 > &covariance_matrix, Eigen::Matrix< Scalar, 4, 1 > ¢roid
// 利用一组点的指数对其进行一般的、通用的nD中心估计
pcl::demeanPointCloud (const pcl::PointCloud< PointT > &cloud_in, const Eigen::Matrix< Scalar, 4, 1 > ¢roid, pcl::PointCloud< PointT > &cloud_out)
pcl::computeNDCentroid (const pcl::PointCloud< PointT > &cloud, Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > ¢roid)
// 计算两个向量之间的角度
pcl::getAngle3D (const Eigen::Vector4f &v1, const Eigen::Vector4f &v2, const bool in_degree=false)
// 同时计算给定点云数据的均值和标准方差
pcl::getMeanStd (const std::vector< float > &values, double &mean, double &stddev)
// 在给定边界的情况下,获取一组位于框中的点
pcl::getPointsInBox (const pcl::PointCloud< PointT > &cloud, Eigen::Vector4f &min_pt, Eigen::Vector4f &max_pt, std::vector< int > &indices)
// 给定点云数据中点与点之间的最大距离的值
pcl::getMaxDistance (const pcl::PointCloud< PointT > &cloud, const Eigen::Vector4f &pivot_pt, Eigen::Vector4f &max_pt)
// 获取给定点云中的在XYZ轴上的最大和最小值
pcl::getMinMax3D (const pcl::PointCloud< PointT > &cloud, PointT &min_pt, PointT &max_pt)
// 计算由三个点pa、pb和pc构成的三角形的外接圆半径
pcl::getCircumcircleRadius (const PointT &pa, const PointT &pb, const PointT &pc)
// 获取点直方图上的最小值和最大值
pcl::getMinMax (const PointT &histogram, int len, float &min_p, float &max_p)
// 根据给定的多边形的点云计算多边形的面积
pcl::calculatePolygonArea (const pcl::PointCloud< PointT > &polygon)
// 从Point_in把字段数据赋值到Point_out
pcl::copyPoint (const PointInT &point_in, PointOutT &point_out)
// 获取两条三维直线之间的最短三维线段
pcl::lineToLineSegment (const Eigen::VectorXf &line_a, const Eigen::VectorXf &line_b, Eigen::Vector4f &pt1_seg, Eigen::Vector4f &pt2_seg)
// 获取点到线的平方距离(由点和方向表示)
pcl::sqrPointToLineDistance (const Eigen::Vector4f &pt, const Eigen::Vector4f &line_pt, const Eigen::Vector4f &line_dir)
// 在给定的一组点中获得最大分段,并返回最小和最大点
pcl::getMaxSegment (const pcl::PointCloud< PointT > &cloud, PointT &pmin, PointT &pmax)
// 确定最小特征值及其对应的特征向量
pcl::eigen22 (const Matrix &mat, typename Matrix::Scalar &eigenvalue, Vector &eigenvector)
// 确定对称半正定输入矩阵给定特征值对应的特征向量
pcl::computeCorrespondingEigenVector (const Matrix &mat, const typename Matrix::Scalar &eigenvalue, Vector &eigenvector)
// 确定对称半正定输入矩阵最小特征值的特征向量和特征值
pcl::eigen33 (const Matrix &mat, typename Matrix::Scalar &eigenvalue, Vector &eigenvector)
// 计算2x2矩阵的逆
pcl::invert2x2 (const Matrix &matrix, Matrix &inverse)
//计算3x3对称矩阵的逆
pcl::invert3x3SymMatrix (const Matrix &matrix, Matrix &inverse)
// 计算3x3矩阵的行列式
pcl::determinant3x3Matrix (const Matrix &matrix)
// 获得唯一 的3D旋转,将Z轴旋转成(0,0,1)Y轴旋转成(0,1,0)并且两个轴是正交的
pcl::getTransFromUnitVectorsZY (const Eigen::Vector3f &z_axis, const Eigen::Vector3f &y_direction, Eigen::Affine3f &transformation)
// 得到将origin转化为(0,0,0)的变换,并将Z轴旋转成(0,0,1)和Y方向(0,1,0)
pcl::getTransformationFromTwoUnitVectorsAndOrigin (const Eigen::Vector3f &y_direction, const Eigen::Vector3f &z_axis, const Eigen::Vector3f &origin, Eigen::Affine3f &transformation)
// 从给定的变换矩阵中提取欧拉角
pcl::getEulerAngles (const Eigen::Transform< Scalar, 3, Eigen::Affine > &t, Scalar &roll, Scalar &pitch, Scalar &yaw)
// 给定的转换中,提取XYZ以及欧拉角
pcl::getTranslationAndEulerAngles (const Eigen::Transform< Scalar, 3, Eigen::Affine > &t, Scalar &x, Scalar &y, Scalar &z, Scalar &roll, Scalar &pitch, Scalar &yaw)
// 从给定的平移和欧拉角创建转换矩阵
pcl::getTransformation (float x, float y, float z, float roll, float pitch, float yaw)
// 保存或者写矩阵到一个输出流中
pcl::saveBinary (const Eigen::MatrixBase< Derived > &matrix, std::ostream &file)
// 从输入流中读取矩阵
pcl::loadBinary (Eigen::MatrixBase< Derived > const &matrix, std::istream &file)
// 获取空间中两条三维直线作为三维点的交点
pcl::lineWithLineIntersection (const Eigen::VectorXf &line_a, const Eigen::VectorXf &line_b, Eigen::Vector4f &point, double sqr_eps=1e-4)
// 获取指定字段的索引(即维度/通道)
pcl::getFieldIndex (const pcl::PCLPointCloud2 &cloud, const std::string &field_name)
// 获取给定点云中所有可用字段的列表
pcl::getFieldsList (const pcl::PointCloud< PointT > &cloud)
// 获取特定字段数据类型的大小(字节)
pcl::getFieldSize (const int datatype)
// 连接 pcl::PCLPointCloud2类型的点云字段
pcl::concatenatePointCloud (const pcl::PCLPointCloud2 &cloud1, const pcl::PCLPointCloud2 &cloud2, pcl::PCLPointCloud2 &cloud_out)
依赖库安装
# install_pcl_dependences.sh
sudo apt-get update
sudo apt-get install git build-essential linux-libc-dev
sudo apt-get install cmake cmake-gui
sudo apt-get install libusb-1.0-0-dev libusb-dev libudev-dev
sudo apt-get install mpi-default-dev openmpi-bin openmpi-common
sudo apt-get install libpcap-dev
sudo apt-get install libflann1.9 libflann-dev
sudo apt-get install libeigen3-dev
sudo apt-get install libboost-all-dev
sudo apt-get install vtk6 libvtk6.3 libvtk6-dev libvtk6.3-qt libvtk6-qt-dev
sudo apt-get install libqhull* libgtest-dev
sudo apt-get install freeglut3-dev pkg-config
sudo apt-get install libxmu-dev libxi-dev
sudo apt-get install mono-complete
sudo apt-get install libopenni-dev libopenni2-dev
源码克隆
$ git clone https://github.com/PointCloudLibrary/pcl.git
编译
$ cd pcl
# 切换到指定版本v1.9.1再编译
$ git checkout pcl-1.9.1
# 创建目录
$ mkdir release
# 进入目录
$ cd release
# 1 配置cmake
$ cmake -DCMAKE_BUILD_TYPE=None \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DBUILD_GPU=ON \
-DBUILD_apps=ON \
-DBUILD_examples=ON ..
# 2.进行编译,也可以 `make -j11` 11 为内核数,按自己的 cpu 内核填写,不写数字默认使用全部核心编译
$ make
安装
$ sudo make install
测试
$ pcl_viewer ../test/pcl_logo.pcd
报错提示
fatal error: pcl/io/pcd_io.h: No such file or directory #include <pcl/io/pcd_io.h>
解决办法
$ sudo ln -s /usr/include/eigen3/Eigen/ /usr/include/Eigen
$ sudo ln -s /usr/include/pcl-1.8/pcl/ /usr/include/pcl
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。