104 lines
3.1 KiB
Python
104 lines
3.1 KiB
Python
"""点云加载模块"""
|
|
import numpy as np
|
|
from pathlib import Path
|
|
import struct
|
|
|
|
|
|
class PointCloudLoader:
|
|
"""加载点云文件"""
|
|
|
|
@staticmethod
|
|
def load_ply(file_path: str) -> np.ndarray:
|
|
"""
|
|
加载PLY格式点云
|
|
|
|
Args:
|
|
file_path: PLY文件路径
|
|
|
|
Returns:
|
|
np.ndarray: 点云数组 (N, 3)
|
|
"""
|
|
path = Path(file_path)
|
|
if not path.exists():
|
|
raise FileNotFoundError(f"点云文件不存在: {file_path}")
|
|
|
|
print(f"正在加载点云: {file_path}")
|
|
|
|
with open(path, 'rb') as f:
|
|
# 读取头部
|
|
header_lines = []
|
|
while True:
|
|
line = f.readline().decode('ascii').strip()
|
|
header_lines.append(line)
|
|
if line == 'end_header':
|
|
break
|
|
|
|
# 解析头部
|
|
vertex_count = 0
|
|
format_type = None
|
|
properties = []
|
|
|
|
for line in header_lines:
|
|
if line.startswith('element vertex'):
|
|
vertex_count = int(line.split()[-1])
|
|
elif line.startswith('format'):
|
|
format_type = line.split()[1]
|
|
elif line.startswith('property'):
|
|
parts = line.split()
|
|
properties.append({
|
|
'type': parts[1],
|
|
'name': parts[2]
|
|
})
|
|
|
|
if vertex_count == 0:
|
|
raise ValueError("PLY文件中没有顶点数据")
|
|
|
|
# 读取顶点数据
|
|
if format_type == 'binary_little_endian':
|
|
points = PointCloudLoader._read_binary_ply(f, vertex_count, properties)
|
|
elif format_type == 'ascii':
|
|
points = PointCloudLoader._read_ascii_ply(f, vertex_count)
|
|
else:
|
|
raise ValueError(f"不支持的PLY格式: {format_type}")
|
|
|
|
print(f" 加载完成: {len(points)} 个点")
|
|
return points
|
|
|
|
@staticmethod
|
|
def _read_binary_ply(f, vertex_count: int, properties: list) -> np.ndarray:
|
|
"""读取二进制PLY数据"""
|
|
# 构建struct格式字符串
|
|
type_map = {
|
|
'float': 'f',
|
|
'double': 'd',
|
|
'uchar': 'B',
|
|
'uint': 'I',
|
|
'int': 'i'
|
|
}
|
|
|
|
fmt = '<' # 小端序
|
|
for prop in properties:
|
|
fmt += type_map.get(prop['type'], 'f')
|
|
|
|
struct_size = struct.calcsize(fmt)
|
|
points = []
|
|
|
|
for _ in range(vertex_count):
|
|
data = struct.unpack(fmt, f.read(struct_size))
|
|
# 只取前3个值作为xyz坐标
|
|
points.append(data[:3])
|
|
|
|
return np.array(points, dtype=np.float64)
|
|
|
|
@staticmethod
|
|
def _read_ascii_ply(f, vertex_count: int) -> np.ndarray:
|
|
"""读取ASCII PLY数据"""
|
|
points = []
|
|
for _ in range(vertex_count):
|
|
line = f.readline().decode('ascii').strip()
|
|
values = line.split()
|
|
# 只取前3个值作为xyz坐标
|
|
points.append([float(values[0]), float(values[1]), float(values[2])])
|
|
|
|
return np.array(points, dtype=np.float64)
|