首页 > CMake结合PCL库学习(1)

CMake结合PCL库学习(1)

经常会有有人问到CMake的学习的问题,而且网上也有很多博客是介绍学习CMake 的用法,但是我觉的学习不用这样死板,用到了就顺便学习一下,也就是边做边学,由浅入深,慢慢的就会熟悉了,这个学习的过程中会遇到很多问题,以解决问题的方式驱动自己学习CMake,首先总结一下CMake 的好处,CMake是一个跨平台编译的工具,所以不再需要折腾平台了,比如Windows需要创建Visual Studio项目文件,配置环境等问题,Linux创建Makefile,OS X创建Xcode项目文件。实际上大部分你的配置都会是一样的,使用CMake会给你很好的项目维护性,也会降低你的维护成本。

cmake 是kitware 公司以及一些开源开发者在开发几个工具套件(VTK)的过程中衍

生品,最终形成体系,成为一个独立的开放源代码项目。官方网站是www.cmake.org,可以通过访问官方网站获得更多关于cmake 的信息,

Cmake的特点

1,开放源代码,使用类BSD 许可发布。http://cmake.org/HTML/Copyright.html

2,跨平台,并可生成native 编译配置文件,在Linux/Unix 平台,生成makefile,在苹果平台,可以生成xcode,在Windows 平台,可以生成MSVC 的工程文件。

3,能够管理大型项目。

4,简化编译构建过程和编译过程。Cmake 的工具链非常简单:cmake+make。

5,高效虑,可扩展,可以为cmake 编写特定功能的模块,扩充cmake 功能。

提示:

1,如果你没有实际的项目需求,那么看到这里就可以停下来了,因为cmake 的学习过程就是实践过程,没有实践,读的再多几天后也会忘记。

2,如果你的工程只有几个文件,直接编写Makefile 是最好的选择。

3,如果使用的是C/C++/Java 之外的语言,请不要使用cmake(至少目前是这样)

那么接下来我们就根据CMake和PCL库中的各个层级的CMakeLists.txt文件配合讲解CMake的用法。

比如我现在要结合PCL 的库写一个基于点云库的不用数据格式之间转换的代码以及CMake文件的解析:该函数的.cpp文件如下:

