保存点云数据_PCL入门系列三——PCL进行数据读写

本节课我们将了解到以下内容:

  1. 基本的PCL中的数据类型;
  2. 使用PCL进行简单编程:写文件与读文件。

一、PCL库基本数据类型

上一节课,我们使用PCL库在本地写入了一个名为test_pcd.pcd的文件。我们划分一下程序的任务步骤:

  1. 构造pcd文件格式;
  2. 写入文件;
  3. 打印输出。

14aca9cc5c16d22253181bacac1ccc25.png

步骤二和步骤三的内容属于基本的C++知识。而步骤一中的pcd文件格式是我们所不熟悉的,所以要先看一看pcd原始文件。

在命令行中输入:

more test_pcd.pcd


可以看到pcd文件的内部结构如下图所示。

cb3e07e5ad81fd0a4c0e23483dda3153.png

三维点云数据最简单的形式是x y z的三维点空间坐标。稍微复杂一些可以加上intensity、RGB等属性。但是这种表达方式有什么缺点呢?

一方面直接以文本形式存储点云的三个坐标在内存上比较浪费空间,另一方面如果用户要取得点云的一些基本信息如点云个数,用户还要自己去查询。如果有一个文件头能够简洁的描述点云数据信息,那么无论是在存储效率还是数据信息提取等方面都会有一定帮助。

pcd格式可以视作“文件格式头+三维点信息”。

请看一个具体pcd文件的例子:

# .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.35222197 -0.15188313 -0.10639524
-0.3974061 -0.47310591 0.29260206
………………………………

这个pcd文件里有着不同的字段。常用的有以下几种。

  • VERSION - PCD文件的版本号(通常为0.7);
  • FIELDS - 每个点所包含的维度或字段(例如x y z);
  • SIZE - 每个数据维度所占据的字节(比如float为4字节)
  • TYPE -每个数据维度的数据类型(I= signed,U= unsigned,F=float)
  • COUNT - 每个数据维度上包含的元素个数。(比如,x, y, or z的count为1,但是hisogram的count包含N)
  • WIDTH - 点云的宽度
  • HEIGHT - 点云的高度
  • VIEWPOINT - 点云的视角 translation (tx ty tz) +quaternion (qw qx qy qz)
  • POINTS -点云的数量
  • DATA -具体的数据存储格式(ascii or binary)

在之前的内容中我们忽略了一个小小的但是相对重要的知识点:待填充的数据怎么表示?请注意这里不能简单的使用字符串xyz的形式进行填充,如果仍旧使用字符串的格式进行填充,那么pcd文件格式在存储上的优势根本无法体现。一种简单的方法是为点云数据定义一个结构体,详细的情况后文再叙,这里先罗列一下最常用的数据类型(当然自定义数据类型也可)。

Point Types
PointXYZ- float x, y, z
PointXYZI- float x, y, z, intensity
PointXYZRGB- float x, y, z, rgb
PointXYZRGBA- float x, y, z, uint32t rgba
Normal- float normal[3], curvature
PointNormal- float x, y, z, normal[3], curvature
Histogram- float histogram[N]
………………

二、利用PCL写点云文件

现在详细看一下生成点云写入文件的过程。

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>intmain (int argc, char** argv)
{pcl::PointCloud<pcl::PointXYZ> cloud;// Fill in the cloud datacloud.width    = 5;cloud.height   = 1;cloud.is_dense = false;cloud.points.resize (cloud.width * cloud.height);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);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);
}

关键的部分可以分为以下内容:生成点云、写入文件。

生成点云可以视作一个字段填充的过程,我们来看看具体干了什么事情。

初始化定义一个点云对象,此处我们创建了一个PointXYZ对象

pcl::PointCloud<pcl::PointXYZ> cloud;

设置pcd文件字段,将想要填的内容填进去。

// Fill in the cloud datacloud.width    = 5;cloud.height   = 1;cloud.is_dense = false;cloud.points.resize (cloud.width * cloud.height);

填充具体的值

  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);

三、读取pcd文件

读写不分家。读文件的过程同样并不复杂。

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>int
main (int argc, char** argv)
{pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile<pcl::PointXYZ> ("test_pcd.pcd", *cloud) == -1) //* load the file{PCL_ERROR ("Couldn't read file test_pcd.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::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);

读取点云

pcl::io::loadPCDFile<pcl::PointXYZ> ("test_pcd.pcd", *cloud) == -1

对!就是这么简单。

四、xyz文件转成pcd文件

现在让我们研究一个小小的案例。有时候,我们的原始点云数据是存放在txt文件里的。也许它长成这样:

