用pcl读ply文件_PCL读取点云慢?自己写一个!

为了方便运算有时候我们只需要点云文件里的坐标信息。尝试在PCL中我们加载点云感觉实在太慢了。索性自己鼓捣了一个读写方案,只取自己需要的信息存在自己定义的数组或者容器里,还方便存取。

这篇文章适合有以下需求的:

1. 需要自己读取ply格式点云坐标并存储预做后续处理的

2. 无论是Ascii 还是二进制码流都支持。

接下来结合功能+代码,提炼我用到的一些方法。

ply文件剖析

有时候不同的软件所生成的ply数据,在标识头部分都有很多信息:

比如:

ply
format binary_little_endian 1.0
comment VCGLIB generated
element vertex 262144
property float x
property float y
property float z
element face 0
property list uchar int vertex_indices
end_header

还有PCL自己生成的(特别长):

ply
format ascii 1.0
comment PCL generated
element vertex 179490
property float x
property float y
property float z
element camera 1
property float view_px
property float view_py
property float view_pz
property float x_axisx
property float x_axisy
property float x_axisz
property float y_axisx
property float y_axisy
property float y_axisz
property float z_axisx
property float z_axisy
property float z_axisz
property float focal
property float scalex
property float scaley
property float centerx
property float centery
property int viewportx
property int viewporty
property float k1
property float k2
end_header

ply文件头部字段说明的信息大概说起来有以下:

ply 格式说明

  • 码流说明(二进制还是Ascii)
  • 来源说明 (PCL还是VCGlib,也有可能是别的库或软件)
  • 坐标数值类型(建议float,PCL目前支持float)
  • 如果带法向,则有法线数值类型(同上)
  • 颜色或强度
  • 曲率
  • ..........

如果是非点云的网格类型ply,后面还有三角面片索引,我就不展开了。

这里我仅针对仅有坐标的ply点云文件进行读写。以下代码如果理解了,可以自行修改,获取各种你想要的东西,以下代码仅供学习用。

File

#pragma once
#include<iostream>
#include<string>
#include<fstream>
#include<istream>
#include<ostream>
#include<sstream>
#include<vector>
#include<cstring>

#include <stdio.h>
#include <stdlib.h>

using namespace std;
class FileIO
{
public:
	FileIO();
	~FileIO();

	//加载点云。判断待读取的ply点云为二进制还是asc码流
	void LoadPts(char *fileName);
	//加载二进制ply点云码流
	void loadAscPts(char *fileName);

	//加载asc ply点云码流
	void loadBinPts(char *fileName);
	//以二进制方式保存点云文件
	void saveBinPts(std::vector<float> &Pts,char *fileName);
	//以ASCII方式保存点云文件
	void saveAscPts(std::vector<float> &Pts,char *fileName);
	std::vector<float> Pts;
	int numPts; 
};

基本功能是,如果已经知道是什么码流,可以分别调用loadAscPts或者loadBinPts。如果不知道。就调用LoadPts即可,在LoadPts内部会跳转。以及文件的存储

接下来我们看看怎么实现。

FileIO.cpp

#include 

调用

#include"FileIO.h"
using namespace std;
int main()
{
	FileIO testObj;
	testObj.LoadPts("XXX.ply");
	cout << testObj.Pts.size() / 3;
	testObj.saveAscPts(testObj.Pts, "XXX.ply");
	return 0;
}

几个小技巧

  1. find 和npos

用来判断读到的行line里有没有 “ binary” 还是“asc ”

if (line.find(format_flag_bin) != string::npos)

其中line 是 string 型. 所以这里需要的就是在一个字符串中找到子字符串。

npos 是一个常数,用来表示不存在的位置,类型一般是std::container_type::size_typ许多容器都提供这个东西。由于[find](find - C++ Reference)函数的返回值是整数(是下标啦),假如字符串存在包含关系,其返回值必定不等于npos,但如果字符串不存在包含关系,那么返回值就一定是npos

2. [strstr](strstr - C++ Reference)

if ((p = strstr(strLine, num_flag)) != NULL)

strstr(str1,str2) 用来判断后者是不是前者的子字符串,如果是,则返回str2在str1中首次出现的地址;对比一下find,find返回主字符串中查找到的子字符串的索引。一个偏折C风格,一个偏C++风格,大家灵活使用

3. f族的使用

相对来说,MSVC平台上C风格的读写比C++ 要快很多,不过我在其它帖子也看到过似乎不同的编译器和平台会有很大差异++。MinGW的话C++读写又很快。

对于其它多种多样的格式,举一反三即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值