LingBot-Depth 2.0 读取的不是原始 LAS 或 PCD 文件,而是一个已转为数组的张量。输出也不是直接可用的点云,而是与输入坐标绑定的深度张量。你首先要确认模型需要哪些通道、坐标系如何定义,再把格式转换做对,最后从输出张量中取出深度值。以下是通常可行的处理顺序。
处理 LingBot-Depth 2.0 时,先加载官方示例数据,检查点云字段与坐标范围。输入通常为 N×C 数组,通道包含 xyz 及可选强度;输出为 B×H×W 或 B×N×D 张量。转换时使用 Open3D 或 laspy,推理后需按原坐标对齐校验,避免点序错位。操作顺序:确认规范→转换→推理→校验。
确认模型输入的点云通道与坐标系统
模型训练时用到的点云字段是固定的。通常至少包含 x、y、z 三个通道,部分变体还接收 intensity、rgb 或归一化坐标。坐标系统一般以模型训练数据的坐标系为准,常见的是相机坐标系:x 向右,y 向下,z 指向场景前方。如果拿到的点云来自激光扫描,其坐标系可能是 Z 轴向上,这时需要先旋转对齐。
建议先加载一份官方示例数据,直接查看数组形状和字段名,例如用 numpy 打印 shape 和 dtype,再读取几个点的坐标范围。这一步能确定输入张量的通道顺序,避免按错误顺序拼接导致推理结果无意义。
将点云文件转换为模型可读的数组
以 LAS 和 PCD 为例,通常用 laspy 和 open3d 读取。转换时只保留模型需要的字段,并按模型要求的通道顺序排列。如果模型使用相机坐标系,需要把 Z 轴向上的点云旋转到 z 向前,旋转矩阵由点云自身的坐标系与相机坐标系之间的外参决定。
import numpy as np
import laspy
# 读取 LAS 文件
las = laspy.read("scan.las")
points = np.vstack([las.x, las.y, las.z]).T # N x 3
# 如果有 intensity,且模型接受该通道
if hasattr(las, "intensity"):
intensity = las.intensity.reshape(-1, 1)
points = np.hstack([points, intensity]) # N x 4
# 转换为 float32,模型通常要求这个精度
points = points.astype(np.float32)
# 这里先不旋转,需根据模型示例确定坐标系import open3d as o3d
import numpy as np
# 读取 PCD 文件
pcd = o3d.io.read_point_cloud("scan.pcd")
points = np.asarray(pcd.points) # N x 3
# 如果还有颜色字段,可加入
colors = np.asarray(pcd.colors)
if colors.shape[1] >= 3:
points = np.hstack([points, colors])
points = points.astype(np.float32)转换后建议保存为 .npy,方便后续重复加载,同时记录坐标范围,供校验阶段使用。
执行推理并解析输出张量
推理代码没有本质不同,关键在解析输出维度。假设模型是 PyTorch 实现,输入张量形状为 (1, N, C),输出可能是 (1, N, D) 或 (1, H, W)。前者表示每个输入点的深度估计,后者表示投影到图像平面后的深度图。
import torch
import numpy as np
model = torch.load("lingbot_depth.pt", map_location="cpu")
model.eval()
# points 已转换为 numpy 数组
input_tensor = torch.from_numpy(points).unsqueeze(0) # (1, N, C)
if input_tensor.dtype != torch.float32:
input_tensor = input_tensor.float()
with torch.no_grad():
output_tensor = model(input_tensor) # 形状可能是 (1,N,D) 或 (1,H,W)
print("输出形状:", output_tensor.shape)
# 按输出形状分情况处理
if output_tensor.ndim == 3:
# (1, N, 1) 或 (1, N, 2),最后维包含深度信息
depth = output_tensor[0, :, 0].numpy()
elif output_tensor.ndim == 4:
# (1, 1, H, W) 深度图
depth = output_tensor[0, 0].numpy()
else:
raise ValueError("未识别的输出结构")
# 保存深度结果
np.save("depth.npy", depth)如果输出是逐点深度,那么每个点对应一个深度值;如果是深度图,需要与对应的投影坐标关联。在没有相机内参的情况下,逐点输出更容易直接使用。
校验解析结果与原始数据的对齐关系
解析错误通常表现为点数不一致或坐标范围漂移。校验时先对比输入点数和输出点数,再检查坐标范围是否在原始点云的包围盒内。如果输出携带坐标,直接比较;如果是深度图,则检查投影后的点数与输入点数的比例。
# 假设原始点云为 points,解析后的深度为 depth
# 校验点数
if depth.ndim == 1 and len(depth) == len(points):
print(f"点数一致: {len(depth)}")
else:
print("点数不一致,检查点序或投影步骤")
# 校验坐标范围:如果输出是深度图,跳过此项
if depth.ndim == 1:
# 用输出深度与原始点 z 坐标对比(需要确认坐标系一致)
min_z = points[:, 2].min()
max_z = points[:, 2].max()
print(f"原始 Z 范围: [{min_z:.3f}, {max_z:.3f}]")
print(f"深度值范围: [{depth.min():.3f}, {depth.max():.3f}]")
# 更深层校验:随机取若干点,计算输出深度与原始点坐标的差值
indices = np.random.choice(len(points), 100, replace=False)
if depth.ndim == 1:
diffs = np.abs(depth[indices] - points[indices, 2])
print(f"采样点深度差均值: {diffs.mean():.4f}")若深度差均值明显偏离 0,说明坐标系对齐方式不对,需要检查模型训练时的坐标定义。建议在正式处理大量数据前,先用少量样本完成从文件到输出的全流程,确认每个环节的数组形状和数值范围都符合预期。