20.623 40.276 -1.999 -1031 127 141 154
20.362 40.375 -2.239 -941 130 141 159
20.36 40.376 -2.402 -1083 139 151 165
20.374 40.367 -2.405 -1122 131 147 163
20.372 40.366 -2.405 -1165 132 145 161
20.375 40.364 -2.404 -1036 133 149 165
20.358 40.371 -2.405 -1137 139 151 165
20.359 40.374 -2.404 -1086 139 151 165
…………

前三个字段为xyz,第四个字段为intensity,后三个字段为rgb。如何将这样的数据转成pcd文件呢?先上代码,运行起来再说。将下列代码复制并保存到xyz2cpp文件。这个程序将xyzirgb数据转成pcd格式的xyzrgb数据。如果想从xyz的数据转成pcd数据,那么只需要剔除若干填充字段即可。

#include <pcl/io/pcd_io.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>using namespace std;
using namespace pcl;
using namespace pcl::io;
using namespace pcl::console;void
printHelp (int, char **argv)
{print_error ("Syntax is: %s input.xyz output.pcdn", argv[0]);
}bool
loadCloud (const string &filename, PointCloud<PointXYZRGB> &cloud)
{ifstream fs;fs.open (filename.c_str (), ios::binary);if (!fs.is_open () || fs.fail ()){PCL_ERROR ("Could not open file '%s'! Error : %sn", filename.c_str (), strerror (errno)); fs.close ();return (false);}string line;vector<string> st;while (!fs.eof ()){getline (fs, line);// Ignore empty linesif (line.empty())continue;// Tokenize the lineboost::trim (line);boost::split (st, line, boost::is_any_of ("tr "), boost::token_compress_on);if (st.size () != 7)continue;pcl::PointXYZRGB point;point.x = float (atof (st[0].c_str ())); point.y = float (atof (st[1].c_str ())); point.z = float (atof (st[2].c_str ()));point.r = uint8_t (atof (st[4].c_str ()));point.g = uint8_t (atof (st[5].c_str ()));point.b = uint8_t (atof (st[6].c_str ()));cloud.push_back (point);}fs.close ();cloud.width = uint32_t (cloud.size ()); cloud.height = 1; cloud.is_dense = true;return (true);
}int
main (int argc, char** argv)
{print_info ("Convert a simple XYZ file to PCD format. For more information, use: %s -hn", argv[0]);if (argc < 3){printHelp (argc, argv);return (-1);}// Parse the command line arguments for .pcd and .ply filesvector<int> pcd_file_indices = parse_file_extension_argument (argc, argv, ".pcd");vector<int> xyz_file_indices = parse_file_extension_argument (argc, argv, ".xyz");if (pcd_file_indices.size () != 1 || xyz_file_indices.size () != 1){print_error ("Need one input XYZ file and one output PCD file.n");return (-1);}// Load the first filePointCloud<PointXYZRGB> cloud;if (!loadCloud (argv[xyz_file_indices[0]], cloud)) return (-1);// Convert to PCD and savepcl::io::savePCDFileASCII (argv[pcd_file_indices[0]], cloud);
}

创建CMakeList.txt文件

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)project(xyz2pcd)find_package(PCL 1.2 REQUIRED)include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})add_executable (xyz2pcd xyz2pcd.cpp)
target_link_libraries (xyz2pcd ${PCL_LIBRARIES})

创建build文件夹按照前一节课所讲的内容进行编译。

运行下列命令./xyz2pcd smalldata.xyz smalldata.pcd

其中smalldata.xyz为待转换的文件,smalldata.pcd为目标文件。如果没有数据可以将下列数据存为smalldata.xyz与xyz2pcd 放在同一级目录下。请注意这里intensity这个字段并没有用到,如果想用intensity字段,请自定义数据类型。

测试数据

20.623 40.276 -1.999 -1031 127 141 154
20.362 40.375 -2.239 -941 130 141 159
20.36 40.376 -2.402 -1083 139 151 165
20.374 40.367 -2.405 -1122 131 147 163
20.372 40.366 -2.405 -1165 132 145 161
20.375 40.364 -2.404 -1036 133 149 165
20.358 40.371 -2.405 -1137 139 151 165
20.359 40.374 -2.404 -1086 139 151 165
20.354 40.375 -2.404 -1106 139 148 163
20.356 40.374 -2.404 -1059 139 151 165
20.359 40.374 -2.399 -1059 138 150 166
20.359 40.374 -2.395 -1014 138 150 166
20.354 40.375 -2.395 -1042 138 150 166
20.356 40.374 -2.396 -1050 138 150 166
20.354 40.374 -2.393 -1031 137 149 165
20.356 40.374 -2.393 -1045 137 149 165
20.359 40.374 -2.392 -957 137 149 165
20.374 40.365 -2.402 -1093 133 149 165
20.375 40.367 -2.401 -1096 133 149 165
20.374 40.367 -2.399 -1158 133 149 165
20.371 40.367 -2.399 -1093 133 146 162
20.365 40.371 -2.405 -1283 133 145 159
20.361 40.371 -2.404 -1211 133 145 159
20.362 40.372 -2.405 -1314 133 145 159
20.36 40.373 -2.405 -1213 139 151 165
20.361 40.375 -2.404 -1116 139 151 165
20.363 40.375 -2.402 -1063 133 145 159
20.367 40.371 -2.405 -1231 133 145 159
20.365 40.375 -2.405 -1311 133 145 159
20.367 40.372 -2.404 -1173 133 145 159

