点云ply格式的读写

点云ply读写时候遇到几个细节的问题,代码放在下面,做好总结。

一般ply格式点云的一个点的结构都可以直接使用notepad++打开ply文件查看头部:
在这里插入图片描述
可以看出每个点都包含float类型的xyz和uchar类型的rgb,ply文件的头部对读写都很重要。
通过下面生成新的ply文件进行演示:

#pragma pack(push, 1) // 设置内存对齐方式为 1 字节,点云一般都是内存紧密排列的
//自定义点格式
struct SelDefPoint
{
	float x, y, z;
	unsigned char intensity;
};
//待解析的点云格式
struct CCPoint 
{
	float x, y, z;
	unsigned char red, green, blue;
};
#pragma pack(pop) // 恢复默认的内存对齐方式

//ply_file 原始ply文件路径;newPlyPath 新生成的ply文件路径
bool NewPlyFile(string ply_file, string newPlyPath) {

	std::ifstream inputFile(ply_file, std::ios::binary);//一定记得要求读写格式为二进制,否则头部末尾后所有内容读取失败

	if (!inputFile.is_open()) {
		std::cerr << "Failed to open PLY file: " << ply_file << std::endl;
		return 1;
	}

	// 读取 PLY 头部信息
	std::string line;
	while (std::getline(inputFile, line)) {
		if (line == "end_header") {
			break; // 头部信息结束才能真正开始读取点数据
		}
	}
	
	// 读取点云数据
	std::vector<CCPoint> points;
	CCPoint point;	
	while (inputFile.read(reinterpret_cast<char*>(&point), sizeof(CCPoint))) {
		points.push_back(point);
	}
	inputFile.close();

	std::ofstream outFile(newPlyPath, std::ios::binary);
	if (!outFile.is_open()) {
		std::cerr << "Failed to open output file" << std::endl;
		return 1;
	}
	//定义新ply的头部
	char plyHeader[] =
		"ply\n"                                 
		"format binary_little_endian 1.0\n"    
		"element vertex %d\n"                    
		"property float x\n"
		"property float y\n"
		"property float z\n"
		"property uchar intensity\n"
		"end_header\n";

	// 替换 %d 为实际的顶点数量
	int numVertices = points.size(); 
	char header[1024]; // 根据ply头大小适当调整
	std::sprintf(header, plyHeader, numVertices);//需要写入顶点数目
	// 将PLY头部信息以二进制形式写入文件,写完后就可以直接在notepad++中打开验证了
	outFile.write(header, strlen(header));

	std::vector<SelDefPoint> selDefPoints;
	//使用新的点格式拷贝所需要的数据,在这里,使用原始数据的red作为新数据的intensity
	for (auto pt:points)
	{
		SelDefPoint tmp;
		tmp.x = pt.x;
		tmp.y = pt.y;
		tmp.z = pt.z;
		tmp.intensity = pt.red;
		selDefPoints.push_back(tmp);
	}

	for (int i=0;i<selDefPoints.size();i++) {
	//使用.write的方法写入新的ply文件中,而不是<<重定向
		outFile.write(reinterpret_cast<const char*>(&selDefPoints[i]), sizeof(SelDefPoint));
	}

	outFile.close();

	return 0;

}

总结

  • 确定ply头格式中的property类型和数目,根据它创建对应的结构体
  • 要使用%d填入顶点的个数
  • 确定是否需要紧密排列结构体的内存,否则容易造成读写出错
  • 注意结构体属性类型是否和ply头的声明类型一致,否则也会读写出错
  • 使用write进行读写而不是重定向符号
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值