你真准备把“摄像头拍一张图机械臂伸手把目标物体抓起来”这句话做成一个能跑的 demo会发现它几乎是机器人学里最反直觉的任务之一。ZeroGrasp 是我给一套单图 3D 重建 机器人抓取学习复现项目起的内部代号——不依赖多视角扫描不预先给物体建模只靠单张 RGB 图像和已知相机内参完成目标物体的三维重建、位姿估计与夹爪抓取规划。这篇文章围绕 ZeroGrasp 复盘了我从原理到落地的完整理解链路也把踩过的坑一起写出来希望能让刚入门的人少绕几个弯。要理解这条链路不能只盯着“深度估计”或“抓取规划”某一个环节。单图重建是一个在信息层面先天不足的任务抓取又是一个对几何误差极其敏感的任务两者拼在一起真正的难点是误差如何在链路里传播。下面我从原理、管线、接口设计、数据训练、学习路径到实战调参一层层拆开讲。1. 单图重建为什么天生“病态”深度估计背后的视觉线索1.1 同一个像平面对应无穷多个三维世界很多新手不理解一个问题多视图重建靠两张图就能三角化出三维点为什么单张图就这么难因为投影过程主动丢弃了深度信息。三维空间里无数个点会被压到同一个像素上光看像素值你无法知道它到底是 0.5 米外的小物体还是 5 米外的同形状大物体。更反直觉的是这种信息损失不是噪声造成的而是几何上不可逆的。你拍到一个圆形轮廓它可能是正对镜头的小圆盘也可能是远处的圆台还可能是斜着的椭圆在特定角度下被拍成了圆。只要投影方程成立这些解释都合法。计算机视觉里管这叫“病态问题”——不是解不出来而是解不唯一。人类为什么没觉得难因为我们有大量先验知道杯子一般多高知道桌面是平的知道物体之间的遮挡关系还知道光线通常从上方来。这些都是视觉系统在进化中学会的“默认假设”。单目深度估计要做的事就是用数据驱动的方式把这类先验“学”进网络而不是靠几何公式直接算出来。这也是 ZeroGrasp 里把所有希望都押在深度模型上的风险所在——模型本质上在做猜测一旦场景超出训练分布猜测就会出错。1.2 深度估计真正学的是“线索组合”深度估计网络不是直接记忆每一张图的深度而是在学习一组视觉线索的组合方式。我拆开看主要有四类透视几何线索平行线在远处汇聚纹理从近到远逐渐密集这些线索能给出相对深度关系。光照与阴影线索阴影形状可以暗示物体凹凸但光照方向不定存在著名的明暗八重歧义单独用非常不稳。遮挡与轮廓线索物体边缘会遮挡背景轮廓内部和外部的深度不连续这条线索对分离物体很关键。语义先验线索知道这是一个人、那是一辆车就能用该类别的典型比例反推深度尺度。训练方式也跟着线索走。最直观的是监督式深度回归用真实深度图作为标签数据不够时用自监督光度一致性让网络从左右视图重建颜色差异来学深度还有一种相对深度排序只预测像素间谁远谁近不追求绝对尺度。工程上我建议别把深度估计当成一个“黑盒魔法函数”。你要明确自己用的是哪类线索才知道模型在什么场景下会失效。ZeroGrasp 里我发现一个规律在强纹理桌面上模型表现很好一到纯色桌面、地面或者墙面深度就变得平滑而失真——因为模型只能靠语义先验猜而语义先验对“没有纹理的平面”无能为力。1.3 深度图只是 2.5D不是三维模型深度图往往给我们一种错觉每个像素都有距离这不就是三维信息吗严格说它只是 2.5D——它是一个带深度的二维图像并没有形成完整的物体表面物体背面、遮挡区域的信息完全缺失。要把深度图变成三维点云需要做反投影unprojection。假设深度值 z 表示相机坐标系下的深度相机内参为 fx、fy、cx、cy那么图像坐标 (u, v) 对应的三维坐标是import numpy as np # depth: (H, W) 单通道深度图 # K: 3x3 相机内参矩阵 def unproject(depth, K, depth_scale1.0): h, w depth.shape fx, fy K[0, 0], K[1, 1] cx, cy K[0, 2], K[1, 2] u, v np.meshgrid(np.arange(w), np.arange(h)) z depth * depth_scale x (u - cx) * z / fx y (v - cy) * z / fy points np.stack([x, y, z], axis-1).reshape(-1, 3) return points反投影之后你得到的是“看得见的表面”。如果要进一步做网格重建就涉及到不可见区域的补全问题。三维表示有好几种点云直接、轻量适合做特征提取和抓取位姿采样网格适合做碰撞检测和物理仿真但单图重建出的网格拓扑经常很糟糕隐式表示如符号距离场、神经辐射场则能连续建模形状却在单图输入下容易过拟合到训练集的平均形状上。ZeroGrasp 的结论是抓取任务不必执着于好看的三维模型可靠的点云表面加物体边界往往比一个“漂亮但几何漂移”的网格更有用。2. 从深度图到点云再到可用的几何表面ZeroGrasp 的第一条管线2.1 四条主线的选择单图 3D 重建的技术路线五花八门我把它归成四类这样选型时目标清晰路线基本做法优势局限深度回归加反投影用网络预测每个像素深度再按相机模型生成点云简单直接速度快模型多物体边缘容易模糊不可见区域无信息隐式曲面重建用坐标网络拟合符号距离场通过渲染损失约束表面连续光滑可处理部分遮挡单图信息太少容易回归到平均形状形状先验补全从类别库中检索或生成相似形状进行补全对已知类别物体效果好开放世界下类别库覆盖不了占用场与可微分重建预测体素或占用概率用投影约束监督融合了深度和形状先验计算量大对显存要求高对 ZeroGrasp 这种要跑在真实机械臂上的场景我选了“深度回归加反投影”作为主路线再用点云后处理和局部表面拟合做补强。原因很简单抓取规划下游需要的是可重复的几何测量而不是一个可能偏到一边的完整 mesh。如果某个物体类别固定可以叠加类别先验补全但开放环境下先保证“看得见的部分测量可靠”是第一位。2.2 最小管线的落地步骤一条可落地的单图重建管线我建议按下面顺序搭用预训练单目深度估计模型从 RGB 图得到相对深度图先不追求绝对尺度。通过一个尺度系数或场景先验把相对深度换算到近似绝对深度。用相机内参反投影得到整张图像的稠密点云通常有几万到几十万个点。对点云做统计滤波与体素下采样去掉离群噪声控制计算量。用语义分割模型提取目标物体掩码把点云裁剪到目标物体区域。对目标点云计算法线然后作为输入交给抓取位姿生成模块。第 2 步是关键很多深度模型输出是归一化或相对值尺度错一个数量级后面全部白做。通常做法是在场景中放一个已知尺寸的参考物体或者利用相机到地面的高度作为锚点在 ZeroGrasp 里我直接放了一个已知边长的标定方块在同一平面深度尺度系数就是“真实边长除以预测边长”。这个笨办法最稳。第 5 步也值得强调不要抓“整张桌子的点云”要先分割出物体。用 RGB 语义分割比在点云上聚类更稳定因为单图深度在物体边界处非常不可靠纯点云聚类会把相邻物体粘在一起。2.3 精度和实时性的取舍做重建不能不谈精度但抓取任务对精度的要求往往被高估。平行板夹爪开口假设是 6 厘米重建误差只要小于夹爪开口的 10%-15%也就是 6 到 9 毫米就足够判别“能不能夹住”。反而普通单目深度模型在 0.7 米距离上常出现 1-2 厘米的偏差这时夹爪就处在“可夹可不夹”的灰色地带。你可以做两个极端实验体会一下静态场景用重一点的深度估计模型让机械臂慢慢规划能稳住毫米级定位动态场景用轻量模型以牺牲精度换来每帧 30 帧以上的推理速度然后靠机械臂的快速执行来弥补。ZeroGrasp 最终选了后者——先快速估算一个候选抓取位姿机械臂移到目标附近后再用当前帧做一次局部精细化。两次估计叠加比一次“最好”的估计可靠得多。3. 重建完不等于能抓从几何模型到夹爪位姿的接口设计3.1 抓取决策需要哪些“几何子问题”很多人以为重建出三维模型就万事大吉实际上抓取规划回答的是另一类问题。它不问“这是什么”而问“在哪里施加力、沿什么方向夹能稳稳把它拿起来”。这包含三个几何子问题局部可抓性物体表面是否有两个近似对立的接触面平行板夹爪能否同时接触。接触稳定性夹爪施加的力是否落在摩擦锥内物体在夹持中不会滑落。全局可达性机械臂末端能否无碰撞地运动到该位姿腕部是否遇到奇异。前两个问题依赖几何与摩擦系数。摩擦锥可以理解成一个以法线为轴的圆锥夹爪施加的力必须落在锥内才能维持静态接触。这也是为什么完全光滑的玻璃杯比磨砂表面难抓——接触摩擦小可用的锥角就窄。单图重建的几何误差会直接影响这三个子问题深度偏差改变表面位置法线估计偏差改变摩擦锥计算点云缺失则可能漏掉唯一的可抓区域。所以下游抓取对重建的要求不是“看起来像”而是“局部几何关系可靠”。3.2 生成夹爪位姿的三种范式从点云或网格生成抓取位姿主流做法有三种解析式打分方法会手工定义接触力学指标比如力封闭程度、接触面积、力矩平衡然后枚举表面点对计算得分。它物理意义清晰但前提是有精确的网格模型。单图重建的网格边缘粗糙解析打分很容易把好位姿误杀现在已很少作为主力。采样加质量网络是当前最稳健的方案。先在物体表面附近随机采样大量候选夹爪位姿再用一个神经网络给每个候选打分预测“抓取成功率”。这类网络对局部几何误差有一定容忍度因为它学的不是精确物理而是“看起来像能抓”的采样分布。ZeroGrasp 的主力方案就是这一种代价是推理时要多跑一次网络推理实时性稍弱。直接回归方法用一个编码器把点云映射到多个抓取位姿速度快但输出缺乏可解释性也难以处理“物体旁边有障碍物但网络没注意”的情况。我在实验里发现它成功率波动大不建议作为第一选择。3.3 夹爪开口与接触面把“3D模型”变成“物理约束”无论哪种范式最终都要落到夹爪的具体几何上。平行板夹爪不是“一个点”它有两个平行平面。抓取规划时你要检查候选位姿下两个平面之间的物体厚度是否小于夹爪最大开口还要检查接触区域的平均法线是否与夹爪闭合方向近似平行。一个简化的校验逻辑如下# points: 目标物体点云(N, 3) # grasp_pose: 候选抓取位姿的 4x4 变换矩阵 def check_jaw_width(points, grasp_pose, max_open0.05): # 把点云变换到夹爪坐标系 pts_local (np.linalg.inv(grasp_pose) np.hstack([points, np.ones((len(points), 1))]).T).T[:, :3] # 夹爪平面之间 z 方向厚度x 方向为夹爪开口方向 x pts_local[:, 0] valid pts_local[:, 2].__abs__() 0.005 # 近似取夹爪平面附近的点 if valid.sum() 3: return False if x[valid].ptp() max_open: return False return True实际项目中我还会加一步“干涉检查”用夹爪的简化包围盒去碰撞目标点云边界防止夹爪还没到目标就先撞到旁边的物体。这一步对零部件的密排摆放尤其重要单靠抓取成功率网络经常忽略周围环境。4. 误差在链路里的传播与缩放为什么好的抓取闭环不能只看重建精度4.1 一个像素偏差到了三维空间可能变成一厘米偏差误差传播是端到端系统最容易被低估的地方。反投影公式里三维横向坐标 x 与深度 z、像素坐标 u 都有关系。简单求导就知道dx (z / fx) * du (u / fx) * dz第一项说明像素误差会被 z / fx 放大第二项说明深度误差还会被像素位置 u 放大。在图像边缘u 很大同样的深度误差会造成更大的横向位置误差。举个具体数字fx 假设 500像素深度 z 为 0.8 米一个像素的横向偏移会造成 1.6 毫米的位置偏差如果深度估计在物体边缘再带 2 厘米噪声横向位置误差能轻松超过 1 厘米。这个误差尺度对抓取意味着什么夹爪开口是 6 厘米时1 厘米定位误差属实更明显直接导致抓偏。所以 ZeroGrasp 里我做了个粗暴经验规则对每个候选抓取位姿根据深度置信度给不确定性打分不确定区域的位姿置信度直接砍半。4.2 误差如何一步步影响抓取结果误差会在链路里层层放大最后变成三类典型失败误差来源下游表现缓解手段深度估计边缘模糊点云黏连目标边界膨胀语义掩码裁剪、边缘不确定性掩码表面法线估计不准夹爪姿态倾斜接触时滑脱局部平面拟合平滑法线、多候选位姿冗余不可见区域补全错误把背面错误区域当成可抓区域限制抓取区域到置信度高视点表面我试过把重建指标刷得很漂亮Absolute Relative Error 降到很低但真实机器人抓取成功率纹丝不动。原因就在这里——重建是在整个图像上平均而抓取只关心目标物体局部 10 厘米见方的一块。局部误差反而被平均指标掩盖了。4.3 数据、仿真与 sim-to-real 的连锁反应单图重建模型的训练数据来源直接决定了它在真实场景的表现。合成数据可以无限生成场景多样能覆盖大量极端视角但有纹理失真和传感器噪声缺失的问题物理仿真标注可以自动生成抓取成败标签但仿真接触模型与真实摩擦力存在差异真实数据标注最可靠成本也最高。sim-to-real 的核心不是让模型“见过真实数据”而是让模型对传感器差异不敏感。ZeroGrasp 里用过两类有效手段域随机化把光照强度、相机噪声、物体纹理颜色都随机打乱逼网络学几何线索闭环校正让机械臂在接近目标时根据最新相机帧重新估计深度和位姿而不是一步到位冲过去。我做过一个对比不做任何闭环校正时抓取成功率约 62%只加一个简单的伺服闭环后提升到 79%。原因就是闭环打断了误差累积——前一步的定位误差不会再喂给下一步。这条经验对所有“重建接抓取”的系统都适用。5. 对照“小白→博士”不同阶段的岔路口我建议的拆解顺序5.1 小白阶段先弄懂相机、变换和 3D 表示不要一上来就调深度模型。我建议先手写一次反投影用相机拍一块棋盘格标定内参手动把角点像素坐标转到相机坐标系再转到世界坐标系。这个过程能把“图像坐标—相机坐标—世界坐标”这条链路焊死在脑子里。同时要把四类三维表示弄熟深度图、点云、体素、网格。每种表示各自的空间效率、精度、下游友好度都不一样。这里不需要啃复杂公式只需要亲手把点云可视化出来再把深度图转成点云对坐标变换形成肌肉记忆。5.2 进阶阶段复现最小闭环而不是漫无目的刷模型当你理解基础后别忙着换最新模型先跑通一条最小闭环相机拍照、单目深度估计、反投影点云、目标分割、采样抓取位姿、机械臂执行。哪怕每一步用最简单的方法都可以比如抓取位姿先用规则生成再人工挑一个可以的金标。这个闭环的价值在于让你体会误差在系统中如何流动。跑通了再升级把规则位姿换成质量网络把离线深度换成在线深度把单视角重建换成多帧融合。每换一步能做一次消融实验知道瓶颈在哪。很多新手败在“每条子模块都用最新的结果加起来跑不动”。5.3 研究阶段把失败案例变成问题定义到这一层你不再是“调参侠”而是从失败中提炼问题。比如透明物体深度不可靠、纯色表面无纹理、极端俯视角度下语义分割失效——每一个都可以拆成一个研究子问题。评估也要从“重建指标高不高”转向“抓取成功率为什么低”并尝试用因果方式定位是目标分割错了还是夹爪位姿生成错了还是机械臂运动精度不够。此时可以大胆修改网络结构和损失函数但前提是你已经能解释“修改哪个模块影响哪个失败模式”。ZeroGrasp 到后期最有用的一件事是给每个失败样本打了标签比如“定位失败”“滑落”“碰撞”“夹取后掉落”然后按类别统计分析每个类别对应一个改进方向。5.4 不推荐的弯路这条学习路线上我认为有三个大坑第一直接上端到端 Transformer。单图到抓取位姿的端到端模型看起来优雅但中间缺少可检查的几何结构调试困难数据需求大。第二不做误差预算就开干。你至少要知道夹爪开口多大、位置误差容许几毫米、深度模型误差大概多少这决定你到底需要多少后处理。第三把重建和抓取分开优化到极致却从不联合测试。它们之间有一大堆接口问题分开做永远发现不了。6. 实战视角的坑与调参记录标定、后处理、评估三件事6.1 相机标定决定系统天花板这句话我踩过亏后才彻底信了。有一次系统里所有重建指标都正常但机械臂就是抓偏 3 厘米查了半天发现是手眼标定矩阵平移向量算错了一个分量。标定不是拍一张棋盘格就完事我建议把标定板放在机械臂实际工作空间的各个位置和角度各拍 20 张以上覆盖视野中心和边缘然后检查重投影误差在目标距离上的表现。另外一个常见坑深度传感器和彩色传感器之间的外参必须单独标定。很多深度相机出厂带有彩色对齐参数但在近距离抓取时微小的外参偏差最终会变成明显的点云错位。用点云投影到彩色图上检查边缘是否对齐是最快的自检方式。6.2 深度后处理是“免费的成功率提升”有时候你不需要换模型只需要把后处理做扎实。我常用的四招深度补洞对深度为 0 或无穷大的像素用邻域中值填充。边缘保护滤波双边滤波保留边界同时平滑噪声。平面去除用 RANSAC 拟合并去掉桌面平面不让桌面点云干扰物体分割。离群点剔除统计每个点邻域密度把孤立点删掉。有一版系统只做了这些后处理还没换任何网络抓取成功率就提升了 10 个百分点。原因不是深度变准了而是下游的点云处理和抓取采样不再被噪声和桌面干扰。每次改完一定要可视化确认“点云里的目标轮廓和彩色图里的边缘是重合的”。6.3 用抓取失败日志评估而不是只看平均准确率评估系统时我强烈建议记录每一次抓取失败的类型而不是只报一个成功率数字。用“总抓取次数 100 次”做基线把失败原因拆成四类定位失败、碰撞、滑落、夹取后掉落。每类失败对应不同的修复手段失败类型最可能根因修复优先级定位失败深度误差或分割不准后处理与深度置信度碰撞夹爪包围盒干涉检查缺失加干涉检测滑落法线估计误差或摩擦模型过乐观调整抓取姿态冗余夹取后掉落抓取点不稳定或物体太容易滚动提高采样密度和质量网络阈值ZeroGrasp 里最大比例的失败来自“定位失败”而且集中在物体边缘的深度渐变区域。后来我用深度预测的不确定性掩码把边缘区域的可抓置信度降低成功把失败率压到可接受范围。这一招比换更大的深度估计网络更有效因为问题根因是单图深度在边缘天然模糊任何模型都难幸免。跑完这轮系统我自己最大的体会是别神话“单图 3D 重建”这四个字也别把它当成一步到位的魔法。它本质上是把信息缺口转化为不确定性的过程而抓取能否成功取决于你能不能优雅地处理这些不确定性。先把标定、后处理、误差预算这些确定性环节做扎实再让不完美的深度模型去发挥成功率提升往往比换个更强网络更明显。