Ubuntu环境下LAS数据格式与PCD数据格式的转换

  • 1 LAS简介
  • 2 源文件代码
  • 3 在Ubuntu环境下使用遇到的问题
  • 4 解决办法
  • 1)安装boost库
  • 2)安装liblas库
  • 5 运行功能包


1 LAS简介

  LAS是一种用于激光雷达数据交换的已发布标准文件格式,它保留与激光雷达数据有关的特定信息。每个LAS文件都在页眉块中包含激光雷达测量的元数据,然后是所记录的每个激光雷达脉冲的所有记录。每个 LAS 文件的页眉部分都保留有激光雷达测量本身的属性信息:数据范围、飞行日期、飞行时间、点记录数、返回的点数、使用的所有数据偏移以及使用的所有比例因子。为 LAS 文件的每个激光雷达脉冲保留以下激光雷达点属性:x,y,z 位置信息、GPS 时间戳、强度、回波编号、回波数目、点分类值、扫描角度、附加 RGB 值、扫描方向、飞行航线的边缘、用户数据、点源 ID 和波形信息。

  LibLAS (https://www.liblas.org/)是一套用于处理常见的“LAS”LiDAR格式数据的C/C++函数库。本章主要利用LibLAS库结合PCL点云库进行LAS和PCD两种点云类型的转换。主要利用libLAS库中的liblas::Reader类和liblas::Writer类分别实现LAS数据的读取和写入。具体地,利用liblas::Reader类读入LAS数据,然后利用reader.GetPoint().GetX()、reader.GetPoint().GetY()、reader.GetPoint().GetZ()获取LAS文件每个点的x,y,z坐标赋予PCL的cloud类存储的点的x,y,z坐标,实现LAS数据格式向PCL数据格式的转换;将PCL的cloud类存储的点的x,y,z坐标提取并赋予liblas::Point类构造的点对象,然后利用liblas::Writer类下的WritePoint函数写入LAS类型文件,实现PCD数据格式向LAS数据格式的转换。

2 源文件代码

#include <iostream>
#include <cstdlib>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <ros/package.h>
#include <cstring>
#include "liblas/liblas.hpp"

using namespace std;

int main (int argc, char** argv)
{
	std::string lasFileName = ros::package::getPath("convert_las2pcd") + "/las/ground.las";
    std::ifstream ifs(lasFileName.c_str(), std::ios::in | std::ios::binary);	// 打开las文件
    liblas::ReaderFactory f;
    liblas::Reader reader = f.CreateWithStream(ifs);	// 读取las文件

	unsigned long int nbPoints=reader.GetHeader().GetPointRecordsCount();	// 获取las数据点的个数

	pcl::PointCloud<pcl::PointXYZRGB> cloud;
	cloud.width    = nbPoints;							// 保证与las数据点的个数一致
	cloud.height   = 1;			
	cloud.is_dense = false;
	cloud.points.resize (cloud.width * cloud.height);

	int i=0;				
	uint16_t r1, g1, b1;	
	int r2, g2, b2;			
	uint32_t rgb;			

	while(reader.ReadNextPoint()) 
	{
		// 获取las数据的x,y,z信息
		cloud.points[i].x = (reader.GetPoint().GetX());
	    cloud.points[i].y = (reader.GetPoint().GetY());
	    cloud.points[i].z = (reader.GetPoint().GetZ());
		
		// 获取las数据的r,g,b信息
		r1 = (reader.GetPoint().GetColor().GetRed());
		g1 = (reader.GetPoint().GetColor().GetGreen());
		b1 = (reader.GetPoint().GetColor().GetBlue()); 
		r2 = ceil(((float)r1/65536)*(float)256);
		g2 = ceil(((float)g1/65536)*(float)256);
		b2 = ceil(((float)b1/65536)*(float)256);
		rgb = ((int)r2) << 16 | ((int)g2) << 8 | ((int)b2);
		cloud.points[i].rgb = *reinterpret_cast<float*>(&rgb);
					
		i++; 
	}

	std::string pcdFileName = ros::package::getPath("convert_las2pcd") + "/pcd/pointcloud.pcd";
	pcl::io::savePCDFileASCII(pcdFileName.c_str(), cloud);	// 存储为pcd类型文件

	return (0);
}

3 在Ubuntu环境下使用遇到的问题

  报错:对“liblas::Reader”和“liblas::Point”相关函数未定义的引用,如下所示:

pcl将pcd转mesh pcd转换为las_#include

4 解决办法

1)安装boost库

  (1)官方网站:(https://www.boost.org/),下载最新版本。我下载的版本是:Version 1.76.0,对应的安装包为:boost_1_76_0.tar.gz
  (2)解压文件
  (3)编译
  进入文件夹boost_1_76_0,运行如下脚本:

./bootstrap.sh

运行完成后生成b2和project-config.jam两个文件。
  上述命令可以带有各种选项,具体可参考帮助文档: ./bootstrap.sh --help。其中–prefix参数,可以指定安装路径,如果不带–prefix参数的话(推荐),默认路径是 /usr/local/include 和 /usr/local/lib,分别存放头文件和各种库。
  (4)安装
  编译完成后,进行安装,也就是将头文件和生成的库,放到指定的路径(–prefix)下:

sudo ./b2 install

注意,必须用管理员权限,否则无法写入到/usr/local/*目录下。
  (5)测试
  新建终端,创建文件:

touch testBoost.cpp
gedit testBoost.cpp

  编写测试代码如下:

#include<iostream>
#include<boost/bind.hpp>
using namespace std;
using namespace boost;
int fun(int x,int y){return x+y;}
int main(){
    int m=2;int n=3;
    cout<<boost::bind(fun,_1,_2)(m,n)<<endl;
    return 0;
}

  编译testBoost.cpp:

g++ testBoost.cpp -o testBoost

  编译完后生成可执行程序testBoost,运行它:

./testBoost

  会输出:5
  至此,说明已成功安装boost库。

2)安装liblas库

  (1)官方网站:(https://liblas.org/download.html),下载最新版本。我下载的版本是:Version libLAS-1.8.1,对应的安装包为:libLAS-1.8.1.tar.bz2
  (2)解压文件夹
  (3)编译,执行如下命令:

cd libLAS-1.8.1
mkdir makefiles
cd makefiles
cmake -G "Unix Makefiles" ../

  (4)接着,继续执行如下命令:

make

  在这一步可能会遇到的问题:

[ 1%] Building CXX object src/CMakeFiles/las.dir/header.cpp.o
/home/yuksel/Downloads/liblas/src/header.cpp: In copy constructor ‘liblas::Header::Header(const liblas::Header&)’:
/home/yuksel/Downloads/liblas/src/header.cpp:104:11: warning: variable ‘p’ set but not used [-Wunused-but-set-variable]
void* p = 0;
^
/home/yuksel/Downloads/liblas/src/header.cpp: In member function ‘liblas::Header& liblas::Header::operator=(const liblas::Header&)’:
/home/yuksel/Downloads/liblas/src/header.cpp:123:15: warning: variable ‘p’ set but not used [-Wunused-but-set-variable]
void* p = 0;
^
/home/yuksel/Downloads/liblas/src/header.cpp: In member function ‘void liblas::Header::DeleteVLRs(const string&, uint16_t)’:
/home/yuksel/Downloads/liblas/src/header.cpp:613:69: error: ‘1’ was not declared in this scope
boost::bind( &SameVLRs, name, id, 1 ) ),
^
/home/yuksel/Downloads/liblas/src/header.cpp:613:69: note: suggested alternatives:
In file included from /usr/local/include/boost/mpl/aux/include_preprocessed.hpp:37:0,
from /usr/local/include/boost/mpl/placeholders.hpp:43,
from /usr/local/include/boost/mpl/apply.hpp:24,
from /usr/local/include/boost/mpl/aux/iter_apply.hpp:17,
from /usr/local/include/boost/mpl/aux_/find_if_pred.hpp:14,
from /usr/local/include/boost/mpl/find_if.hpp:17,
from /usr/local/include/boost/mpl/find.hpp:17,
from /usr/local/include/boost/mpl/aux_/contains_impl.hpp:20,
from /usr/local/include/boost/mpl/contains.hpp:20,
from /usr/local/include/boost/multi_index_container.hpp:26,
from /home/yuksel/Downloads/liblas/include/liblas/external/property_tree/ptree.hpp:21,
from /home/yuksel/Downloads/liblas/include/liblas/schema.hpp:46,
from /home/yuksel/Downloads/liblas/include/liblas/point.hpp:47,
from /home/yuksel/Downloads/liblas/include/liblas/bounds.hpp:46,
from /home/yuksel/Downloads/liblas/include/liblas/header.hpp:47,
from /home/yuksel/Downloads/liblas/src/header.cpp:43:
/usr/local/include/boost/mpl/aux_/preprocessed/gcc/placeholders.hpp:29:16: note: ‘mpl_::1’
typedef arg<1> 1;
^
/usr/local/include/boost/mpl/aux/preprocessed/gcc/placeholders.hpp:29:16: note: ‘mpl::1’
In file included from /usr/local/include/boost/bind/bind.hpp:2356:0,
from /usr/local/include/boost/multi_index/sequenced_index.hpp:17,
from /home/yuksel/Downloads/liblas/include/liblas/external/property_tree/ptree.hpp:23,
from /home/yuksel/Downloads/liblas/include/liblas/schema.hpp:46,
from /home/yuksel/Downloads/liblas/include/liblas/point.hpp:47,
from /home/yuksel/Downloads/liblas/include/liblas/bounds.hpp:46,
from /home/yuksel/Downloads/liblas/include/liblas/header.hpp:47,
from /home/yuksel/Downloads/liblas/src/header.cpp:43:
/usr/local/include/boost/bind/placeholders.hpp:46:38: note: ‘boost::placeholders::1’
BOOST_STATIC_CONSTEXPR boost::arg<1> 1;
^
In file included from /usr/local/include/boost/lambda/lambda.hpp:14:0,
from /home/yuksel/Downloads/liblas/src/header.cpp:56:
/usr/local/include/boost/lambda/core.hpp:71:60: note: ‘boost::lambda::{anonymous}::1’
boost::lambda::placeholder1_type& BOOST_ATTRIBUTE_UNUSED 1 = free1;
^
/usr/local/include/boost/lambda/core.hpp:71:60: note: ‘boost::lambda::{anonymous}::1’
In file included from /usr/local/include/boost/mpl/aux/include_preprocessed.hpp:37:0,
from /usr/local/include/boost/mpl/placeholders.hpp:43,
from /usr/local/include/boost/mpl/apply.hpp:24,
from /usr/local/include/boost/mpl/aux/iter_apply.hpp:17,
from /usr/local/include/boost/mpl/aux/find_if_pred.hpp:14,
from /usr/local/include/boost/mpl/find_if.hpp:17,
from /usr/local/include/boost/mpl/find.hpp:17,
from /usr/local/include/boost/mpl/aux/contains_impl.hpp:20,
from /usr/local/include/boost/mpl/contains.hpp:20,
from /usr/local/include/boost/multi_index_container.hpp:26,
from /home/yuksel/Downloads/liblas/include/liblas/external/property_tree/ptree.hpp:21,
from /home/yuksel/Downloads/liblas/include/liblas/schema.hpp:46,
from /home/yuksel/Downloads/liblas/include/liblas/point.hpp:47,
from /home/yuksel/Downloads/liblas/include/liblas/bounds.hpp:46,
from /home/yuksel/Downloads/liblas/include/liblas/header.hpp:47,
from /home/yuksel/Downloads/liblas/src/header.cpp:43:
/usr/local/include/boost/mpl/aux/preprocessed/gcc/placeholders.hpp:29:16: note: ‘mpl::_1’
typedef arg<1> _1;
^
src/CMakeFiles/las.dir/build.make:199: recipe for target ‘src/CMakeFiles/las.dir/header.cpp.o’ failed
make[2]: *** [src/CMakeFiles/las.dir/header.cpp.o] Error 1
CMakeFiles/Makefile2:273: recipe for target ‘src/CMakeFiles/las.dir/all’ failed
make[1]: *** [src/CMakeFiles/las.dir/all] Error 2
Makefile:182: recipe for target ‘all’ failed
make: *** [all] Error 2

  解决办法如下:
  需要对libLAS-1.8.1/src/文件夹下面的header.cpp做如下修改:
  ①增加头文件

#include <boost/bind/bind.hpp>

  ②在函数Header::DeleteVLRs(std::string const& name, uint16_t id)前添加命名空间

using namespace boost::placeholders;

  按上述方式修改header.cpp文件后,重新编译liblas:

cmake ..
make

此时,还会报另外两个错误,如下所示:

In function 'LASErrorEnum LASWriter_SetOutputSRS(LASWriterH , LASSRSH )':
error:'_1' was not declared in this scope
boost::bind(&IsReprojectionTransform, _1)

In function 'LASErrorEnum LASReader_SetOutputSRS(LASReaderH , LASSRSH )':
error:'_1' was not declared in this scope
boost::bind(&IsReprojectionTransform, _1)

  解决办法如下:
  需要对libLAS-1.8.1/src/文件夹下面的c_api.cpp boost做如下修改:
  ①增加头文件

#include<boost/bind/bind.hpp>

  ②在LASErrorEnum LASReader_SetOutputSRS(LASReaderH, LASSRSH)函数前添加

using namespace boost::placeholders;

  ③在LASErrorEnum LASWriter_SetOutputSRS(LASWriterH, LASSRSH)函数前添加

using namespace boost::placeholders;

  按上述方式修改c_api.cpp boost文件后,重新编译liblas:

cmake ..
make

  (5)最后,执行如下命令:

make install

  (6)测试,执行如下命令:

lasinfo ../test/data/TO_core_last_clip.las

  会输出如下类似信息:

---------------------------------------------------------
  Header Summary
---------------------------------------------------------

  Version:                     1.0
  Source ID:                   0
  Reserved:                    0
  Project ID/GUID:             '00000000-0000-0000-0000-000000000000'
  System ID:                   ''
  Generating Software:         'TerraScan'
  File Creation Day/Year:      0/0
  Header Byte Size             227
  Data Offset:                 229
  Header Padding:              2
  Number Var. Length Records:  None
  Point Data Format:           1
  Number of Point Records:     8
  Compressed:                  False
  Number of Points by Return:  4 4 0 0 0 
  Scale Factor X Y Z:          0.01000000000000 0.01000000000000 0.01000000000000
  Offset X Y Z:                -0.00 -0.00 -0.00
  Min X Y Z:                   630262.30 4834500.00 50.90
  Max X Y Z:                   630346.83 4834500.00 55.26
  Spatial Reference:           
Reference defined, but GDAL is not available for WKT support

Geotiff_Information:
   Version: 1
   Key_Revision: 1.0
   Tagged_Information:
      End_Of_Tags.
   Keyed_Information:
      End_Of_Keys.
   End_Of_Geotiff.


---------------------------------------------------------
  Schema Summary
---------------------------------------------------------
  Point Format ID:             1
  Number of dimensions:        13
  Custom schema?:              false
  Size in bytes:               28

  Dimensions
---------------------------------------------------------
  'X'                            --  size: 32 offset: 0
  'Y'                            --  size: 32 offset: 4
  'Z'                            --  size: 32 offset: 8
  'Intensity'                    --  size: 16 offset: 12
  'Return Number'                --  size: 3 offset: 14
  'Number of Returns'            --  size: 3 offset: 14
  'Scan Direction'               --  size: 1 offset: 14
  'Flightline Edge'              --  size: 1 offset: 14
  'Classification'               --  size: 8 offset: 15
  'Scan Angle Rank'              --  size: 8 offset: 16
  'User Data'                    --  size: 8 offset: 17
  'Point Source ID'              --  size: 16 offset: 18
  'Time'                         --  size: 64 offset: 20
  
---------------------------------------------------------
  Point Inspection Summary
---------------------------------------------------------
  Header Point Count: 8
  Actual Point Count: 8

  Minimum and Maximum Attributes (min,max)
---------------------------------------------------------
  Min X, Y, Z: 		630262.30, 4834500.00, 50.90
  Max X, Y, Z: 		630346.83, 4834500.00, 55.26
  Bounding Box:		630262.30, 4834500.00, 630346.83, 4834500.00
  Time:			413665.233600, 414094.846200
  Return Number:	1, 2
  Return Count:		1, 2
  Flightline Edge:	0, 0
  Intensity:		90, 670
  Scan Direction Flag:	0, 0
  Scan Angle Rank:	0, 0
  Classification:	1, 1
  Point Source Id:	0, 0
  User Data:		3, 4
  Minimum Color (RGB):	0 0 0 
  Maximum Color (RGB):	0 0 0 

  Number of Points by Return
---------------------------------------------------------
	(1) 4	(2) 4

  Number of Returns by Pulse
---------------------------------------------------------
	(1) 4	(2) 4

  Point Classifications
---------------------------------------------------------
	8 Unclassified (1) 
  -------------------------------------------------------
  	0 withheld
  	0 keypoint
  	0 synthetic
  -------------------------------------------------------

5 运行功能包

  在编译运行功能包之前,需要修改CMakeLists.txt文件,如下所示:

cmake_minimum_required(VERSION 2.8)
project(convert_las2pcd)

add_compile_options(-std=c++11)

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  roslib
)

find_package(PCL 1.7 REQUIRED)

include_directories(
# include
  ${catkin_INCLUDE_DIRS}
  ${PCL_INCLUDE_DIRS}
)
include_directories(${Boost_INCLUDE_DIRS})

link_directories(${PCL_LIBRARY_DIRS})
link_directories(${catkin_LIB_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (las2pcd src/las2pcd.cpp)
target_link_libraries (las2pcd ${PCL_LIBRARIES} ${Boost_LIBRARIES} ${catkin_LIBRARIES} /usr/local/lib/liblas.so.3)

  注意:如果不在target_link_libraries()中添加/usr/local/lib/liblas.so.3(这个就是liblas库安装路径,需要根据您的安装路径进行修改),则会报对“liblas::Reader”和“liblas::Point”相关函数未定义的引用的错误。

  按照上述操作步骤完成后,进行编译。但是在此时,还遇到另外一个问题,报“libboost_thread.so.xxx.xxx.xxx: cannot open shared object file: No such file or directory”错误,如下所示:

pcl将pcd转mesh pcd转换为las_数据_02

  解决办法如下,在终端中执行如下命令:

sudo ldconfig /usr/local/include/boost/

其中,/usr/local/include/boost/为boost库安装路径