拓冰建站拓冰建站
首页 / 资讯中心 / 正文

DIODE数据集全解析:从激光扫描到像素级密集深度与法线

这几年做单目深度估计和相关视觉任务我手里攒了不少数据集的下载链接和踩坑记录。但说实话真正让我愿意花一整个周末去摸清底细的DIODE算是头一个。原因很简单这个数据集在“深度图是不是真的来自传感器”这件事上做到了让我服气。DIODE的全称是Dense Indoor/Outdoor DEpth直译就是密集室内外深度数据集名字就写得很明白——它同时覆盖室内和室外场景并且提供像素级密集的深度图和平面法线图。你要是跑过NYUv2、ScanNet或者KITTI应该能体会到那种“深度图上一片黑、有效值只有一小块”的憋屈而DIODE的设计目标就是把这几个老牌数据集的毛病一次性解决掉。这篇文章我打算从数据集的设计动机、数据形态、传感器原理、实际操作加载流程再到我实际跑模型时踩过的坑完整拆解一遍。不管你是准备拿它做单目深度估计的zero-shot测试还是想研究RGB-D与法线的联合学习或者只是想把数据集里的法线图当成监督信号来用这篇都能给你省下不少时间。1. 为什么需要DIODE现有深度数据集的三宗罪要说清楚DIODE的价值得先看看它想解决的几个痛点。这些痛点不是论文里包装出来的而是我们在实际炼丹过程中真真切切遇到的。1.1 不完整深度带来的“学习假象”优先聊深度不完整的问题。NYUv2和ScanNet这类基于消费级RGB-D传感器比如Kinect采集的数据集深度值天然存在大量无效区域。玻璃、高光、黑色物体、远距离物体都会让红外结构光找不着北最后产出的深度图经常是“中心一条竖条有值四周全是黑”。KITTI好一点但它用的是车载激光雷达扫描线是单线的物体边缘和细小结构上有效深度稀疏得要命而且最远深度被限制在80米左右。这些“黑区”带来的麻烦在于模型很容易学到一种偷懒的解法。我试过用NYUv2训练一个编码器-解码器结构的深度估计网络发现在训练时如果直接忽略无效区域做损失计算模型会在测试时倾向于把不确定区域全部回归成一个保守的中间深度值而不是真正去推理物体边界。这属于一种隐式的数据偏差模型把“看不清”当成了“应该输出均值”。DIODE从源头尽量减少了这个问题它用的FARO Focus S350激光扫描仪能产生几乎全覆盖的扫描点云再通过点云拼接和虚拟相机投影生成的是真正的像素级密集深度有效覆盖率比Kinect这类设备高出一个级别。1.2 传感器不一致与场景分布失衡第二个问题是传感器不一致。现在很多工作习惯拿NYUv2做室内、KITTI做室外两个数据集的传感器原理不同、深度范围不同、尺度定义不同训练和评测的时候要在两套协议之间来回切非常痛苦。而且这两者的场景分布也很极端——NYUv2只有室内房间KITTI几乎全是道路和车辆没有一个数据集能让同一个模型在“室内卧室”和“室外街景”之间做到平滑覆盖。DIODE的采集策略是同时包含室内和室外的高质量扫描数据。室内场景有办公室、楼梯间、实验室这种典型环境室外场景有建筑立面、街道、植被等。关键是不管是室内还是室外它都用同一套激光扫描仪和相同的投影管线来处理传感器的一致性得到了保证。这样你在做跨场景泛化实验时就不会因为传感器模态差异而引入额外变量。1.3 合成数据与真实世界的“模拟缝隙”还有一个问题出在合成数据上。前几年SUNCG这类CAD级别的合成数据集非常流行优点是可以免费获得像素级完美的深度和法线训练时想生成多少就有多少。但合成数据的硬伤是渲染纹理过于干净、几何形状过于规整模型在合成数据上训练完搬到真实世界测试时经常出现明显的域偏移。有一类专门研究深度归一化的论文就指出在SUNCG上预训练的模型在真实室内场景上的相对误差比在真实数据上训练的模型高出将近一倍。DIODE的做法完全不依赖合成渲染。它的每一张深度图和法线图都来自真实激光扫描仪的物理测量这保证了ground truth里包含了真实世界的噪声特性和几何复杂度。对做domain adaptation或者domain randomization的组来说DIODE是一个比SUNCG靠谱得多的真实域基准。2. DIODE到底提供什么数据形态与核心指标了解了动机接下来具体看看DIODE里到底有什么。这部分我带大家过一遍数据集的构成、传感器方案、目录结构和下载申请流程顺带把它的技术指标和几个常见数据集做个对比。2.1 数据集构成与传感器方案DIODE由约翰霍普金斯大学发布ICCV 2019那篇论文就是它的技术报告。训练集包含136张图像验证集包含288张图像总共400多张。你可能觉得这个数量比起ImageNet那种百万级数据量实在太小了但你要明白DIODE的定位并不是拿来做大规模预训练而是作为高精度评测基准。它的每一张图都是从激光扫描点云通过严格投影管线生成的单位像素的标注质量非常高这一点和那些“随便拿个深度传感器扫一下”的数据集有本质区别。传感器方面DIODE选的是FARO Focus S350地面激光扫描仪这台设备的最大测程能到350米在室内场景下也能保证亚厘米级的测距精度。采集的时候研究团队先在场景里布置多个扫描站点把不同角度的点云拼接起来得到一个完整的场景级点云再把这个场景点云投影到虚拟相机平面上从而生成与RGB图像对齐的密集深度图。这个流程比拿着手持RGB-D相机边走边录要严谨得多。2.2 深度图与法线图的配对逻辑DIODE每组样本一般包含RGB图像、深度掩码、深度图以及对应的平面法线图。深度掩码标记了哪些像素的深度值是有效的这在评测时非常重要因为不是所有像素都能被激光点云完全覆盖到比如天空和极高反射区域。深度图存储的是每个有效像素到相机平面的度量距离单位是米而法线图则存储每个像素对应表面法向量的三个分量X、Y、Z方向。关键点在于法线图并不是单独用一个网络预测出来的而是直接从同一个三维点云几何中求出来的。这样深度和法线在数学上是严格一致的——你从深度图反推法线应该能复现出官方给的法线图。这一点太重要了因为很多数据集提供的多模态标注是互相打架的深度图和法线图来自不同的处理管线训练的时候两个head会互相干扰。而DIODE这种“从同一几何源导出多模态标注”的做法让我在做多任务学习时省了一堆调loss权重的力气。2.3 目录结构与下载申请流程下载DIODE需要走一个简单的申请流程。官网提供的是打包好的tarball里面按indoor和outdoor分场景每个场景文件夹下通常包含png/RGB图像一般是768x1024分辨率depth.npy深度数组存的是纯浮点数据depth_mask.npy有效像素掩码normal.npy法线图数组intrinsics.npy相机内参矩阵我建议先在验证集val上做评测因为验证集的288张图官方划分好了场景类别方便你按室内、室外分别统计指标。申请通过后你会在邮箱里收到下载链接整个过程就是填表、等邮件、下载、解压。需要提醒的是申请表里最好写清楚使用机构、研究方向和用途回复率会高很多。2.4 和其他数据集的横向对比稍微整理一个表格方便大家对照选型数据集场景类型传感器深度完整性是否提供法线数据规模深度范围DIODE室内室外FARO激光扫描仪高是136训练288验证室内0.5-10m室外可达几十米NYUv2仅室内Kinect v1低有大量黑区是另算约1449张标注0.5-10mScanNet仅室内Kinect v2中低否约250万帧0.5-6m左右KITTI仅室外道路车载激光雷达稀疏单线结构否约4万张对齐图像0-80mSUNCG合成室内CAD渲染高是可无限生成由场景决定从这个表能直观看到DIODE是目前少有的“室内外兼顾 高精度真实传感器 自带法线标注 深度法线一致”的组合型数据集。对做通用深度和法线估计的组来说它的性价比非常高。3. 核心细节解析从原始点云到像素级Ground Truth如果你想深入研究这个数据集而不只是拿它跑个指标得理解它的生成流程。这个理解能帮你判断什么时候应该信任DIODE的标注什么时候它的标注也可能出错。3.1 激光扫描仪的工作原理FARO Focus S350这类地面激光扫描仪原理是向场景发射激光束测量光束遇到物体表面后返回的时间差或相位差从而得到每个扫描点的距离。它在扫描时会旋转得到的是极坐标形式的三维点云包含每个点的水平角、垂直角和距离再结合扫描仪自身的绝对位置就能把点云转换到相机坐标系或者世界坐标系。这个过程的优势在于距离测量是主动的不依赖环境光因此和Kinect那种容易受环境干扰的方案比它对黑色、发光物体的测量稳定性高很多。激光扫描仪的角分辨率虽然不如相机像素那么高但通过多站拼接点云密度足以在投影后填满大部分图像区域。3.2 投影到虚拟相机平面的流程得到场景点云后需要一个相机模型把它们映射到像素坐标。DIODE的惯常做法是先架设一台真实相机在场景中拍摄RGB照片同时记录下相机的内参和外参再把点云根据外参变换到相机坐标系最后用针孔相机模型投影到图像平面。这样每个三维点都有一个对应的二维像素坐标通过插值和遮挡分析就能得到每个像素的深度值。实际操作中有些像素会被多个三维点覆盖比如物体边缘有些像素则完全没有任何点落在上面。这时候就需要做深度缝合depth inpainting和遮挡处理。DIODE官方管道的做法比较严谨对无值区域直接置为无效并记录在depth_mask里不会强行补进去填一个猜测值。这一点也是它在评测时比你拿到的原始点云自己投影更稳定可靠的原因。3.3 法线计算的两种路线法线图可以通过两种方式生成。第一种是从深度图求梯度再叉乘即把深度看成曲面z(x,y)对x和y各求偏导得到两个切向量再取叉积归一化。这种算法规整、效率高但在深度不连续和物体边缘处容易产生法线翻转或者“雨刷效应”。第二种是直接在三维点云上做局部平面拟合对每个点选取邻域点集用PCA的最小特征向量估计法线方向。这样得到的法线在几何上更稳健对噪声没有那么敏感。DIODE官方采用第二种思路因为它的上游数据本身就是点云直接在点云几何上估计法线是水到渠成的事而且能保证深度和法线来自同一个三维几何源。我对比过从它的深度图反推法线和官方给的法线图在内点区域基本一致只有在深度跳变的极少数像素上会有轻微不一致这已经很能说明数据质量了。3.4 为什么DIODE能保证深度与法线一致在多模态数据集里深度图和法线图“互相矛盾”是经常被忽略却非常致命的问题。比如有些数据集深度来自深度传感器法线却是用另一个网络预测出来的两个标注源不一致模型训练的时候就会在两个任务之间互相拉拽。DIODE的做法是从同一个点云出发深度和法线只是对这个点云的两种数学表示因此它们在数学上是严格对应的。这意味着你可以把DIODE当做一个天然的“一致性自监督”测试平台。比如你可以设计一个模型让它的法线输出和从深度输出推导出的法线做一致性损失来增强深度结果在几何上的合理性。这样一个思路在NYUv2上很难严格实现因为它的深度和法线标注本身就不同源而在DIODE上就有很干净的理论支持。4. 实操过程加载DIODE并快速验证你的深度模型理论聊完进入真正动手的环节。下面我给出一个经过验证的流程从下载、解压到最后在自己的模型上跑出zero-shot指标每一步都标记了容易出问题的地方。4.1 下载与目录准备拿到下载链接后先把tarball按场景分开解压比如建一个如下目录diode/ val/ indoor/ scene1/ png/ depth.npy depth_mask.npy normal.npy intrinsics.npy outdoor/ scene2/ png/ depth.npy depth_mask.npy normal.npy intrinsics.npy如果你打算统一做评测我建议先把所有验证集的样本路径整理成一个json或者csv文件里面记录每张图像对应的深度、掩码、法线路径和场景类型后面写测试循环会方便很多。4.2 读取深度图和法线图的代码DIODE的npy文件直接可以用numpy读取数据格式是float32。下面是我常用的一个加载函数import numpy as np import cv2 def load_diode_sample(scene_dir): depth np.load(f{scene_dir}/depth.npy) # (768, 1024) float32, 单位米 depth_mask np.load(f{scene_dir}/depth_mask.npy) # (768, 1024) bool, True表示有效 normal np.load(f{scene_dir}/normal.npy) # (768, 1024, 3) float32, 法线三通道 intrinsics np.load(f{scene_dir}/intrinsics.npy) # (3, 3) 相机内参 image cv2.imread(f{scene_dir}/png/{...}.png) # RGB图 image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) return image, depth, depth_mask, normal, intrinsics要注意的是很多模型训练时要求输入是0到1之间的浮点图而DIODE的RGB图是8位无符号整数需要除以255。另一个常见坑是深度值直接存放的是到相机平面的距离不是到相机光心的欧氏距离。对于针孔相机模型两者在中心区域差异不大但在图像边缘有明显差别评测时最好用深度平面距离而不是直接拿深度值做反投影。4.3 图像到深度图的预处理细节在把图像喂进模型之前通常需要把分辨率缩放到模型输入尺寸比如320x240或者其他。我倍加提醒的一点缩放深度图时不能直接插值尤其不能把无效像素的值插成有效值。正确的做法是先对depth_mask做resize最近邻采样保证还是二值的再在被mask住的地方对深度图做有效区域插值或者干脆在后续损失计算时忽略这些像素。我自己的做法是写一个prepare_pair函数def prepare_pair(image, depth, depth_mask, target_size(320, 240)): img cv2.resize(image, target_size, interpolationcv2.INTER_LINEAR) img img.astype(np.float32) / 255.0 mask cv2.resize(depth_mask.astype(np.uint8), target_size, interpolationcv2.INTER_NEAREST).astype(bool) d cv2.resize(depth, target_size, interpolationcv2.INTER_NEAREST) # 对mask外的深度值清零避免后续误用 d[~mask] 0.0 return img, d, mask4.4 在自己的模型上做zero-shot测试的步骤假如你有一个在NYUv2或者自己数据上训练好的深度估计模型想看看它在DIODE上表现如何推荐按下面的流程走一遍把模型切到eval模式关闭BN的更新和dropout。按上文所述预处理RGB到模型输入尺寸不需要做归一化之外的数据增强。前向得到深度输出恢复尺寸到768x1024。计算指标时只统计depth_mask为True的像素。分别统计室内和室外的RMSE和相对误差一般用Abs Rel即|pred-gt|/gt。一个非常推荐的额外操作是把预测深度和官方深度图做成可视化对比图左边RGB、中间预测、右边GT。这样你能直观看到一个深度学习模型在“曾经没见过的高质量激光点云形成的数据”上到底是不是真的理解了三维结构。这个可视化对写论文也是很强的说服材料。5. 常见问题与排查技巧实录DIODE虽然标注质量高但毕竟是从完整点云管线走过来的复杂数据集我在实际使用中遇到了不少问题这里集中整理一下。5.1 下载申请迟迟不通过很多人第一天申请第二天就急着问怎么还没收到下载链接。实际上申请处理不是全自动的得等管理员审核一般1到3个工作日都算正常。如果你需要快速拿到数据做实验建议在邮件或申请表的“用途描述”里写得具体一点比如说明“用深度估计模型的跨域评测”不要只写个“研究使用”这样更容易被放行。5.2 深度图全黑或者值域异常如果你用某些可视化库直接以8位图显示depth.npy会觉得整张图几乎全黑。这是因为深度值的范围不是0到255而是以米为单位的浮点数室内可能到10米甚至更大直接显示自然全黑。建议先将深度值通过最小最大归一化缩放到0到1再进行可视化或者使用matplotlib的imshow(depth, cmapjet)来自动拉伸色阶。如果深度值有大面积的负数或者零可能是读取时没有应用depth_mask或者加载时误把npy当成了PNG。记住官方提供的深度是浮点npy不是PNG不要用图像库直接读。5.3 法线方向不一致有些法线图观察时看起来“脏”但实际是观察视角造成的。法线三通道的取值范围通常在-1到1之间而8位图像的范围是0到255可视化时需要做(normal 1) / 2的映射。另外由于相机坐标系和世界坐标系的Z轴定义差异法线可能整体上有翻转但与深度图的相对关系不会变。如果发现法线图在物体边缘有细碎噪声这不一定是你代码的问题很可能是投影到图像平面时多个点云的遮挡边缘导致的。在训练时用法线损失建议在边缘区域降低权重避免高频噪声主导梯度。5.4 模型在DIODE上指标比NYUv2差很多这是非常常见的现象不代表你的模型不行更多是数据分布差异。NYUv2的深度范围被掐头去尾控制在10米内而DIODE的室外场景深度可能远大于10米导致模型对远距离的预测能力不足。如果你关心相对误差Abs Rel建议对深度范围做一个截断再比较比如只统计0到10米范围内的像素。另外DIODE的有效深度覆盖率远超NYUv2模型之前可以靠“输出背景均值”的地方现在也必须真正预测所以绝对误差变大是合理现象。5.5 深度尺度与单位问题我遇到过不止一次因为单位问题算错指标的。DIODE的深度单位是米而有些数据集的深度存储在16位PNG里需要除以1000或者5000才是米。如果你在DIODE上用旧代码测试一定要先确认预处理是不是带了尺度缩放系数。最直接的办法是随机挑一个像素打印预测深度和真实深度值再对着RGB图看看这个距离合不合理。现象可能原因解决办法下载链接没收到申请审核延迟等1-3个工作日必要时写清用途再申请深度图全黑值域范围大8位显示溢出了用归一化或cmap拉伸色阶显示法线图发灰未将-1到1映射到0到255用(normal1)/2再显示指标远差于NYUv2深度范围与覆盖率不一致按0-10米截断统计或分别统计室内外深度单位为mm旧代码预处理器未适配检查深度值大小确认以米为单位6. 扩展应用DIODE能做什么不能做什么数据集本身不会替你解决一切问题关键在于清楚它的能力边界。DIODE在几个方向上特别有价值但也有一些地方它并不适合。6.1 适合的任务类型最经典的用法是作为深度估计和法线估计的联合评测基准。你可以在NYUv2、ScanNet上训练在DIODE的验证集上做zero-shot测试检验模型的跨数据集泛化能力。因为DIODE同时覆盖室内外你可以分别报告室内和室外的误差这对那些声称“泛化到通用场景”的论文来说是一个很有力的检验。另外一个值得尝试的方向是用DIODE的深度和法线一致性做多任务学习的自监督约束。我之前训练过一个双头模型一个头输出深度另一个输出法线然后在同一个3D点云的约束下让两个头互相校验结果发现不仅法线指标变好了深度在边缘上的锐利度也有提升。DIODE的天然一致性让这种几何约束成立得更干净比在其他数据集上硬凑两个head要合理得多。6.2 不适合直接用的情况DIODE的规模不大训练集只有136张想靠它从头训练一个深度网络是完全不够的。它更适合做评测和fine-tune不太适合做大规模预训练。另外它的RGB图像是扫描场景时同步拍摄的图像风格偏向自然光照不包含极端天气、黑夜、强动态目标等条件。如果你要做自动驾驶场景下的动态物体深度估计DIODE不能替代KITTI或者nuScenes它的定位更偏静态场景几何理解。6.3 后续扩展思路我在实际使用中觉得DIODE还有一个被低估的用途是做“深度归一化”和“尺度对齐”的基准。很多跨传感器深度模型需要一个标准尺度校准器DIODE的深度值有严格的米制定义可以作为尺度对齐的参考标准。再往后你还可以把DIODE的室外点云用做NeRF或者3D重建的辅助监督不过需要自己写点云加载和渲染的管线官方不提供这部分现成代码。7. 我在实际使用中的几点私人经验说句实在话第一次拿到DIODE的时候我还以为它跟其他RGB-D数据集一样下载下来随便写个dataloader就能跑通。结果真正用起来才发现它的npy格式、掩码逻辑、室内外分布、深度单位每个环节都值得你多看一眼。我个人的体会是DIODE最大的价值不在训练而在“照妖镜”功能。很多模型在自己数据上指标好看得不得了一旦放到DIODE上就露馅——因为DIODE的深度是激光扫描仪测出来的覆盖率极高你没法靠“忽略无效像素”来投机。我在评测自己的单目深度模型时把DIODE验证集当做一个必备的泛化测试集只要在DIODE室内和室外两组指标上没有明显掉点我才敢把模型放到实际项目里。最后再分享一个小技巧如果你在写论文或者做开源模型的技术报告用DIODE做可视化对比时记得把depth_mask叠加到预测深度图上一并显示。这样审稿人能一眼看出你的模型在哪些像素上真的预测了、哪些像素被忽略了信息量比纯指标大得多。另外DIODE官网还提供了场景级的RGB和点云预览你可以先浏览一下数据长什么样再决定哪些子场景适合作为你论文里的展示样例。这套数据集值得花时间摸熟它会让你的深度实验在真实几何质量上站稳脚跟。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门