使用Pyparsing解析二进制Stanford多边形文件(PLY)

3
针对一个大型项目,我目前正在编写斯坦福多边形文件(PLY)解析器。此示例(Github Gists)目前可以将ASCII格式的PLY文件解析为数据抽象Mesh。它还包含了实际语法的描述,适合那些有兴趣的人。
然而,该格式定义(PLY - 多边形文件格式)还包括两种二进制格式(小端和大端)。由于这两种格式更常见(并且存储空间更有效),我希望也能够使用pyparsing解析这些文件。
如果可能的话,我很感激一些关于如何做到这一点的建议。
二进制PLY文件的想法是,头部分包含文件实际数据的ASCII描述,而主体包含实际数据。以下是一个例子(方括号中的数据是十六进制字节):
ply
format binary_little_endian 1.0          
element vertex 1
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
property uchar alpha
end_header
[84 72 F1 C1 D8 FD 9F C1 00 00 00 00 3B 45 CB FF]

我的第一种方法是以二进制格式加载输入文件(使用bytes而不是str),并相应地调整解析器,但这种方法会使pyparsing出现问题。此外,我不知道如何告诉pyparsing如何理解字节组。

  File "components.py", line 338, in create
    mesh = PlyParser.create().load(mesh_path)
  File "model_parser.py", line 120, in create
    property_position = aggregate_property("position", b"x", b"y", b"z")
  File "model_parser.py", line 113, in aggregate_property
    aggregates.append(pp.Group(property_simple_prefix + keyword_or(*keywords)("name")))
  File "model_parser.py", line 87, in keyword_or
    return pp.Or(pp.CaselessKeyword(literal) for literal in keywords)
  File "pyparsing.py", line 3418, in __init__
    super(Or,self).__init__(exprs, savelist)
  File "pyparsing.py", line 3222, in __init__
    exprs = list(exprs)
  File "model_parser.py", line 87, in <genexpr>
    return pp.Or(pp.CaselessKeyword(literal) for literal in keywords)
  File "pyparsing.py", line 2496, in __init__
    super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
  File "pyparsing.py", line 2422, in __init__
    self.matchLen = len(matchString)
TypeError: object of type 'int' has no len()

pyparsing 面向文本 - 也许可以通过 base64 编码将二进制流转换为文本流,然后进行解析? - halloleo
感谢您的建议,@halloleo。不幸的是,PLY文件是部分文本,部分二进制。因此,我必须预加载文件,仅将二进制部分编码为类似于base64的内容,然后使用pyparsing解析它。此外,对于有时可能达到100多兆字节的文件进行编码并不是我想做的事情。 - E Y
2个回答

1

已经有一个用于解析二进制PLY文件的模块:python-plyfile

你可以使用它,或者至少查看源代码以了解其工作原理。

它使用numpy.fromfile - 这被描述为一种“高效读取具有已知数据类型的二进制数据”的方法 - 用于读取二进制数据。


谢谢你的建议!不幸的是,python-plyfile使用了一种数据模型,将二进制数据解析为嵌套和/或结构化的numpy数组。对于我的用途,我需要具有连续存储的方式。此外,我正在尝试不在这个项目中使用numpy。 - E Y

1
你可能想尝试的是将文件作为文本打开,使用pyparsing解析标头并捕获“结束标头”令牌的结束位置。使用从标头提取的结构信息构建一个Python struct reader来处理二进制内容。然后将文件重新作为二进制文件打开,寻找位置,并使用struct reader加载二进制内容。这样做可能比将pyparsing扭曲成文本和二进制更简单。

我决定采用你的建议,使用struct模块。更新后的代码可在原始Gist中找到:PlyParser - E Y

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接