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数据格式的转换。
#include
#include
#include
#include
#include
#include
#include
#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);
}
报错:对“liblas::Reader”和“liblas::Point”相关函数未定义的引用,如下所示:
(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
#include
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库。
(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
②在函数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
②在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
-------------------------------------------------------
在编译运行功能包之前,需要修改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”错误,如下所示:
解决办法如下,在终端中执行如下命令:
sudo ldconfig /usr/local/include/boost/
其中,/usr/local/include/boost/为boost库安装路径