/*PCL tutorial by yao 2018.03.23the manager of wechat official account "dianyunPCL"*///这是一个将mesh点云数据转换位OBJ,PCD,PLY,STL,STL,VTK 等格式
//这个工具的可以指定输出文件的存储个格式有ASCII binary 和binary compressed三种可选#include #include 
#include 
#include 
#include #include #define ASCII 0
#define BINARY 1
#define BINARY_COMPRESSED 2/*** Display help for this program* @param argc[in]* @param argv[in]*/
void
displayHelp (int argc,char** argv)
{PCL_INFO ("
Usage: %s [OPTION] SOURCE DEST
", argv[0]);PCL_INFO ("Convert SOURCE point cloud or mesh to DEST.

");PCL_INFO ("Available formats types for SOURCE and DEST:
""	OBJ (Wavefront)
""	PCD (Point Cloud Library)
""	PLY (Polygon File Format)
""	STL (STereoLithography)
""	VTK (The Visualization Toolkit)

");PCL_INFO ("Available options:
""	-f, --format Specify DEST output type, available formats are ascii, binary and binary_compressed.
""	             When not specified, binary is used as default.
""	             OBJ only supports ascii format.
""	             binary_compressed is only supported by the PCD file format.

""	-c --cloud   Output DEST as a point cloud, delete all faces.

");
}bool
saveMesh (pcl::PolygonMesh& input,std::string output_file,int output_type);/*** Saves a cloud into the specified file and output type. The file format is automatically parsed.* @param input[in] The cloud to be saved* @param output_file[out] The output file to be written* @param output_type[in] The output file type* @return True on success, false otherwise.*/
bool
savePointCloud (pcl::PCLPointCloud2::Ptr input,std::string output_file,int output_type)
{if (boost::filesystem::path (output_file).extension () == ".pcd"){//TODO Support precision, origin, orientationpcl::PCDWriter w;if (output_type == ASCII){PCL_INFO ("Saving file %s as ASCII.
", output_file.c_str ());if (w.writeASCII (output_file, *input) != 0)return (false);}else if (output_type == BINARY){PCL_INFO ("Saving file %s as binary.
", output_file.c_str ());if (w.writeBinary (output_file, *input) != 0)return (false);}else if (output_type == BINARY_COMPRESSED){PCL_INFO ("Saving file %s as binary compressed.
", output_file.c_str ());if (w.writeBinaryCompressed (output_file, *input) != 0)return (false);}}else if (boost::filesystem::path (output_file).extension () == ".stl"){PCL_ERROR ("STL file format does not support point clouds! Aborting.
");return (false);}else  // OBJ, PLY and VTK{//TODO: Support precision//FIXME: Color is lost during OBJ conversion (OBJ supports color)pcl::PolygonMesh mesh;mesh.cloud = *input;if (!saveMesh (mesh, output_file, output_type))return (false);}return (true);
}/*** Saves a mesh into the specified file and output type. The file format is automatically parsed.* @param input[in] The mesh to be saved* @param output_file[out] The output file to be written* @param output_type[in]  The output file type* @return True on success, false otherwise.*/
bool
saveMesh (pcl::PolygonMesh& input,std::string output_file,int output_type)
{if (boost::filesystem::path (output_file).extension () == ".obj"){if (output_type == BINARY || output_type == BINARY_COMPRESSED)PCL_WARN ("OBJ file format only supports ASCII.
");//TODO: Support precision//FIXME: Color is lost during conversion (OBJ supports color)PCL_INFO ("Saving file %s as ASCII.
", output_file.c_str ());if (pcl::io::saveOBJFile (output_file, input) != 0)return (false);}else if (boost::filesystem::path (output_file).extension () == ".pcd"){if (!input.polygons.empty ())PCL_WARN ("PCD file format does not support meshes! Only points be saved.
");pcl::PCLPointCloud2::Ptr cloud = boost::make_shared (input.cloud);if (!savePointCloud (cloud, output_file, output_type))return (false);}else  // PLY, STL and VTK{if (output_type == BINARY_COMPRESSED)PCL_WARN ("PLY, STL and VTK file formats only supports ASCII and binary output file types.
");if (input.polygons.empty() && boost::filesystem::path (output_file).extension () == ".stl"){PCL_ERROR ("STL file format does not support point clouds! Aborting.
");return (false);}PCL_INFO ("Saving file %s as %s.
", output_file.c_str (), (output_type == ASCII) ? "ASCII" : "binary");if (!pcl::io::savePolygonFile (output_file, input, (output_type == ASCII) ? false : true))return (false);}return (true);
}/*** Parse input files and options. Calls the right conversion function.* @param argc[in]* @param argv[in]* @return 0 on success, any other value on failure.*/
int
main (int argc,char** argv)
{// Display helpif (pcl::console::find_switch (argc, argv, "-h") != 0 || pcl::console::find_switch (argc, argv, "--help") != 0){displayHelp (argc, argv);return (0);}// Parse all files and optionsstd::vector supported_extensions;supported_extensions.push_back("obj");supported_extensions.push_back("pcd");supported_extensions.push_back("ply");supported_extensions.push_back("stl");supported_extensions.push_back("vtk");std::vector file_args;for (int i = 1; i < argc; ++i)for (size_t j = 0; j < supported_extensions.size(); ++j)if (boost::algorithm::ends_with(argv[i], supported_extensions[j])){file_args.push_back(i);break;}std::string parsed_output_type;pcl::console::parse_argument (argc, argv, "-f", parsed_output_type);pcl::console::parse_argument (argc, argv, "--format", parsed_output_type);bool cloud_output (false);if (pcl::console::find_switch (argc, argv, "-c") != 0 ||pcl::console::find_switch (argc, argv, "--cloud") != 0)cloud_output = true;// Make sure that we have one input and one output file onlyif (file_args.size() != 2){PCL_ERROR ("Wrong input/output file count!
");displayHelp (argc, argv);return (-1);}// Convert parsed output type to output typeint output_type (BINARY);if (!parsed_output_type.empty ()){if (parsed_output_type == "ascii")output_type = ASCII;else if (parsed_output_type == "binary")output_type = BINARY;else if (parsed_output_type == "binary_compressed")output_type = BINARY_COMPRESSED;else{PCL_ERROR ("Wrong output type!
");displayHelp (argc, argv);return (-1);}}// Try to load as meshpcl::PolygonMesh mesh;if (boost::filesystem::path (argv[file_args[0]]).extension () != ".pcd" &&pcl::io::loadPolygonFile (argv[file_args[0]], mesh) != 0){PCL_INFO ("Loaded a mesh with %d points (total size is %d) and the following channels:
%s
",mesh.cloud.width * mesh.cloud.height, mesh.cloud.data.size (), pcl::getFieldsList (mesh.cloud).c_str ());if (cloud_output)mesh.polygons.clear();if (!saveMesh (mesh, argv[file_args[1]], output_type))return (-1);}else if (boost::filesystem::path (argv[file_args[0]]).extension () == ".stl"){PCL_ERROR ("Unable to load %s.
", argv[file_args[0]]);return (-1);}else{// PCD, OBJ, PLY or VTKif (boost::filesystem::path (argv[file_args[0]]).extension () != ".pcd")PCL_WARN ("Could not load %s as a mesh, trying as a point cloud instead.
", argv[file_args[0]]);//Eigen::Vector4f origin; // TODO: Support origin/orientation//Eigen::Quaternionf orientation;pcl::PCLPointCloud2::Ptr cloud (new pcl::PCLPointCloud2);if (pcl::io::load (argv[file_args[0]], *cloud) < 0){PCL_ERROR ("Unable to load %s.
", argv[file_args[0]]);return (-1);}PCL_INFO ("Loaded a point cloud with %d points (total size is %d) and the following channels:
%s
", cloud->width * cloud->height, cloud->data.size (),pcl::getFieldsList (*cloud).c_str ());if (!savePointCloud (cloud, argv[file_args[1]], output_type)){PCL_ERROR ("Failed to save %s.
", argv[file_args[1]]);return (-1);}}return (0);
}

对应的CMakeLists.txt文件的编写如下 ,有些基本理解

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)   #Cmake的最低版本project(yao_pcl)   #PROJECT(project_name [CXX] [C] [Java])这个指令定义工程名称,后面可以指定工程所支持的语言,当然也是可以不写忽略的,那么默认情况下就是支持所有语言的,set(SRC_LIST yao_convert.cpp)#SET(SRC_LIST yao_convert.cpp) 这里对于在CMake中关键字对于大小写不敏感#set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])  SET 指令用来显式的定义变量,同时也可以定义多个文件  比如#SET(SRC_LIST main.cpp yao_1.cpp yao_2.cpp)。#PCL库find_package(PCL 1.8 REQUIRED)include_directories(${PCL_INCLUDE_DIRS})link_directories(${PCL_LIBRARY_DIRS})add_definitions(${PCL_DEFINITIONS})add_executable(yao_convert ${SRC_LIST})
#定义了这个工程会生成一个文件名为 hello 的可执行文件,相关的源文件是 SRC_LIST 中
#定义的源文件列表,注意这里使用变量引用的方式是${}这是CMake变量应用方式,但是,有一些例外,比如在 IF 控制语句,变量是直接使用变量名引用,而不需要${}
target_link_libraries(yao_convert ${PCL_LIBRARIES})

编译该代码命令:

mkdir build

cd build

cmake …

make

上述过程就是所谓的out-of-source 外部编译,一个最大的好处是,对于原有的工程没 有任何影响,所有动作全部发生在编译目录。通过这一点,也足以说服我们全部采用外部编译方式构建工程。

总结基本语法:

1,变量使用${}方式取值,但是在IF 控制语句中是直接使用变量名

2,指令(参数1 参数2…) 参数使用括弧括起,参数之间使用空格或分号分开。

以上面的ADD_EXECUTABLE 指令为例,如果存在另外一个func.cpp 源文件,就要写成: ADD_EXECUTABLE(hello main.cpp func.cpp)

3,指令是大小写无关的,参数和变量是大小写相关的

关于语法上的疑惑

SET(SRC_LIST main.c)也可以写成SET(SRC_LIST “main.cpp”)

是没有区别的,但是假设一个源文件的文件名是fu nc.c(文件名中间包含了空格)。

这时候就必须使用双引号,如果写成了SET(SRC_LIST fu nc.c),就会出现错误,提示你找不到fu 文件和nc.cpp 文件。这种情况,就必须写成:

SET(SRC_LIST “fu nc.cpp”)

清理工程:

运行: make clean

即可对构建结果进行清理。

以上就是全部内容,可能存在一些错误欢迎指示,并可以发邮件交流,您可以可以关注微信公众号。加入我们翻译小组或者加入经营微信公众号群,也加入技术交流群与跟多的小伙伴一起交流。

在这里插入图片描述

更多相关:

  • 本例的初始文件是4位数字 (e.g. 0001.png),想在前面补1个0 (00001.png) import numpy as np import cv2 from ptsemseg.utils import recursive_glob import osroot = "./src/" root1 = "./dst/" fil...

  • 方法一: QString file("sample.jpg"); if (file.contains(".jpg") ||      file.contains(".bmp") ||      file.contains(".png")) {     qDebug()<<"这是图片。"; } 方法二: QString file_...

  • shell中可能经常能看到:>/dev/null 2>&1 命令的结果可以通过%>的形式来定义输出 分解这个组合:“>/dev/null 2>&1” 为五部分。 1:> 代表重定向到哪里,例如:echo "123" > /home/123.txt 2:/dev/null 代表空设备文件 3:2> 表示stderr标准错误...

  • 第三步,使用JODConverter将office文档转换为pdf       JODConverter是一个java的OpenDucument文件转换器,可以进行许多文件格式的转换,它利用 OpenOffice来进行转换工作,它能进行以下的转换工作:      1.Microsoft Office格式转换为OpenDucument...

  •   测试用prototxt   name: "CIFAR10_quick"layer {name: "data" type: "MemoryData" top: "data" top: "label" memory_data_param {batch_size: 1     #样本个数 channels: 3 height: 32 w...

  •    话说每到吃完的时间就发愁,真的不知道该吃什么,然后就想到做一个生成吃什么的小软件,既然这个软件如此的简单,就打算用wpf开发吧,也不用数据库了,直接保存在xml中就可以了  程序整体结构如下图  首先我写了一个xml的帮助类,主要是写了个常用的增加方法 主程序界面也很简单,一共就两个页面 对应的两处代码也粘上 pr...