LingBot-Depth 2.0 深度图和点云对不上——先查内参与坐标约定

文章导读
深度图和点云叠在一起明显错位,先不要急着判定是 LingBot-Depth 2.0 的模型输出有问题。实际排查里更常见的是两类原因:一是你手里这套内参,和深度生成时用的内参不是同一套(改过分辨率、做过裁切、走过缩放,内参都会变);二是点云与深度图之间的单位、坐标轴方向、光轴朝向约定不一致。这两类错位的共同特征是整体性偏差——所有点朝同一个方向平移、整体放大缩小、或者左右镜像——而不是局部扭曲。如果
📋 目录
  1. 一 把点云按内参投影回原图
  2. 二 核对单位是米还是毫米
  3. 三 核对坐标轴方向与光轴朝向
  4. 四 每次只换一层参数做对照
  5. 五 用平面与网格场景复验
A A

深度图和点云叠在一起明显错位,先不要急着判定是 LingBot-Depth 2.0 的模型输出有问题。实际排查里更常见的是两类原因:一是你手里这套内参,和深度生成时用的内参不是同一套(改过分辨率、做过裁切、走过缩放,内参都会变);二是点云与深度图之间的单位、坐标轴方向、光轴朝向约定不一致。这两类错位的共同特征是整体性偏差——所有点朝同一个方向平移、整体放大缩小、或者左右镜像——而不是局部扭曲。如果错位是局部的、随距离变化的,才需要回头去怀疑深度本身。判断顺序建议固定为:先用投影回图确认内参是否自洽,再核对单位,再核对轴向,最后才动外参。

深度图与点云对不上,先用同一套内参把点云投影回原图,看轮廓能否贴合:贴合则错位发生在下游消费点云的环节,不贴合再怀疑深度本身。排查顺序建议固定为内参、单位、轴向,每次只改一层做对照。这套判断的适用前提是深度图与彩色图来自同一次采集、同一分辨率;如果中间做过裁切或缩放,内参必须先按比例还原,否则后续每一步对照都不可归因。

把点云按内参投影回原图

这一步的目的是用一个可观察的重合度,把错位定位到具体的环节,而不是靠肉眼猜。做法是:把深度按内参反投影成点云,再用同一套内参把点云正投影回彩色图,输出叠加图。这一步放在你自己的调试脚本里执行,输入是原始深度图、彩色图和一份待验证的内参矩阵,输出是一张叠加图。

import numpy as np

def depth_to_points(depth, K, depth_scale=1.0):
    # depth_scale 是深度原始值到米的换算系数,例如深度以毫米存储则填 0.001
    h, w = depth.shape
    v, u = np.mgrid[0:h, 0:w]
    fx, fy, cx, cy = K[0, 0], K[1, 1], K[0, 2], K[1, 2]
    z = depth.astype(np.float64) * depth_scale
    x = (u - cx) * z / fx
    y = (v - cy) * z / fy
    return np.dstack([x, y, z])      # HxWx3

def project_points(points, K):
    fx, fy, cx, cy = K[0, 0], K[1, 1], K[0, 2], K[1, 2]
    x, y, z = points[..., 0], points[..., 1], points[..., 2]
    u = fx * x / z + cx
    v = fy * y / z + cy
    return np.dstack([u, v])         # HxWx2

把投影结果画到彩色图上,叠加图是这样生成的:

import cv2

K = np.array([[fx, 0, cx],
              [0, fy, cy],
              [0,  0,  1]], dtype=np.float64)

pts = depth_to_points(depth, K, depth_scale=0.001)
uv  = project_points(pts, K)
rgb = cv2.imread('frame.png')

for u, v in uv.reshape(-1, 2):
    if 0 <= u < rgb.shape[1] and 0 <= v < rgb.shape[0]:
        cv2.circle(rgb, (int(round(u)), int(round(v))), 1, (0, 0, 255), -1)
cv2.imwrite('overlay.png', rgb)

看叠加图时重点看物体外轮廓:桌面边缘、显示器边框、门框这类直线结构,点集的外缘应当与图像里的边缘平行且间距基本恒定。如果轮廓整体平移,优先怀疑主点或外参;整体缩放,优先怀疑焦距或单位换算;左右对调、上下对调,优先怀疑轴向约定;轮廓贴合但形状随距离扭曲,才需要怀疑深度质量。轮廓是否贴合,是判断错位发生在内参还是深度本身的分界点。

核对单位是米还是毫米

单位错会把很多“看起来偏了”的现象掩盖掉。先把点云坐标范围打出来,与场景的实测尺寸做对比:

