不同格式点云存储结构(txt、pcd、las、ply)整理以及基本的读写、可视化方法
不同格式点云存储结构整理以及基本的读写、可视化方法
- 一、文本(txt)
- 1.1、存储结构
- 1.2、读取
- 二、PCD格式
- 1.1、存储结构
- 1.2、读写
- 1.2.1、open3d读写(python)
- 1.2.2、PCL读写(C++)
- 三、LAS格式
- 3.1、存储结构
- 3.2、读写
- 3.2.1、使用laspy 读写(Python)
- 3.2.2、使用laslib读写(C++)
- 四、PLY格式
- 4.1、存储结构
- 文件头(header)
- 数据区域
- 4.2、读写
- 4.2.1、使用plyfile读写(Python)
- 4.2.2、使用pcl读写(C++)
一、文本(txt)
1.1、存储结构
使用文本格式存储的点云数据文件结构比较简单,每个点是一行记录,点的信息存储格式为 x y z或者 x y z r g b。
1.2、读取
读取文本格式的点云数据时,可以按照一般的文本读取方法,这里记录一下如何使用open3d读取txt格式的点云数据
import open3d as o3d
txt_file=r"D:\test_data\bildstein_station1_xyz_intensity_rgb.txt"pcd=o3d.io.read_point_cloud(txt_file,format='xyz')
o3d.visualization.draw([pcd])
二、PCD格式
一个PCD文件是文件头部分和数据部分组成
1.1、存储结构
字段名 | 字段解释 |
---|---|
VERSION | 指定PCD文件版本 |
FIELDS | 指定一个点可以有的每一个维度和字段的名字 |
SIZE | 用字节数指定每一个维度的大小 |
TYPE | 用一个字符指定每一个维度的类型 |
COUNT | 指定每一个维度包含的元素数据 |
WIDTH | 无序点的数量或者有序点一行中点的数目 |
HEIGHT | 无序点云中设置为1,有序点云中表示行数 |
POINTS | 点云中点的总数 |
DATA | 数据类型,二进制或者ASCII |
1.2、读写
1.2.1、open3d读写(python)
读取pcd点云文件
import open3d as o3d
import numpy as np#读取pcd数据并可视化
pcd_file=r""
pcd=o3d.io.read_point_cloud(pcd_file,format='pcd')#将点云的坐标和颜色转换为numpy格式
points=np.array(pcd.points)
colors=np.array(pcd.colors)#可视化
o3d.visualization.draw([pcd])
保存pcd点云文件
#写入pcd格式
save_file="test2.pcd"#手动定义点云
points=np.array([[8,5,3],[9,0,1],[2,5,3],[0,4,2],[7,2,9],[8,8,4],[9,5,8],[2,5,9],[0,7,5],[11,2,8],[10,9,0]])
colors=np.array([[255,0,0],[255,0,0],[0,255,0],[0,255,0],[0,0,255],[0,0,255],[255,0,255],[255,0,255],[255,255,0],[255,255,0],[255,255,0]])
colors=colors/255pcd=o3d.geometry.PointCloud()pcd.points=o3d.utility.Vector3dVector(points)
pcd.colors=o3d.utility.Vector3dVector(colors)#可视化
o3d.visualization.draw_geometries([pcd])#使用draw方法可视化需要将颜色归一化到0-1之间
# o3d.visualization.draw([pcd])#保存
#o3d.io.write_point_cloud(save_file,pcd,write_ascii=True) #以ascii格式存储点数据集部分
o3d.io.write_point_cloud(save_file,pcd)#以二进制格式存储点数据集部分
pcd点数据集部分保存为ASCII格式
pcd点数据集部分保存为二进制格式,其中rgb是用位存储的方式写入的。
1.2.2、PCL读写(C++)
我们用上面生成的pcd文件做测试
#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>using namespace std;
int main()
{string pcd_file = "D:\\project\\Python\\PointCloud\\test2.pcd";//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);if (pcl::io::loadPCDFile<pcl::PointXYZRGB>(pcd_file,*cloud)==-1){PCL_ERROR("couldn't read file\n");return(-1);}for (size_t i=0;i<cloud->points.size();++i){cout << " " << cloud->points[i].x << " " <<cloud->points[i].y << " " <<cloud->points[i].z << " " <<(int)cloud->points[i].r<< " "<<(int)cloud->points[i].g<<" "<<(int)cloud->points[i].b<< endl;}return 0;
}
打印结果
保存pcd文件
#include <iostream>#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>using namespace std;
int main()
{string pcd_file = "test2.pcd";pcl::PointCloud<pcl::PointXYZRGB> cloud;int data[11][6] = {{8,5,3,255,0,0},{9,0,1,255,0,0},{2,5,3,0,255,0},{0,4,2,0,255,0},{7,2,9,0,0,255},{8,8,4,0,0,255},{9,5,8,255,0,255},{2,5,9,255,0,255},{0,7,5,255,255,0},{11,2,8,255,255,0},{10,9,0,255,255,0}};cloud.width = 11;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 = data[i][0];cloud.points[i].y = data[i][1];cloud.points[i].z = data[i][2];cloud.points[i].r = data[i][3];cloud.points[i].g = data[i][4];cloud.points[i].b = data[i][5];}pcl::io::savePCDFileASCII(pcd_file, cloud);//pcl::io::savePCDFileBinary(pcd_file, cloud);return 0;
}
打开输出的ascii文件
可以看到pcl生成的pcd点云文件与open3d生成的点云文件在颜色部分不一致,主要是数据存储类型导致的,pcl1.7之后颜色部分会保存成整型。具体请参看这里。
三、LAS格式
3.1、存储结构
LAS是一种存储点云的公开数据格式,主要用来存储雷达点云数据,LAZ是对LAS格式的无损压缩。
最新的LAS规格版本是LAS 1.4。laspy库支持1.2~1.4版本的LAS文件。
一个LAS文件有三部分组成:文件头区(Header)、可变长记录区(VLRs)、点集记录区(Point Records)
文件头包含数据版本,点的格式(每个点存储的不同维度)等信息;可变长记录包括一些元信息,如坐标系信息,额外的维度等信息;点集记录区是las文件的核心,记录点的x、y、z坐标信息和r、g、b、classification、intensity等其他属性信息。
点的格式共有11个版本,其中第0版为基础,其他后续版本在第0版的基础上增加了其他字段,具体字段参考这里。
3.2、读写
3.2.1、使用laspy 读写(Python)
在python中可以使用laspy包来读写las点云文件
import laspy
import numpy as nplas_file=r""
las=laspy.read(las_file)
#获取文件头
header=las.header
#点类型
point_format=las.point_format
print(point_format.id)
#属性字段名
dimension_names=point_format.dimension_names
print(list(dimension_names))#点集的外边框
print(header.mins)
print(header.maxs)#点个数
point_num=header.point_count#获取坐标和颜色
las_x=np.array(las.x)
las_y=np.array(las.y)
las_z=np.array(las.z)
las_r=np.array(las.red)
las_g=np.array(las.green)
las_b=np.array(las.blue)#组合
pt=np.stack([las_x,las_y,las_z],axis=1)
colors=np.stack([las_r,las_g,las_b],axis=1)
使用laspy写las文件
save_las_file=r"save_las.las"#以x y z r g b的方式定义点云数据
my_data=np.array([[8,5,3,255,0,0],[9,0,1,255,0,0],[2,5,3,0,255,0],[0,4,2,0,255,0],[7,2,9,0,0,255],[8,8,4,0,0,255],[9,5,8,255,0,255],[2,5,9,255,0,255],[0,7,5,255,255,0],[11,2,8,255,255,0],[10,9,0,255,255,0]])#创建点云文件las=laspy.create(file_version="1.2",points_format=3)las.x=my_data[:,0]las.y=my_data[:,1]las.z=my_data[:,2]las.red=my_data[:,3]las.green=my_data[:,4]las.blue=my_data[:,5]#保存las文件las.write(save_las_file)
3.2.2、使用laslib读写(C++)
使用C++操作las文件可以使用laslib库。
#include <iostream>
#include "lasreader.hpp"
#include "laswriter.hpp"
using namespace std;
int main()
{const string las_file="";LASreadOpener lasreadopener;lasreadopener.set_file_name(las_file.data());LASreader* lasreader=lasreadopener.open();LASheader header=lasreader->header;lasreader->header.unlink();int nbPoints = header.number_of_point_records;float x,y,z;int r,g,b;while(lasreader->read_point()){LASpoint& pointReader= lasreader->point;x=pointReader.get_x();y=pointReader.get_y();z=pointReader.get_z();r=pointReader.get_R();g=pointReader.get_G();b=pointReader.get_B();}delete lasreader;
}
写入las文件
#include <iostream>
#include "lasreader.hpp"
#include "laswriter.hpp"
using namespace std;
int main()
{const string las_file="test.las";int data[11][6] = {{8,5,3,255,0,0},{9,0,1,255,0,0},{2,5,3,0,255,0},{0,4,2,0,255,0},{7,2,9,0,0,255},{8,8,4,0,0,255},{9,5,8,255,0,255},{2,5,9,255,0,255},{0,7,5,255,255,0},{11,2,8,255,255,0},{10,9,0,255,255,0}};LASwriteOpener laswriteropener;laswriteropener.set_file_name(las_file.data());LASheader header;header.point_data_format=3;header.point_data_record_length=34;header.number_of_point_records=11;LASWriter* laswriter = laswriteropener.open(&header);LASpoint point;point.init(&header,header.point_data_format,header.point_data_record_length,&header);double minx=DBL_MAX,miny=DBL_MAX,minz=DBL_MAX;double maxx=-DBL_MAX,maxy=-DBL_MAX,maxz=-DBL_MAX;for(size_t i=0;i<header.point_data_record_length;++i){point.set_x(data[i][0]);point.set_y(data[i][1]);point.set_z(data[i][2]);point.set_R(data[i][3]);point.set_G(data[i][4]);point.set_B(data[i][5]);if(data[i][0]<minx){minx=data[i][0];}if(data[i][1]<miny){minx=data[i][1];}if(data[i][2]<minz){minx=data[i][2];}if(data[i][0]>maxx){maxx=data[i][0];}if(data[i][1]>maxy){maxy=data[i][1];}if(data[i][2]>maxz){maxx=data[i][2];}laswriter->write_point(&point);laswriter->update_inventory(&point);}header.set_bounding_box(minx,miny,minz,maxx.maxy.maxz);laswriter->update_header(&header);I64 total_bytes=laswriter->close();delete laswriter;
}
四、PLY格式
4.1、存储结构
PLY(Polygon File Format)是一种常见的点云存储格式,由斯坦福大学开发,其最早主要用于存储三维扫描仪器的点云数据。
PLY文件是由文件头和数据区两部分组成。
文件头(header)
其中文件头记录的是点云文件中的注释、元素类别和属性,以ply开头,以end header结尾。
ply
...
...
end header
文件头的第二行是文件的存储方式和版本,以format开头,依次是编码方式、版本。编码方式有三种分别是ascii、binary_little_endian 、binary_big_endian。目前PLY只有1.0版本。
ply
format ascii 1.0
...
...
end header
format之后跟注释信息,以comment开头,制作者可以添加一些作者信息,点云基本信息。
ply
format ascii 1.0
comment made by anonymous
comment this file is a cube
...
end header
注释信息comment之后是element元素信息+该种元素的property属性信息,element元素信息包括种类、个数,property属性信息包括属性字段的存储类型和属性名。PLY文件中的元素一般包括顶点(vertex)、面(face)、边(edge)等。元素信息和属性信息应该组合出现,格式如下
element <element name> <number in file>
property <data_type> <property name 1>
property <data_type> <property name 2>
property <data_type> <property name 3>
我们定义一个包含6个顶点和8个面元素的ply文件,文件头如下,
ply
format ascii 1.0
comment made by anonymous
comment this file is a cube
element vertex 6
property float32 x
property float32 y
property float32 z
property uchar red
property uchar green
property uchar blue
element face 8
property list uint8 int32 vertex_index
end_header
数据区域
在文件头后直接开始存储数据,存储形式分为ASCII和二进制。以ASCII为例,先按行记录每个点,全部点记录完成后再按行记录每个面。
0 0 0 0 0 0 (开始记录点,按照x,y,z,r,g,b方式排列)
0 100 0 0 0 0
100 100 0 0 0 0
100 0 0 0 0 0
50 50 75 255 255 255
50 50 -75 255 255 255
3 0 1 4 (开始记录面,按照点个数,点的序号排列,3表示这个面由3个点组成,0,1,4代表该面由第0,1,4个点组成)
3 1 2 4
3 2 3 4
3 0 3 4
3 0 1 5
3 1 2 5
3 2 3 5
3 0 3 5
所以完整的一个ply文件如下
ply
format ascii 1.0
comment made by anonymous
comment this file is a cube
element vertex 6
property float32 x
property float32 y
property float32 z
property uchar red
property uchar green
property uchar blue
element face 8
property list uint8 int32 vertex_index
end_header
0 0 0 0 0 0
0 100 0 0 0 0
100 100 0 0 0 0
100 0 0 0 0 0
50 50 75 255 255 255
50 50 -75 255 255 255
3 0 1 4
3 1 2 4
3 2 3 4
3 0 3 4
3 0 1 5
3 1 2 5
3 2 3 5
3 0 3 5
4.2、读写
4.2.1、使用plyfile读写(Python)
使用plyfile读取ply文件
from plyfile import PlyData,PlyElementfile=r"C:\Users\123\Desktop\test2.ply"
plydata=PlyData.read(file)print(plydata)
print("*************************************************")
#第一种读取方法
elements=plydata.elements
for element in elements:for data in element.data:print(data)
print("*************************************************")
#第二种读取方法
vertex_data=elements[0].data
face_data =elements[1].data
print(vertex_data)
print(face_data)
打印结果
ply
format ascii 1.0
comment made by anonymous
comment this file is a cube
element vertex 6
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
element face 8
property list uchar int vertex_index
end_header
*************************************************
(0., 0., 0., 0, 0, 0)
(0., 100., 0., 0, 0, 0)
(100., 100., 0., 0, 0, 0)
(100., 0., 0., 0, 0, 0)
(50., 50., 75., 255, 255, 255)
(50., 50., -75., 255, 255, 255)
(array([0, 1, 4]),)
(array([1, 2, 4]),)
(array([2, 3, 4]),)
(array([0, 3, 4]),)
(array([0, 1, 5]),)
(array([1, 2, 5]),)
(array([2, 3, 5]),)
(array([0, 3, 5]),)
*************************************************
[( 0., 0., 0., 0, 0, 0) ( 0., 100., 0., 0, 0, 0)(100., 100., 0., 0, 0, 0) (100., 0., 0., 0, 0, 0)( 50., 50., 75., 255, 255, 255) ( 50., 50., -75., 255, 255, 255)]
[(array([0, 1, 4]),) (array([1, 2, 4]),) (array([2, 3, 4]),)(array([0, 3, 4]),) (array([0, 1, 5]),) (array([1, 2, 5]),)(array([2, 3, 5]),) (array([0, 3, 5]),)]
使用plyfile写入ply文件
def write_ply(output_file,text=True):points=[(0,0,0),(0,100,0),(100,100,0),(100,0,0),(50,50,75)]face=np.array([((0,1,2),255,0,0),((0,2,3),255,0,0),((0, 1, 4),0,255,0),((1,2,4),0,0,255),((2,3,4),255,255,0),((0,3,4),0,0,0)],dtype=[('vertex_index','i4',(3,)),('red','u1'),('green','u1'),('blue','u1')])print(face)vertex = np.array(points, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')])el = PlyElement.describe(vertex, 'vertex')face = PlyElement.describe(face, 'face')PlyData([el,face], text=text).write(out_file)
在meshlab中打开
4.2.2、使用pcl读写(C++)
读取ply点云文件
#include <iostream>#include <pcl-1.8/pcl/io/pcd_io.h>
#include <pcl-1.8/pcl/point_types.h>
#include <pcl-1.8/pcl/visualization/cloud_viewer.h>
#include <pcl-1.8/pcl/io/ply_io.h>using namespace std;
int main()
{string ply_file = "C:\\Users\\123\\Desktop\\test7.ply";pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPLYFile<pcl::PointXYZ>(ply_file,*cloud)==-1){return (-1);}cout << cloud->width << " " << cloud->height << endl;for (size_t i=0;i<cloud->points.size();++i){cout << cloud->points[i].x << " " << cloud->points[i].y << " " << cloud->points[i].z << endl;}return (0);
}
保存ply点云文件
#include <iostream>#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>using namespace std;
int main()
{string ply_file = "test2.ply";pcl::PointCloud<pcl::PointXYZRGB> cloud;int data[11][6] = {{8,5,3,255,0,0},{9,0,1,255,0,0},{2,5,3,0,255,0},{0,4,2,0,255,0},{7,2,9,0,0,255},{8,8,4,0,0,255},{9,5,8,255,0,255},{2,5,9,255,0,255},{0,7,5,255,255,0},{11,2,8,255,255,0},{10,9,0,255,255,0}};cloud.width = 11;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 = data[i][0];cloud.points[i].y = data[i][1];cloud.points[i].z = data[i][2];cloud.points[i].r = data[i][3];cloud.points[i].g = data[i][4];cloud.points[i].b = data[i][5];}pcl::io::savePLYFile(ply_file, cloud);return 0;
}
不同格式点云存储结构(txt、pcd、las、ply)整理以及基本的读写、可视化方法相关推荐
- [20150113]关于oracle的存储结构.txt
[20150113]关于oracle的存储结构.txt --这阵子在看vage写的>,里面第一章提到: --P2 --每个文件的前128个块,都是文件头,被Oracle留用了.在oracle 1 ...
- 微信小程序云存储中调用fileid作为图片路径,无法正常显示解决方法
教同学们写一个图片瀑布流的微信小程序,图片是放到云存储中的,大多数同学都没有问题,有个别同学出现了下方的问题,图片无法正常显示 查阅了官方的资料,发现image组件的src从2.3.0 起开始支持云文 ...
- C语言手写二叉树(链式存储结构)
C语言手写二叉树(链式存储结构) 二叉树结构 二叉树基本运算 代码 图例(main函数执行过程如下:) 阶段I 阶段II 阶段III 阶段IV 阶段V 先序遍历输出过程 二叉树结构 二叉树可以用顺序存 ...
- 论文:云存储区块链技术:系统文献综述
Blockchain Technology for Cloud Storage: A Systematic Literature Review 本文链接:https://download.csdn.n ...
- 云豹直播系统源码接入华为云存储,含问题及解决方法
云豹直播系统源码接入华为云存储该怎么做? 一.云豹直播系统源码接入华为云存储的前期准备工作 1.注册云服务账号开通对象存储服务. (1)登录公有云网站.在页面右上角单击"注册".按 ...
- 关于asc、txt格式到pcd、ply格式数据转换
1 asc数据说明 许多点云数据是asc或txt数据格式,asc(ascii)即文本文件,数据已可视化的文本存储.在点云数据处理时,常面临数据格式转换问题,比如说需要转换成pcd或ply数据格式. 2 ...
- 利用 labelCloud 开源工具标注自己的点云数据集为KITTI标注格式教程(支持pcd、bin格式点云)
先贴地址 github 地址:https://github.com/ch-sa/labelcloud 标注为KITTI格式的复现步骤与操作流程 首先吧pcd格式点云转乘bin格式 克隆代码 git c ...
- 《Fabric 云存储的电子健康病历系统》(3)病历结构体API
1. IPMR初始化患者病历 IPMR 初始化患者病历接口通过 initRecords()方法实现,根据接口传入的病历信息完成病历初始化并将病历 Records 记录到账本中. 5 个参数:病历 ID ...
- 实现Scrapy框架爬取酷狗音乐Top100名,并存储为TXT,JSON,CSV和Excel格式数据
前言 实现Scrapy框架爬取网页数据(酷狗音乐Top100名,包括排名信息.歌手信息.歌曲名.歌曲时长) 一.创建项目 在cmd中输入: scrapy startproject kugouScrap ...
最新文章
- Java并发编程高级篇(八):在执行器中取消任务
- 《当程序员的那些狗日日子》(十五)首次接单
- 实例——在编程过程中进行单元测试
- 第五十三篇、OC利用AFN上传视频到服务器
- linux不自动创建sda1,linux下头挂载新硬盘(转)
- 使用Hibernate和Spring构建Java Web应用程序
- 机器学习从入门到精通50讲(二)-千万级流量压力测试
- Android教程之android平台水波效果!提供源码!
- 查看php项目tp版本,tp5.1如何查看版本号
- python基础 - 字符串与列表的基本操作方法
- 发卡网源码附企业发卡网源码搭建安装教程
- android将照片压缩并显示,android拍照选择图库后将照片剪裁压缩显示到imageview上 -电脑资料...
- 群晖日历同步到android,用群晖calander日历做华为手机、ipad、mac三方通讯录和日历同步 2020-12-28...
- Swagger官网与官方文档
- 计算机硬件技术心得,计算机硬件技术基础学习心得.doc
- 用友u8服务器优化,用友U8erp软件运行的性能优化方案图文教程
- 国内外技术论坛的区别
- 班尼机器人维修方法_工业机器人常见故障和修理方法
- Linux下安装tuned以使用tuned-adm命令优化Linux系统性能
- mcjava盗版联机_使用N2N组建虚拟局域网联机游戏(我的世界 Java版)
热门文章
- pi六轴算法_PIMars六轴压电平台系统.PDF
- goroutine中使用recover,解决协程中出现panic,导致程序崩溃的问题。recover panic 协程的错误处理
- 禅道怎么启动mysql_解决禅道(ZenTao)Mysql启动不了的有关问题_mysql
- 路由表、静态路由、RIP
- ct文件用什么打开(ce修改器怎么打开ct文件)
- Python--获取电脑配置信息--完整代码及过程
- [春秋云镜]CVE-2020-19960,CVE-2020-19961
- 主成分分析法 (PCA) 用于数据可视化实验 -- Matlab版
- 产品总监(经理)应该具备的能力
- 关于 DellEMC 安装系统时找不到系统硬盘的问题