使用C#读取二进制PLY文件面索引



我正在使用此项目读取.ply二进制文件:https://github.com/Zarbuz/FileToVox/blob/2064dcf99532e9c22748afb8e1a3755c1e5dfb81/SchematicToVoxCore/Converter/PLYToSchematic.cs

它适用于阅读点及其颜色。但是我不知道如何检索网格面的索引列表。

在ReadDataHeaders函数中,我成功地检索了面数:

private static DataHeader ReadDataHeader(StreamReader reader) {
...
if (col[0] == "element") {
if (col[1] == "vertex") {
data.vertexCount = Convert.ToInt32(col[2]);
skip = false;
} else if (col[1] == "face") {
data.faceCount = Convert.ToInt32(col[2]);
skip = false;
} else {
// Don't read elements other than vertices.
skip = true;
}
}
...
}

但我不明白的是如何在函数ReadDataBodyBoundary中检索网格面索引。我也不明白BinaryReader是如何在这个函数中工作的,它是如何读取网格面顶点索引的每一行二进制形式的。

private static DataBody ReadDataBodyBinary(DataHeader header, BinaryReader reader) {
DataBody data = new DataBody(header.vertexCount,header.faceCount);
float x = 0, y = 0, z = 0;
byte r = 255, g = 255, b = 255, a = 255;
int f0 = 0, f1 = 0, f2 = 0;
//for(int i = 0; i < header.faceCount; i++) {
//    //foreach(var face in )
//    int faceVertex = reader.ReadInt32();
//    Console.WriteLine();
//}
//reader.BaseStream.Position = readCount;
Console.WriteLine("Number of properties:   " + header.properties.Count().ToString());
for (int i = 0; i < header.vertexCount; i++) {
foreach (DataProperty prop in header.properties) {//iterate six properties
//Console.WriteLine(prop.ToString());
switch (prop) {
case DataProperty.R8:
r = reader.ReadByte();
break;
case DataProperty.G8:
g = reader.ReadByte();
break;
case DataProperty.B8:
b = reader.ReadByte();
break;
case DataProperty.A8:
a = reader.ReadByte();
break;
case DataProperty.R16:
r = (byte)(reader.ReadUInt16() >> 8);
break;
case DataProperty.G16:
g = (byte)(reader.ReadUInt16() >> 8);
break;
case DataProperty.B16:
b = (byte)(reader.ReadUInt16() >> 8);
break;
case DataProperty.A16:
a = (byte)(reader.ReadUInt16() >> 8);
break;
case DataProperty.SingleX:
x = reader.ReadSingle();
break;
case DataProperty.SingleY:
y = reader.ReadSingle();
break;
case DataProperty.SingleZ:
z = reader.ReadSingle();
break;
case DataProperty.DoubleX:
x = (float)reader.ReadDouble();
break;
case DataProperty.DoubleY:
y = (float)reader.ReadDouble();
break;
case DataProperty.DoubleZ:
z = (float)reader.ReadDouble();
break;
case DataProperty.Data8:
reader.ReadByte();
break;
case DataProperty.Data16:
reader.BaseStream.Position += 2;
break;
case DataProperty.Data32:
reader.BaseStream.Position += 4;
break;
case DataProperty.Data64:
reader.BaseStream.Position += 8;
break;
}
}
data.AddPoint(x, y, z, r, g, b);
}
return data;
}

问题是,您提供的示例只期望有颜色的点云(而不是面的三角形(。

To键读人脸似乎在您在代码中注释的那段代码中。

我假设你的ply文件的标题是这样的:

ply
format binary_little_endian 1.0
element vertex 326
property float x
property float y
property float z
property uchar r
property uchar g
property uchar b
property uchar a
element face 595
property list uchar int vertex_indices
end_header

重要的一行是property list uchar int vertex_indices,这意味着你有一个带有面中顶点数(通常为3(的uchar,以及一个带有顶点索引的带符号int列表。

因此,您需要更改数据结构以使用类似public List<List<Int> > faces;的内容来存储面,并在您有return data;行的地方添加类似的内容。

for(int i = 0; i < header.faceCount; i++) {
byte numVertex = reader.ReadByte(); //Read one uchar. Usually 3.
List<int> indices = new List<int>();
for(byte j = 0; j < numVertex; j++) {
indices.Add(reader.ReadInt());   //Read one int and store in the list
}
data.faces.Add(indices);                 //Store the face
}
return data;

最新更新