ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深度摄像头入门与选型:结构光、双目、ToF及点云实战

深度摄像头入门与选型:结构光、双目、ToF及点云实战 第一次拆开一台深度摄像头的时候我盯着里面那块红外激光模组和旁边的两颗镜头愣了半天——外形跟用了十几年的普通 USB 摄像头差不了多少凭什么它就能知道前面那面墙离我 1.2 米后来做视觉引导抓取的项目连续踩了两个月的坑我才算真正把这东西的门道摸清楚。深度摄像头不是更清楚的摄像头它本质上是一台测距仪器只是顺手给你配了张彩色图。它能输出每个像素到镜头的距离把二维画面变成三维空间信息解决的问题是物体在哪、有多大、离多远、动了没。这篇内容适合三类人刚接触机器视觉的学生和转行者、要选型的硬件/算法工程师、以及想把人脸识别、手势交互、体积测量、避障这些功能塞进产品里的开发者。哪怕你完全没有视觉基础跟着看下去也能明白它每一行参数在说什么。1. 深度摄像头到底在测什么三句话讲清它和普通摄像头的区别1.1 普通摄像头给的是颜色深度摄像头给的是距离普通摄像头的工作方式是被动接收外界光线打到物体上反射回来穿过镜头落在传感器上传感器记录的是每个像素接到的光有多强、什么颜色。它拿到的信息里完全没有距离这一维一张 1920×1080 的照片本质上是一张 200 多万个格子的颜色表前景和背景被压扁在同一个平面上。你想让机械臂知道杯子在桌上哪个位置光靠这张表是不够的只能靠推断——比如看阴影、看透视、看物体之间谁挡住谁这些推断在实验室里勉强能用换到真实环境就崩。深度摄像头在输出彩色图之外还会额外输出一张深度图Depth Map。深度图的每个像素值不是颜色而是距离单位通常是毫米。比如深度图上第 (300, 200) 这个点写着 1250意思就是镜头正前方这个方向、1.25 米的地方有东西。有了这张图你随手就能做几件事把深度值小于 800 的像素全部抠出来得到前景物体的掩膜把整个场景的深度图反投影成点云直接在三维空间里量尺寸、算体积、做平面拟合。彩色图告诉你这是什么深度图告诉你它在哪两者叠加起来才是完整的空间感知。我一般用一句话跟新人解释普通摄像头拍的是一张画深度摄像头拍的是一张带高度信息的地形图。画只能看地形图能拿尺子量。1.2 一只蝙蝠教我的事主动测距和被动测距工作环境里的深度摄像头按测量原理大致分成主动和被动两大类。这个分类跟蝙蝠和海豚的思路一模一样——蝙蝠在黑暗里飞行靠的不是眼睛而是嘴里发出超声波、用耳朵听回音从回声的时间差判断前面有没有障碍物。这就是主动测距设备自己往外发信号再接收反射回来的信号。深度摄像头发的不是声音是红外光或者激光速度快、精度高、体积小。被动测距则更像人的双眼。你有两只眼睛左右眼看到的画面有细微差别大脑根据这个差别算出距离——闭上一只眼睛去戳桌上的笔尖你会发现准头明显下降就是这个道理。双目立体视觉就是纯被动方案它不发光只靠两颗摄像头拍到的视差来算深度。好处是功耗低、没有激光安全问题、在室外阳光下也能用坏处是特别挑环境遇到纯白墙面、玻璃、大面积单色地毯这类没有纹理的表面算法根本找不到左右图之间的对应点深度图就会大面积空洞。除此之外还有第三类介于两者之间叫结构光它主动投射一张已知的红外光斑图案到场景里再用摄像头看这张图案被物体表面掰弯成什么样。相当于主动给场景画上纹理然后再去匹配所以它既有主动方案的精度又保留了双目匹配的思路。理解这三种路线的差别是选型的第一道关。1.3 哪些项目真的需要它哪些纯属浪费钱我见过太多项目一上来就写用深度摄像头实现结果做下来发现根本用不上。判断标准其实很简单你的任务里是否存在必须知道距离这一环。如果答案是肯定的深度摄像头值得上如果只是识别一个颜色、读一个二维码、判断有没有人经过普通摄像头加算法就够了。具体来说这几类任务用深度摄像头是刚需。第一类是三维测量包裹体积测量、零件平面度检测、料箱内物料余量估算这些都要真实的三维坐标二维图靠标定换算误差太大。第二类是空间避障与导航扫地机、AGV 小车、无人机定高需要知道前方障碍物的实际距离深度图给的是直接的几何信息比单目测距稳得多。第三类是人机交互手势识别、体感游戏、人脸活体检测判断是真人还是照片深度信息能有效防作弊。第四类是视觉引导抓取机械臂从料筐里随机抓取堆叠的零件必须知道每个零件的位姿这属于深度摄像头的经典战场。反过来这几个场景我建议先别急着上深度。一是只在固定工位做二维缺陷检测相机位置不动、物体在固定平面上普通工业相机加光源足够。二是远距离室外大场景普通深度摄像头的有效量程通常在 0.3~5 米再远精度掉得厉害得上激光雷达。三是预算极度紧张的消费级产品一颗深度模组的成本可能顶两三颗普通摄像头如果功能上单目能凑合就没必要硬加。我自己的习惯是先拿普通摄像头做一版原型把哪里确实缺深度信息列出来再决定要不要换硬件这样能省下大量返工时间。2. 三条主流技术路线的真实取舍结构光、双目、ToF2.1 结构光把一张已知图案掰弯来算距离结构光的核心思路很巧妙既然是匹配困难导致双目方案翻车那我就主动给场景打上一层纹理。设备里有一个红外激光发射器透过一块刻有特定图案的光学元件业内常叫 DOE把一张密密麻麻的光斑阵列投射到前方物体上。旁边一颗红外摄像头拍下这张图案另一颗或者同一个模组作为参考通过比对图案的形变程度反推每个点的深度。它的优势非常明确近距离精度高。在 0.3 到 1 米这个区间做得好的结构光模组深度误差能压到 1 毫米以内细节保留得非常好人脸建模、小零件测量这类活它能干得很漂亮。缺点同样明显怕光、怕远、怕吸光材质。室外强光里的红外成分会直接淹没投射的光斑太阳底下基本没法用距离一拉远光斑在传感器上糊成一团精度断崖式下跌而黑色绒布、哑光海绵这类强吸光表面会把光吃掉深度图上直接留下黑洞。另一个隐性成本是标定投影仪-相机系统出厂标定一旦受震动偏移整机精度就废了返修率不低。2.2 双目立体视觉模仿人眼但比人眼挑食双目方案的硬件最干净两颗完全相同的摄像头经过严格标定外加一块算力还行的处理器。它的原理就是三角测量——同一个空间点在左右两幅图里成像位置有水平偏移这个偏移量叫视差视差越大说明物体越近。公式非常简洁$$Z \frac{f \cdot B}{d}$$其中 Z 是深度f 是相机焦距以像素为单位B 是两镜头之间的基线距离d 是视差像素。这个公式我在后面讲精度的时候还会用到值得先记住。双目最大的好处是成本低、无激光安全问题、室外可用所以很多扫地机和消费级机器人选它。坏处是它完全依赖匹配这一步而匹配要求画面里有可区分的纹理。白墙、纯色地板、玻璃、镜面这些地方它算不出视差深度图就是一片空洞。同时它对算力有真实要求做一次稠密匹配通常要跑实时立体匹配算法在嵌入式平台上功耗和延迟都不低。我在一个室内机器人项目里用过双目方案白天开窗的时候深度图还挺干净一到傍晚拉上窗帘、地面反光变弱可用的深度点直接掉了三成。2.3 ToF直接给光掐表ToF 是 Time of Flight 的缩写直译就是飞行时间。它的思路最直白发射一束调制过的红外光光打到物体反射回来我测量光从出发到返回用了多少时间乘以光速再除以二就是距离。实际工程里为了测准纳秒级的时间差普遍用连续波调制的做法——不是测单个脉冲而是发射一个高频正弦调制的光通过测量反射回来那束光的相位偏移来换算距离。ToF 的特点是响应快、帧率高、精度在整个量程内比较均匀而且它对物体表面纹理不敏感白墙也好、纯色地板也好只要有反射就测得到这是它相对双目和结构光最实在的优势。它的短板在于几个方面一是多径干扰光在墙角、桌角这种地方多次反射回来会算出一个虚假的深度值表现为边缘出现莫名其妙的飞点二是深度模糊距离的限制调制频率越高精度越好但能测的不模糊距离会缩短超过这个距离深度值会绕回来必须在算法里做解模糊三是功耗和发热高帧率高分辨率的 ToF 模组连续跑起来温度不低温漂会带来系统性偏差需要做温度补偿。2.4 选型对照表与最容易踩的坑把三条路线的关键差异列在一起看选型会清楚很多维度结构光双目立体视觉ToF测距原理投射已知图案看形变双镜头视差三角测量调制光相位差典型量程0.2~1.5 m0.5~10 m随基线变化0.2~6 m近距离精度很高亚毫米~毫米级中等中等偏上室外表现差强光下基本失效好白天可用一般受阳光红外干扰对无纹理表面好自带纹理差容易空洞好算力占用中等高立体匹配低多为模组内处理典型成本中高低到中中选型的时候我建议按这个顺序问自己四个问题一是距离范围你的工作距离是 30 厘米还是 3 米这一步直接淘汰掉一半候选二是环境光条件是否在室外或者有强阳光直射有的话结构光基本出局三是被测物表面是不是白墙、玻璃、镜面、黑色吸光材质是的话优先 ToF 或结构光四是算力预算主控芯片能不能扛住实时立体匹配。最容易踩的坑有三个。第一个是只信参数表上的最大量程那个数字通常是在理想条件下测的实际有效量程往往要打七折。第二个是忽略安全等级激光类产品在消费场景要满足相应的激光安全等级要求选型时务必确认模组已经过相关认证别自己拿裸模组往产品里塞。第三个是忘了考虑机械结构ToF 和结构光的发射-接收窗口需要保持洁净一旦被油污、灰尘糊住深度图会整体劣化产品上必须留出擦拭和防尘设计。3. 参数表里那些数字哪个才是真指标3.1 分辨率、视场角与基线三个决定看多广、看多细的量分辨率分两种彩色图分辨率和深度图分辨率这两者经常不一样。市面上不少模组的彩色图能到 1920×1080深度图只有 640×480选型时要分开看。深度图分辨率直接影响你能分辨多小的物体也影响点云的密度。我做体积测量的时候640×480 在 1 米距离上单个像素的横向间隔大约 2 到 3 毫米量纸箱绰绰有余量小螺丝就不够了。**视场角FOV**决定一次能看到多大范围。视场角越大同样的分辨率下单位角度的像素变少精度会下降而且边缘区域的畸变更严重。很多模组标称的水平视场角是 60 度到 90 度实际有效的高精度区域往往集中在中央 50 度左右边缘一圈的数据质量明显差一截。我在做抓取项目时会刻意把目标物体放在画面中央区域边缘只用来做粗略的避障判断。基线是双目的专属参数指两个镜头光心之间的距离。由前面的公式可以看出来基线越大同样的视差下测出的深度越准但基线大了之后近处物体的视差会超出搜索范围最近可测距离会变远而且模组体积会变大。所以基线是一个需要权衡的量近距离高精度的模组基线通常只有几厘米远距离测绘型的基线能做到几十厘米。选型时看到某模组标称量程 0.1 米起先确认它的基线是多少别被数字骗了。3.2 深度精度到底怎么算跟我一起把公式算一遍精度是所有人最关心、也最容易被含糊表述糊弄的参数。我用双目的公式给你实算一次你就明白精度这两个字有多不靠谱了。假设某模组 f 1400 像素B 50 毫米现在要测一个距离 1000 毫米的物体$$d \frac{f \cdot B}{Z} \frac{1400 \times 50}{1000} 70 \text{ 像素}$$视差值大约是 70 个像素。现在关键的一步来了——视差误差会被放大成深度误差。对公式求导$$\Delta Z \frac{Z^2}{f \cdot B} \cdot \Delta d$$代入 Z 1000、f·B 70000、假设立体匹配的视差误差 Δd 0.1 像素$$\Delta Z \frac{1000^2}{70000} \times 0.1 14.29 \times 0.1 \approx 1.43 \text{ 毫米}$$也就是说在 1 米处深度误差约 1.4 毫米。但如果把距离拉到 2 米同样的视差误差下$$\Delta Z \frac{2000^2}{70000} \times 0.1 \approx 5.7 \text{ 毫米}$$误差直接涨了四倍。这就是精度随距离平方衰减的来源也是为什么所有深度摄像头在标称量程的远端精度都会崩。厂商在手册里写精度 1 毫米绝大多数情况下指的是最近工作距离附近的最好成绩而不是全量程的平均值。做方案时我一般会留出 2 到 3 倍的安全余量。ToF 的精度逻辑不太一样它主要受调制频率和信噪比影响。调制频率越高一个完整周期对应的距离越短相位测量越精细精度越好但与此同时不模糊距离 (Z_{max} c / (2 f_{mod})) 会缩短。举例来说f_mod 100 兆赫兹时不模糊距离约为 1.5 米超过这个距离的物体会被折算到测量范围内出现远近混淆。工程上常用多个调制频率组合来扩展量程代价是采集时间变长、帧率下降。结构光则通常用一套出厂标定的查找表把相位或图案偏移映射成深度精度分布是近处极好、远处快速恶化。3.3 帧率、延迟与多机同步别让总线成为瓶颈帧率决定你能捕捉多快的动作。30 帧每秒是主流模组的基础配置做手势交互基本够用做高速抓取或者抖动检测可能要到 60 甚至 90 帧每秒。但要提醒一句很多模组标称的高帧率是在降低分辨率的前提下实现的参数表上90fps旁边往往跟着一行小字写着320×240一定要把这两个数字一起看。延迟和帧率是两件事。帧率高不代表延迟低因为从曝光、深度计算、数据传输到主机拿到数据中间可能有几十毫秒的链路。做闭环控制的项目里这个延迟会直接体现在控制精度上。我做过一个简单的测量某模组的标称帧率是 30fps但端到端延迟实测约 90 毫秒抓取节拍快的场景下这个延迟是致命的后来改用模组内置处理、减少主机往返通信才把延迟压下来。多机同步是很多人到项目中期才发现的坑。同一个场景里放两台深度摄像头尤其是同型号的主动光源会互相干扰——A 投射的红外图案被 B 的传感器拍到深度图上会出现规律性的条纹或者片状噪声。解决办法主要有三种错开采集时序分时轮询、使用支持外触发同步的模组、或者干脆换不同调制频率的型号。如果项目一开始就规划多机这个同步方案要在选型阶段就定好。3.4 接口与算力预算先算带宽再选主控深度数据是高带宽数据这一点经常被低估。算一下就清楚了一张 640×480 的深度图每个像素用 16 位2 字节表示单帧就是 614400 字节约 600KB。30 帧每秒就是 18 MB/s再加上同步传输的彩色图假设 1280×720、YUV422 格式单帧约 1.8MB30fps 就是 55MB/s总带宽接近 75MB/s。USB 2.0 的理论带宽只有 480 Mbps实际可用约 320 Mbps40MB/s根本不够用所以这个量级的数据必须上 USB 3.05Gbps或者千兆网口、MIPI 直连。我在早期项目里用 USB 2.0 接过一颗模组结果就是帧率被强行砍到 5fps深度图还时不时丢帧排查了半天才发现是带宽满了不是模组的锅。主控侧的算力也要提前估。如果模组自带深度计算现在大多数消费级模组都是这样主机只需要做后处理和业务逻辑一颗中端 ARM 芯片就够了。如果是裸双目传感器模组稠密立体匹配要在主机上跑那至少需要一颗带 SIMD 指令的处理器或者专用加速单元否则实时性无从谈起。我的经验是选型阶段拿一张真实场景图在目标平台上跑一遍算法看能不能稳定跑到 20fps 以上比看任何参数表都靠谱。4. 从拆箱到出第一张深度图完整实操记录4.1 硬件部署与环境布置先把物理条件摆平模组到手之后别急着插电。先做三件事。第一找一个稳定的安装方式。深度摄像头对震动很敏感尤其是双目和结构光这类依赖标定的模组用扎带或者双面胶随手一贴跑两天精度就跑偏。我一般用带螺孔的金属支架固定模组和支架之间垫一层薄橡胶垫做隔振。第二检查工作距离和视场角是否覆盖目标区域。把模组临时装上用彩色图看一眼画面确认目标区域完整落在画面里而且尽量靠近中心。第三处理反光和强光。如果画面里正对着窗户、镜面、抛光金属先把这些东西遮掉或者换个角度不然你调试时看到的第一个深度空洞就是它们造成的。环境温度也要留意。ToF 和结构光模组通电后一般需要预热一到三分钟让内部温度稳定深度值才会收敛。我在项目里养成了一个习惯采集数据前先让模组空转几分钟同时观察深度图上的固定平面数值波动波动小于 2 毫米了再开始正式采集。这一步看着多余但能省掉后面一大堆为什么数据在飘的排查时间。4.2 驱动、SDK 与固件版本那些文档不会写的坑模组厂商通常会提供 SDK里面包含驱动、示例程序和一个可视化工具。安装顺序一般是先装驱动再插设备最后装 SDK顺序颠倒容易导致设备枚举失败。Linux 环境下如果用的是 USB 模组可能需要配置 udev 规则把设备权限放开否则程序会报打不开设备的错误。这一步在文档里往往一笔带过但新手卡在这里的比例非常高。注意官方 SDK 的示例程序通常跑的是厂家自己的可视化窗口不是你要的 API。想在自己的程序里取数据要找到 SDK 里暴露的数据回调接口或者裸流接口别对着 GUI 工具研究半天。更隐蔽的坑是固件和 SDK 版本不匹配。同一款模组不同批次的固件版本可能不一样而 SDK 的某些接口在新固件里改了行为。我遇到过一次深度图正常但彩色图和深度图的像素对齐差了十几个像素查了很久才发现是固件升级后对齐参数表变了SDK 版本没跟上。所以拿到模组第一件事就是记录固件版本号并锁定一套能跑通的 SDK 版本别随便升级尤其是在项目中期。4.3 采集并可视化第一帧深度数据环境准备好之后先跑通能出图这一步。假设 SDK 提供了类似get_frames()的接口返回彩色帧和深度帧深度帧是 16 位无符号整型数组单位毫米。可视化时要注意一点深度值不能直接当灰度图显示。因为深度值动辄几千而图像显示范围是 0 到 255直接显示整张图会白成一片。正确的做法是做一次归一化或者截断映射。截断映射在工程里更好用因为你能指定感兴趣的距离区间import numpy as np import cv2 def visualize_depth(depth_mm, near300, far2000): 把深度图映射成灰度图near/far 之外的像素置黑 d depth_mm.astype(np.float32) # 无效值通常是 0置为 far避免被误认为是一米内的物体 d[d 0] far # 截断到 [near, far] 区间 d np.clip(d, near, far) # 线性映射到 0-255注意近处要亮所以做反向 gray 255 - ((d - near) / (far - near) * 255).astype(np.uint8) # 上色更直观用 COLORMAP_JET color cv2.applyColorMap(gray, cv2.COLORMAP_JET) return color跑出第一张图之后先做几个定性检查站在模组前伸手手的轮廓在深度图上是否清晰移动一下深度值变化是否跟得上对着一面平整的墙整张图的深度值是否均匀如果出现明显的波浪纹或者环状条纹多半是标定或者多径干扰问题。这几个检查花五分钟能提前发现大部分硬件层面的问题。4.4 内参标定与外参对齐把像素坐标变成真实的三维坐标要用深度摄像头做测量标定是绕不过去的一步。内参描述的是相机自身的成像特性包括焦距 fx、fy 和主点 cx、cy还有畸变系数。外参描述的是深度模组和彩色模组之间的相对位置也就是旋转和平移矩阵。两者都拿到才能把彩色图上的一个像素映射成空间中的一个三维点。标定工具我习惯用 OpenCV 的棋盘格方案稳定、资料多。流程是先打印一张棋盘格标定板常用 9×6 格、方格边长 25 毫米从不同角度拍 20 到 30 张照片注意覆盖画面中心和四个角标定板要倾斜一些别全都平行于成像平面import numpy as np import cv2 import glob # 棋盘格内角点数量格子数减一 pattern (8, 5) criteria (cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) objp np.zeros((pattern[0] * pattern[1], 3), np.float32) objp[:, :2] np.mgrid[0:pattern[0], 0:pattern[1]].T.reshape(-1, 2) objp * 25.0 # 方格实际边长单位毫米 objpoints, imgpoints [], [] for path in sorted(glob.glob(calib/*.png)): img cv2.imread(path, cv2.IMREAD_GRAYSCALE) ok, corners cv2.findChessboardCorners(img, pattern, None) if not ok: print(未找到角点跳过:, path) continue corners cv2.cornerSubPix(img, corners, (11, 11), (-1, -1), criteria) objpoints.append(objp) imgpoints.append(corners) ret, K, dist, rvecs, tvecs cv2.calibrateCamera( objpoints, imgpoints, img.shape[::-1], None, None) print(重投影误差(像素):, ret) print(内参矩阵:\n, K) print(畸变系数:\n, dist.ravel())重投影误差是判断标定好坏的唯一标准。这个值在 0.5 像素以内算优秀0.5 到 1 像素可用超过 1 像素就要检查照片质量了——常见原因是标定板不平整、拍摄时有运动模糊、或者角点覆盖范围太集中。我一般会删掉误差最大的那几张重新跑一遍通常能把误差压下来一半。有了内参之后把深度图转成点云就非常直接了本质上是像素坐标乘上深度除以焦距def depth_to_xyz(depth_mm, K): 把深度图反投影成点云返回 H x W x 3 的数组单位毫米 h, w depth_mm.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_mm.astype(np.float32) valid z 0 # 无效深度先标记出来 x np.zeros_like(z) y np.zeros_like(z) x[valid] (u[valid] - cx) * z[valid] / fx y[valid] (v[valid] - cy) * z[valid] / fy return np.stack([x, y, z], axis-1), valid如果你还需要把彩色贴到点云上就要用外参把深度坐标系下的点变换到彩色坐标系再用彩色内参投影回彩色图像取颜色。这一步的精度取决于两模组之间的标定质量如果发现颜色和点云错位通常是外参没标好或者出厂对齐参数被固件覆盖了。5. 拿到深度数据之后滤波、点云与业务落地5.1 空洞填补与飞点滤除先把脏数据洗干净原始深度图几乎不可能直接拿来用。最常见的三类脏数据是空洞值为 0 或者无效标记、飞点边缘处孤立的高误差点和噪声随机的小幅波动。处理方法按场景选。空洞填补的常用手段是形态学闭运算加邻域插值。对于小面积空洞直接用 3×3 或 5×5 的闭运算就能补上面积较大的空洞用周围有效像素做联合双边滤波插值效果更好因为它会同时参考彩色图的边缘信息避免把物体边界糊掉。但要注意在物体边缘处的空洞不要强行填补那里是深度不连续的地方插值出来的值往往是错的宁可留空。飞点滤除最有效的办法是统计离群点滤波对每个点算它到最近 k 个邻居的平均距离超过全体均值加若干倍标准差的点判为离群。点云库里有现成实现自己写也不难。还有一个更简单的做法是用中值滤波对深度图做 3×3 中值边缘飞点会被明显压制代价是深度图的细节略有损失。我在一个料筐抓取项目里总结出一条经验先把有效深度点的比例统计出来作为数据质量的健康指标。正常情况下画面里有物体的区域有效点比例应该在 70% 以上如果低于 50%说明环境或者标定出问题了这时候调算法是白费力气应该回去查硬件。这个指标我后来直接做成了程序启动时的自检项。5.2 平面拟合与坐标系变换让深度数据落到真实世界拿到点云之后业务上第一步往往不是识别而是建立参考平面。绝大多数工业场景里物体都放在一个平面上比如桌面、传送带、料筐底部。用随机采样一致性算法RANSAC拟合出这个平面就能得到平面的法向量和方程后面所有的高度测量都以它为基准。这一步的价值在于你可以把物体相对于相机的距离转换成物体相对于工作台的高度后者才是业务真正关心的量。RANSAC 的核心参数是距离阈值和迭代次数。距离阈值一般取 1 到 3 毫米太小了平面点不够太大了会把物体上的点也算进平面。迭代次数经验值是 100 到 500 次平面比较干净时 100 次足够。拟合完之后把到平面距离小于阈值的点剔除剩下的就是前景物体可以进一步做聚类和位姿估计。如果需要把点云从相机坐标系转换到机械臂坐标系就要做手眼标定。基本思路是让机械臂抓取标定板在多个不同位姿下运动同时用相机拍摄标定板通过多组对应关系解出相机与机械臂末端或者基座之间的变换矩阵。这部分内容单独拿出来能写一整篇这里只说两个容易出错的点一是标定板的位姿要尽量分散全都平移不旋转的话旋转分量解不出来二是标定完成后一定要做验证让机械臂带着一个尖端点去触碰几个已知位置看相机算出来的坐标和实际坐标差多少差值在任务允许范围内才能交付。5.3 三个典型场景的落地思路场景一包裹体积测量。核心需求是算长宽高。做法是先用深度图加 RANSAC 找到传送带平面把平面以上的点全部保留投影到平面得到一个二维轮廓用最小外接矩形算长宽再用点到平面的最大高度算高。精度主要受过分割影响如果包裹颜色和传送带接近可能要用深度阈值配合形态学操作分离。实测在 1 米距离上单边误差能控制在 5 毫米以内对快递计费来说完全够用。场景二料筐内随机抓取。这是深度摄像头最有价值的应用之一。思路是先拟合料筐底部平面把筐壁和底部滤掉剩下的点云做欧式聚类把堆叠的零件分成一个个点簇然后对每个点簇做位姿估计比如主成分分析给出主轴方向或者用模板匹配做 6D 位姿。选的时候优先挑最上面、最容易被夹爪够到的那个。这个场景的坑在于遮挡堆叠零件的下半部分根本看不到深度图只能给你可见表面所以抓取策略必须配合抓完再拍一张的迭代流程。场景三手势与人体交互。做法通常是先用深度阈值把近处的人体分离出来背景深度大、人深度小再做骨架关键点检测。深度信息在这里最大的价值是防误触发和区分前后景如果你只做二维手部检测画面里贴一张手的照片也会触发加上深度判断手到镜头的距离在 30 到 80 厘米之间照片就骗不过去了。这个思路在人脸活体检测里也常用判断人脸区域的三维起伏是否自然能有效区分真人和平面照片。6. 实操中最容易翻车的几个点问题排查速查6.1 深度图大面积空洞先别怀疑算法空洞是最高频的问题但它的成因分布很广按概率从高到低排依次是被测表面特性问题、环境光问题、标定问题、硬件问题和算法问题。表面特性方面玻璃、镜面、黑色哑光材料、透明塑料是重灾区。玻璃和镜面会让光要么穿透要么反射到别处深度值要么无效要么测到镜子后面的虚像黑色材料吸光返回的光太弱信噪比不够。解决思路是贴一层哑光贴纸或者喷一层显像剂改变表面光学特性这比调算法有效得多。环境光方面强阳光里的红外成分会淹没主动光源这个基本无解只能改方案。室内的话还要注意某些大功率灯具比如一些卤素灯、白炽灯会发出较强红外可以关灯试一下对比深度图的变化。标定方面如果空洞呈现规律性的条纹或者块状且位置固定很可能是标定参数不对或者模组内部的图案投射元件脏了。硬件方面检查镜头是不是有指纹、油污发射窗口有没有被遮挡USB 线有没有接触不良导致的数据丢包。6.2 多机互扰与温漂两个慢性的坑多机互扰的典型表现是深度图上出现随机的条带状噪声或者间歇性的错误深层。判断方法很简单关掉其中一台看问题是否消失。解决手段前面提过分时轮询、外触发同步、或者换不同调制频率的型号。如果三台以上同时工作建议做严格的时序调度每台分配独立的采集窗口哪怕牺牲一半帧率也比拿到一锅粥的数据强。温漂是最容易被忽视的。模组通电后温度上升内部光学元件会发生微小的热胀冷缩标定参数随之漂移表现为对同一面墙的深度读数在开机 10 分钟内缓慢变化几毫米。我做长时间采集的项目时会先让模组预热 15 分钟再做标定或者在软件里加温度补偿——记录几个温度点下的偏差量用线性拟合做修正。如果模组的 SDK 本身就提供温度补偿接口直接用就行别自己造轮子。6.3 问题排查速查表现象最可能的原因排查顺序与处理办法深度图整体全黑或全 0设备未正常出流、权限不足检查驱动与 udev 规则用官方 GUI 工具先确认能出图大面积片状空洞无纹理或吸光表面、玻璃镜面移动或更换被测物表面贴哑光材料验证边缘大量飞点深度不连续处的匹配错误、多径干扰加中值滤波或对边缘区域标记为不可信深度值在开机后缓慢漂移温漂预热 15 分钟后再标定启用温度补偿深度图有规律条纹多机互扰、主动光源被同频干扰关掉其他设备验证改分时采集或外触发同步彩色和深度错位外参不准、固件升级导致对齐参数变化重新做外参标定回退 SDK 版本验证帧率远低于标称带宽不足、分辨率未降、算力不够核对接口带宽降低分辨率试跑检查 CPU 占用这张表是我几个项目下来攒的基本上覆盖了八成以上的现场问题。每次去现场调试我都会先按这张表从上往下过一遍比漫无目的地改代码效率高得多。6.4 几个不值当踩的坑说点掏心窝的经验第一别迷信标称精度。我见过太多方案书里直接抄手册上的精度 1 毫米结果实际做完发现全量程平均误差 8 毫米交付时非常被动。选型阶段一定要拿到实机在自己的真实场景、真实距离下测一遍用平面板从近到远测十几个距离点画出误差曲线这才是能写进方案的数。第二别忽略机械结构设计的长期影响。我做过一个户外设备模组本身的防尘防水做得不错但发射窗口外面那层保护玻璃用了普通亚克力半年后表面被磨花深度图质量整体下降。后来换成镀膜光学玻璃才解决。这类问题在实验室里根本暴露不出来只有上现场才会显现。第三把数据质量自检写进程序里。有效深度点比例、深度值分布、固定参考面读数这三个指标我后来都会做成程序启动时的自检项异常时直接报警。这比出了问题再回头查日志省太多事了尤其是现场部署了十几台设备的时候。第四留足算力和带宽余量。我个人的经验是算力按峰值需求的 1.5 倍配带宽按 2 倍配。深度数据的处理链路里滤波、点云转换、聚类每一步都可能比预想中吃资源加上后期的算法迭代一开始就卡着边配会非常难受。最后再说一个我自己的观察深度摄像头这东西硬件决定下限标定和数据处理决定上限。同一颗模组标定做得好、滤波参数调得合适出来的数据质量能差出一倍以上。所以别急着上复杂的三维识别算法先把标定和清洗这两步做到极致很多看起来很难的任务其实在数据变干净的那一刻就解决一半了。
返回列表