LingBot-Depth 2.0 深度图和点云对不上——先查内参与坐标约定
pts = depth_to_points(depth, K, depth_scale=1.0)   # 先按原始数值看范围
print('x', pts[..., 0].min(), pts[..., 0].max())
print('y', pts[..., 1].min(), pts[..., 1].max())
print('z', pts[..., 2].min(), pts[..., 2].max())

用卷尺量一下相机到正前方墙面或桌面的实际距离,对照 z 的典型值。若 z 落在几十到几千这个量级、而实际距离是零点几到几米,说明深度是以毫米存储的,反投影时需要乘 0.001;反过来,若 z 是零点几到几米而下游工具期望毫米,同样要对齐。这里有一个容易踩的坑:如果反投影和再投影用的是同一个错误单位的内参,透视除法会把整体缩放抵消掉,叠加图上几乎看不出差别,所以单位不能只靠叠加图判断,必须看点云数值本身。千倍差异真正暴露的位置,通常是把点云与其它传感器、外参标定结果或机器人本体尺寸放在一起时——点云会整体穿出画面、落在视野之外,或者与场景尺寸差出三个数量级。

核对坐标轴方向与光轴朝向

轴向问题表现为整体旋转或镜像,需要逐项确认,不能凭感觉试:

  • x 轴:像素 u 是向右增大,还是图像本身已被水平镜像;x 是否取了负。
  • y 轴:是按图像坐标向下为正,还是按可视化器约定向上为正;y 是否取了负。
  • 深度:深度值是沿相机前方为正,还是取成了负值;z 接近 0 或为负的区域是否被错误参与投影。
  • 光轴朝向:相机坐标系是 +Z 向前,深度是否定义在 -Z 方向;坐标系是右手系还是左手系。

验证方式优先用已知方位的物体,而不是靠调参试错。在相机视野左侧放一个可辨识物体,或贴一张带文字的纸,正对相机采集一帧。生成点云后再投影回图:投影点落在图像左侧说明 x 方向正确,落到右侧说明 x 轴方向反了;同理判断上下。深度整体取负时,点云会跳到相机背后,投影时因除以负数而翻到另一侧,形态上接近镜像并伴随点序混乱,这类现象与简单的左右翻转要分开记录。

每次只换一层参数做对照

同时改内参、单位、轴向,最后即使对上了也无法说明是哪一项起了作用。建议固定一组基准参数,然后做三组单变量对照,每组只改一项,其余全部锁死:

  1. 只换内参:分别用标定值 A 与按当前分辨率缩放后的值 B 各跑一次,其它参数不变。
  2. 只换单位:depth_scale 在 1.0 与 0.001 之间切换,其它参数不变。
  3. 只换坐标约定:分别试验 x 取反、y 取反、z 取反,每次只动一个轴。

每组都记录:叠加图文件名、使用的内参、depth_scale、轴约定、偏差方向(左上平移还是右下平移、左右镜像还是上下镜像、整体缩放)、以及偏差的大致像素量级——是几十像素的小幅平移,还是接近整幅图宽度的量级。像素量级本身不需要精确到个位,但它能区分问题层级:小幅平移更像主点偏差,接近整幅图的偏移更像轴向约定写反。不要用“改完看着好点”当作结论,因为那种描述在下次换一台设备时无法复用。

LingBot-Depth 2.0 深度图和点云对不上——先查内参与坐标约定

用平面与网格场景复验

修正参数后,需要在规则场景里确认结论成立。找一面平整的墙,或者铺一张棋盘格,让相机正对拍摄,保持固定距离,然后按修正后的参数重新生成点云。

判断平面上的点是否共面,可以对墙面区域做一次最小二乘平面拟合,看残差与法向:

pts = depth_to_points(depth, K, depth_scale=0.001).reshape(-1, 3)
sel = pts[pts[:, 2] > 0]                 # 只保留相机前方的点
centroid = sel.mean(axis=0)
_, _, vt = np.linalg.svd(sel - centroid)
normal = vt[-1]
residual = (sel - centroid) @ normal
print('normal', normal, 'residual std', residual.std())

墙面上的点残差应当落在深度噪声的量级,而不是沿某一轴出现线性漂移——线性漂移通常意味着轴向或内参仍未对齐。再用投影回图检查棋盘格:格线投影应当平直,角点投影应落在格点附近。棋盘格的好处是尺寸已知,可以同时验证单位与比例;如果格线投影间距与实际网格尺寸按固定倍数偏离,说明单位换算还没对齐。

需要留存的记录包括:原始深度图、对应彩色图、叠加图、使用的内参矩阵、depth_scale、轴约定、平面拟合的法向与残差。这几项留齐之后,下次在另一台设备上复现同样的错位时,可以直接对照参数差异,而不必从零重排一遍。