至此运行成功,结果如下:

a2ec8fd7bda2b717b70a85dbf5dbefca.png

或许大家会感到疑惑为什么RGB转成了一个大整数?这里为了方便存储使用了移位拼接的方法。下节课我们继续讨论可视化等更深入的内容。

参考材料:

http://www.pointclouds.org/documentation/tutorials/writing_pcd.php#writing-pcd

http://pointclouds.org/documentation/tutorials/pcd_file_format.php

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/343623.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机辅助技术课设,《计算机辅助设计技术》课程标准-20210311103339.doc-原创力文档...

.《计算机辅助设计技术》课程标准教研室主任&#xff1a;专业带头人&#xff1a;(部 )主任&#xff1a;教务处处长&#xff1a;教学副院长&#xff1a;审核批准日期&#xff1a;二○一三年 十二月Word 资料.《计算机辅助设计》课程标准(基本信息)课程编码&#xff1a;课程类别&…

工业交换机技术优点

工业领域工作过的人都会知道&#xff0c;工业上的交换机称之为工业以太网交换机&#xff0c;工业以太网交换机就是我们常说的工业交换机&#xff0c;工业交换机是专门为了满足灵活多变的工业应用需求而设计的工业设备&#xff0c;它提供一种高性价比工业以太网通讯解决方案。所…

win8系统的计算机共享在哪里设置方法,win10系统设置与win8系统局域网文件共享的方案...

win10系统使用久了&#xff0c;好多网友反馈说关于对win10系统设置与win8.1系统局域网文件共享设置的方法&#xff0c;在使用win10系统的过程中经常不知道如何去对win10系统设置与win8.1系统局域网文件共享进行设置&#xff0c;有什么好的办法去设置win10系统设置与win8.1系统局…

python中输入字符串中只有字母_python中,只有一个字母的字符串属于类型

python中,只有一个字母的字符串属于类型 答:字符串 智慧职教: 静脉输液流程输液规划的哪一种形式? 答:程序 26. 患者,男性,38岁,体重80kg,从高空坠落后导致肝破裂,入院后须立即进行手术治疗。住院处护理人员首先应 答:护送患者入院 中国大学MOOC: 有人说:“流浪汉都是不想…

光端机的使用方法

光端机是一种不仅可以传输视频信号&#xff0c;还能传输音频、电话、网络、和很多种控制信号的以太网介质传输设备&#xff0c;目前主要使用安防监控行业。那么&#xff0c;光端机是怎么使用的&#xff0c;接下来就由飞畅科技的小编来为大家详细介绍下光端机的使用方法吧&#…

python脚本设置环境变量_详解如何设置Python环境变量?

家好&#xff0c;我是Yivies&#xff01;相信大家多多少少遇到过这样的情况吧&#xff1f;就是在安装了python之后想完整在命令提示符直接输入python就可以使用的操作&#xff0c;但是会出现输入了python之后找不到命令的情况&#xff01;例如这样↓↓↓但是&#xff01;这并不…

vmware服务器虚拟化实施文档,VMware服务器虚拟化

vmware服务器虚拟化技术,简介了服务器虚拟化解决的问题以及vmware服务器虚拟化技术Vm最新版的服务器虚拟化解决方案貌似叫做vSphere_4.1&#xff0c;其中也是包括了ESX和Vcenter来实现功能的&#xff0c;主要能够实现的功能有&#xff1a;1、 Vmotion&#xff0c;实现虚拟机的动…

使用Junit参数在更短的时间内编写更好的单元测试

大多数人都知道单元测试的重要性和好处&#xff0c;以及为什么要在进行的项目中使用它们。 而且&#xff0c;大多数人不喜欢在他们从事的项目中编写单元测试。 TDD的人当然处于另一面&#xff0c;但根据我的经验&#xff0c;他们在IT行业中是少数派。 说到我&#xff0c;我和大…

光端机常见五大故障问题及解决方法

光端机&#xff0c;就是光信号传输的终端设备。光端机在安防中的作用&#xff0c;主要还是起到光端机本身的传输作用。光端机的作用是把一些传输距离比较近的信号转换为传输距离相对较远的信号进行传输&#xff0c;主要的作用是增加传输距离和在监控中起到节约成本的作用。光端…

用香港服务器建收费网站,使用香港站群服务器搭建网站的好处有哪些?

