博客摘录「 不同格式点云存储结构(txt、pcd、las、ply)整理以及基本的读写、可视化方法」2024年3月23日

不同格式点云存储结构(txt、pcd、las、ply)整理以及基本的读写、可视化方法GHZhao_GIS_RS于 2021-07-15 16:52:51 发布阅读量2.9w 收藏 349点赞数 60分类专栏: 点云 文章标签: 点云 存储格式 读写版权点云专栏收录该内容56 篇文章732 订阅¥19.90¥99.00订阅专栏超级会员免费看不同格式点云存储结构整理以及基本的读写、可视化方法一、文本(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 o3dtxt_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])12345二、PCD格式一个PCD文件是文件头部分和数据部分组成1.1、存储结构字段名 字段解释VERSION 指定PCD文件版本FIELDS 指定一个点可以有的每一个维度和字段的名字SIZE 用字节数指定每一个维度的大小TYPE 用一个字符指定每一个维度的类型COUNT 指定每一个维度包含的元素数据WIDTH 无序点的数量或者有序点一行中点的数目HEIGHT 无序点云中设置为1,有序点云中表示行数POINTS 点云中点的总数DATA 数据类型,二进制或者ASCII1.2、读写1.2.1、open3d读写(python)读取pcd点云文件import open3d as o3dimport 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])12345678910111213保存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)#以二进制格式存储点数据集部分1234567891011121314151617181920212223242526272829303132333435363738394041424344pcd点数据集部分保存为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;}1234567891011121314151617181920212223242526272829打印结果保存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;}1234567891011121314151617181920212223242526272829303132333435363738394041424344打开输出的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 laspyimport numpy as nplas_file=r""las=laspy.read(las_file)#获取文件头header=las.header#点类型point_format=las.point_formatprint(point_format.id)#属性字段名dimension_names=point_format.dimension_namesprint(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)1234567891011121314151617181920212223242526272829303132使用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) 1234567891011121314151617181920212223242526273.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;}1234567891011121314151617181920212223242526272829303132333435写入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;}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879四、PLY格式4.1、存储结构PLY(Polygon File Format)是一种常见的点云存储格式,由斯坦福大学开发,其最早主要用于存储三维扫描仪器的点云数据。PLY文件是由文件头和数据区两部分组成。文件头(header)其中文件头记录的是点云文件中的注释、元素类别和属性,以ply开头,以end header结尾。ply......end header1234文件头的第二行是文件的存储方式和版本,以format开头,依次是编码方式、版本。编码方式有三种分别是ascii、binary_little_endian 、binary_big_endian。目前PLY只有1.0版本。plyformat ascii 1.0......end header12345format之后跟注释信息,以comment开头,制作者可以添加一些作者信息,点云基本信息。plyformat ascii 1.0comment made by anonymouscomment this file is a cube...end header123456注释信息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>1234我们定义一个包含6个顶点和8个面元素的ply文件,文件头如下,plyformat ascii 1.0comment made by anonymouscomment this file is a cubeelement vertex 6property float32 xproperty float32 yproperty float32 zproperty uchar redproperty uchar greenproperty uchar blueelement face 8property list uint8 int32 vertex_indexend_header1234567891011121314数据区域在文件头后直接开始存储数据,存储形式分为ASCII和二进制。以ASCII为例,先按行记录每个点,全部点记录完成后再按行记录每个面。0 0 0 0 0 0 (开始记录点,按照x,y,z,r,g,b方式排列)0 100 0 0 0 0100 100 0 0 0 0100 0 0 0 0 050 50 75 255 255 25550 50 -75 255 255 2553 0 1 4 (开始记录面,按照点个数,点的序号排列,3表示这个面由3个点组成,0,1,4代表该面由第0,1,4个点组成)3 1 2 43 2 3 43 0 3 43 0 1 53 1 2 53 2 3 53 0 3 51234567891011121314所以完整的一个ply文件如下plyformat ascii 1.0comment made by anonymouscomment this file is a cubeelement vertex 6property float32 xproperty float32 yproperty float32 zproperty uchar redproperty uchar greenproperty uchar blueelement face 8property list uint8 int32 vertex_indexend_header0 0 0 0 0 00 100 0 0 0 0100 100 0 0 0 0100 0 0 0 0 050 50 75 255 255 25550 50 -75 255 255 2553 0 1 4 3 1 2 43 2 3 43 0 3 43 0 1 53 1 2 53 2 3 53 0 3 5123456789101112131415161718192021222324252627284.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.elementsfor element in elements: for data in element.data: print(data)print("*************************************************")#第二种读取方法vertex_data=elements[0].dataface_data =elements[1].dataprint(vertex_data)print(face_data)123456789101112131415161718打印结果plyformat ascii 1.0comment made by anonymouscomment this file is a cubeelement vertex 6property float xproperty float yproperty float zproperty uchar redproperty uchar greenproperty uchar blueelement face 8property list uchar int vertex_indexend_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]),)]123456789101112131415161718192021222324252627282930313233343536使用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)12345678910111213141516171819202122232425在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);}123456789101112131415161718192021222324252627保存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;}123456789101112131415161718192021222324252627282930313233343536373839404142434445

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值