不同格式点云存储结构(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 headerformat之后跟注釋信息,以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 54.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)整理以及基本的读写、可视化方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 百度云显示服务器返回错误,网站加入百度云
- 下一篇: WAP资源