香港站群服务器搭建网站的作用&#xff1a;1、香港站群服务器有利于提高网站被搜索引擎收录情况;2、搭建站群能够有效降低网站被封的风险;3、当网站遭受攻击时&#xff0c;可快速通过带有独立IP的网站来查出问题所在&#xff0c;从而有效提高服务器的维护。香港站群服务器搭建站…

分数化简_分数应用题七讲 (一) 图示法解分数应用题

一、今日一讲图示法就是用线段图(或其它图形)把题目中的已知条件和问题表示出来&#xff0c;这样可以把抽象的数量关系具体化&#xff0c;往往可以从图中找到解题的突破口。运用图示法教学应用题&#xff0c;是培养思维能力的有效方法之一。图示法不仅可以形象地、直观地反映分…

E1光端机和2M光端机有什么区别?

光端机&#xff0c;电信非压缩光端机&#xff0c;就是将多个E1&#xff08;一种中继线路的数据传输标准&#xff0c;通常速率为2.048Mbps&#xff0c;此标准为中国和欧洲采用&#xff09;信号变成光信号并传输的设备。E1的定义的就是2048K。 接下来我们就来为大家详细介绍下光端…

javadoc maven_创建Maven源代码和Javadoc工件

javadoc maven许多人都知道Maven源代码和Javadoc工件&#xff0c;但是不知道为什么要创建它们。 我绝对是在这个阵营中–我可以理解为什么人们想要此信息&#xff0c;但是由于需要手动导航Maven存储库&#xff0c;因此获取信息似乎相对效率较低。 然后我被线索棒击中。 这些工…

发送广播_DHCP服务器什么时候发送?为什么request要广播发送?那还不看?

动态主机配置协议&#xff1a;DHCP 用来集中管理、分配IP地址&#xff0c;使网络环境中的主机能够动态获取IP地址、网关地址、DNS服务器地址等信息&#xff1b;DHCP采用客户端服务器模式&#xff0c;端口号&#xff1a;客户端为68(中继模式下67)&#xff0c;服务器端为67版本一…

开关量光端机指示灯说明及常见故障问题处理方法

开关量光端机可以使开关量信号通过光缆在光纤上传输双向控制。全数字光传输通道&#xff0c;确保高质量的信号传输。面板上有电源指示灯、光信号指示灯数据信号指示灯&#xff0c;可以直观的检测电源、光信号、数据信号状态。单向系列开关量光端机是高性能&#xff0c;高可靠性…

为特使建立控制平面的指南-部署权衡

部署控制平面组件 构建并设计了控制平面后&#xff0c;您将需要确切确定如何部署其组件。 在这里&#xff0c;您可以选择将控制平面与数据平面共置一处以集中控制平面。 这里还有一个中间立场&#xff1a;部署与控制平面位于同一位置的某些组件&#xff0c;并使某些组件保持集中…

大牛服务器超时位置模拟失败,大牛模拟定位掉线怎么办 | 手游网游页游攻略大全...

发布时间&#xff1a;2016-07-07在第四期"微分享"活动中,有许多游戏大牛向小智讲述了关于玩游戏的妙招.巧招和绝招,现小智将这些内容推送给大家! 1.如何在3v3中取得好名次?(由"天才的小白"玩家供稿) 打3v3 ...标签&#xff1a;游乐网 游戏攻略发布时间&am…

宋佳乐博客全站正版PHP源码下载丨自助建站源码丨音乐外链源码丨最新图床源码丨官方网站源码丨网页跳转源码丨云相册源码丨打包下载

本套源码共包含了六套网站系统&#xff0c;请在下方看演示站&#xff1a; 一&#xff1a;主页跳转演示地址&#xff1a;http://ssl.songjiale.com&#xff08;无演示图&#xff09; 二&#xff1a;官方网站演示地址&#xff1a;http://ssl.songjiale.com/upload &#xff08;…

丰田pcs可以关闭吗_别只知道开不坏,现在的丰田还有这些厉害绝招!

记得我刚毕业一年多的时候&#xff0c;有个同龄的同事——三金&#xff0c;买了一台丰田的卡罗拉。那是一台上一代的卡罗拉。三金之所以买卡罗拉&#xff0c;就是图它省心省油保养便宜。那一代卡罗拉采用了keen-look设计&#xff0c;算是在年轻化上迈出了半只脚后来大家调侃他“…

模拟光端机与数字光端机的区别详解

模拟光端机采用了 PFM调制技术实时传输图象信号。发射端将模拟视频信号先进行PFM调制后&#xff0c;再进行电-光转换&#xff0c;光信号传到接收端后&#xff0c;进行光电转换&#xff0c;然后进行 PFM解调&#xff0c;恢复出视频信号。数字光端机是一种通过数字电路控制光信号…