数据集计算机视觉3D视觉【免费下载链接】ScanNet项目地址https://gitcode.com/gh_mirrors/sc/ScanNet点击查看免费下载在 ScanNet 数据集中每个扫描序列目录scene%04d_%02d都包含一个scanId.sens文件它以压缩二进制形式保存了全部彩色帧、深度帧、逐帧相机位姿、IMU 数据以及相机内参/外参是后续重建、标注投影、评测等任务的第一手数据来源。本文基于 SensReader/README.md 逐节展开结合 SensReader/c/src/sensorData.h、SensReader/python/SensorData.py 等源码讲清.sens的二进制布局、压缩约定、位姿无效帧处理以及 C 工具链与 Python 导出器的具体构建和运行方法帮助你在拿到 ScanNet 数据后能够独立解析任意一帧的颜色/深度图像与 camera-to-world 变换。1. .sens 文件在 ScanNet 数据组织中的位置仓库根目录 README.md 的 Data Organization 一节给出了每个扫描序列的目录结构其中第一个文件就是scanId |-- scanId.sens RGB-D sensor stream containing color frames, depth frames, camera poses and other data |-- scanId_vh_clean.ply High quality reconstructed mesh ...README 明确指出.sens是 Compressed binary format with per-frame color, depth, camera pose and other data解析代码见 ScanNet C Toolkit即本模块 SensReader另有一个 very basic python data exporter 位于 SensReader/python。在整条数据管线中.sens文件的上游是 Converter把 ScannerApp iPad 采集的.h264、.depth、.txt、.imu原始数据转换为.sens下游则是 Calibrate对未标定的.sens做色彩/深度标定并输出标定后的.sens、Alignment将扫描对齐到 z-up 坐标系以及 AnnotationTools 中把 2D 标注投影回帧序列的工具例如 AnnotationTools/Filter2dAnnotations/Filter2dAnnotations.cpp 中直接构造SensorData sd(scanNetPath name / name .sens)读取帧数据。因此理解.sens格式是读懂 ScanNet 原始数据的关键一步。2. SensorData 结构体文件的逻辑视图SensReader/README.md 给出的核心定义是SensorData结构体完整实现见 SensReader/c/src/sensorData.hstruct SensorData { unsigned int m_versionNumber; std::string m_sensorName; CalibrationData m_calibrationColor; //4x4 intrinsic matrix CalibrationData m_calibrationDepth; //4x4 intrinsic matrix COMPRESSION_TYPE_COLOR m_colorCompressionType; //scannet color frames are typically jpeg encoded COMPRESSION_TYPE_DEPTH m_depthCompressionType; //scannet depth frames are typically zLib encoded unsigned int m_colorWidth; unsigned int m_colorHeight; unsigned int m_depthWidth; unsigned int m_depthHeight; float m_depthShift; //conversion from float[m] to ushort (typically 1000.0f) std::vectorRGBDFrame m_frames; // Main data (contains timestamps and rigid transforms) std::vectorIMUFrame m_IMUFrames; }各成员的含义与源码事实如下m_versionNumber / m_sensorName文件版本号与传感器名称。C 端宏M_SENSOR_DATA_VERSION定义为 4sensorData.h#L839-L841并注释说明version 3 was missing the IMUFrame vector、前三个版本[0,1,2]保留给旧的.sensor文件Python 端同样硬编码self.version 4并在读取时assertSensorData.py#L48-L56。m_sensorName的候选值在SensorNames中列出StructureSensor、Kinect.V1、Kinect.V2、PrimeSense Carmine、Asus Xtion ProsensorData.h#L1653-L1663这与 ScanNet 采集设备iPad Structure.io见 ScannerApp/README.md 与根 README 的 ScanNet Scanner iPad App 一节相对应。m_calibrationColor / m_calibrationDepthREADME 注释写作 4x4 intrinsic matrix但从CalibrationData的实现看每个CalibrationData实际包含两块矩阵m_intrinsic注释为 Camera-to-Proj matrix与m_extrinsicit should be the mapping to base frame in a multi-view setup (typically its depth to color; and the color extrinsic is the identity)sensorData.h#L285-L344。也就是说文件中颜色与深度通道各自存有一对 4x4 矩阵内参 外参Python 导出器也正是把intrinsic_color、extrinsic_color、intrinsic_depth、extrinsic_depth四块矩阵都写出来的SensorData.py#L59-L62、SensorData.py#L118-L125。makeIntrinsicMatrix(fx, fy, mx, my)静态方法给出了标准针孔内参的构造形式sensorData.h#L303-L310。m_colorCompressionType / m_depthCompressionType压缩方式枚举ScanNet 的彩色帧通常为 JPEG深度帧通常为 zLib详见第 4 节。m_colorWidth / m_colorHeight / m_depthWidth / m_depthHeight两个通道的分辨率注意两者可以不同例如 Structure.io 彩色与深度分辨率不一致。m_depthShiftfloat 型深度值与ushort之间的换算系数通常取1000.0f。ushort是量化后的存储格式换算回米制时除以该系数见第 4.3 节computeDepthImage的实现。m_frames / m_IMUFrames主数据。m_frames逐帧包含位姿与时间戳m_IMUFrames为角速度、加速度等惯性数据。3. 二进制布局逐字段解析.sens是纯小端二进制流。C 端loadFromFile/writeHeaderToFilesensorData.h#L1058-L1109、sensorData.h#L1250-L1290与 Python 端SensorData.loadSensorData.py#L53-L75按同一顺序读写字段交叉比对两者可以得到一份可靠的字段级布局表文件头header字段类型大小说明m_versionNumberuint324B当前为 4传感器名长度uint648B紧随其后是strlen字节的m_sensorName颜色内参16 ×float3264Bm_calibrationColor.m_intrinsic颜色外参16 ×float3264Bm_calibrationColor.m_extrinsic深度内参16 ×float3264Bm_calibrationDepth.m_intrinsic深度外参16 ×float3264Bm_calibrationDepth.m_extrinsicm_colorCompressionTypeint324B见第 4 节枚举m_depthCompressionTypeint324B见第 4 节枚举m_colorWidth/Height、m_depthWidth/Height4 ×uint3216B分辨率m_depthShiftfloat324B深度量化系数RGBDFrame 段先写入uint64帧数随后每帧按RGBDFrame::saveToFilesensorData.h#L733-L741的顺序存放字段类型大小说明m_cameraToWorld16 ×float3264Bcamera-to-world 4x4 变换行优先扁平化m_timeStampColoruint648B彩色帧时间戳约定为微秒m_timeStampDepthuint648B深度帧时间戳约定为微秒m_colorSizeBytesuint648B压缩后彩色数据字节数m_depthSizeBytesuint648B压缩后深度数据字节数彩色数据m_colorSizeBytes字节按m_colorCompressionType编码深度数据m_depthSizeBytes字节按m_depthCompressionType编码IMUFrame 段先写入uint64帧数随后每个IMUFramesensorData.h#L786-L833按saveToFile顺序存放 5 个vec3drotationRate角速度原始值、acceleration三轴加速度原始值、magneticField磁力计原始值、attitude推断的 roll/pitch/yaw、gravity推断的重力方向共 5 × 3 ×float64 120B加一个uint64时间戳约定微秒。注意C 的saveToImages并不会导出 IMU 数据会打印 warning sensor has imu frames; but writing is not implemented hereSensReader/c/README.txt 也明确说明 IMU data is not saved out (its stored in m_IMUFrames)若需要 IMU应直接从m_IMUFrames读取或使用findClosestIMUFrame见第 5.3 节。由于帧数据带变长 payload解析器无法随机访问只能顺序读取——C 端的loadFromFile就是先读帧数、再循环loadFromFile每一帧sensorData.h#L1275-L1290Python 端同样顺序frame.load(f)直到读完。4. 压缩类型与深度换算约定COMPRESSION_TYPE_COLOR与COMPRESSION_TYPE_DEPTH枚举定义在 sensorData.h#L346-L357Python 端用等值的字典表示SensorData.py#L9-L10编码彩色深度-1TYPE_COLOR_UNKNOWNTYPE_DEPTH_UNKNOWN0TYPE_RAW原始 RGBTYPE_RAW_USHORT原始 ushort1TYPE_PNGTYPE_ZLIB_USHORTzlib 压缩的 ushort2TYPE_JPEGTYPE_OCCI_USHORTStructure.io uplink 压缩README 中的注释与实现对 ScanNet 数据给出的事实是颜色帧typically jpeg encoded深度帧typically zLib encoded。从源码结构看解码路径如下彩色非 RAW 类型走decompressColorAlloc_stb用内置的 stb_imagestbi_load_from_memory头文件通过STB_IMAGE_IMPLEMENTATION内嵌实现实现头见 SensReader/c/src/sensorData/stb_image.h直接解码 JPEG/PNG 内存数据为 RGB若编译时定义_USE_UPLINK_COMPRESSIONWindows 路径则改用 Structure.io 的 uplink 编解码器sensorData.h#L600-L638。_USE_UPLINK_COMPRESSION仅对 Win32 生效Linux 下会自动取消定义sensorData.h#L61-L71。深度TYPE_ZLIB_USHORT用stbi_zlib_decode_malloc解出 ushort 数组sensorData.h#L703-L709TYPE_OCCI_USHORT需要 uplink 的decode shift2depthTYPE_RAW_USHORT直接memcpysensorData.h#L724-L730。Python 端只实现了zlib_ushortzlib.decompress与 JPEGimageio.imread其余类型直接raiseSensorData.py#L24-L43。压缩侧用于自行写出.senscompressDepth对 zLib 类型调用stbi_zlib_compress且固定quality 8compressColor的 PNG/JPEG 路径在不开启_USE_UPLINK_COMPRESSION时会抛异常sensorData.h#L648-L698——即默认配置下该头文件完整支持读写 JPEG则依赖 uplink。4.1 深度值 → 米.sens中深度以ushort存储m_depthShift通常是1000.0f。C 头文件中规范的还原写法出现在computeDepthImage需_HAS_MLIBdepth[i] 0标记为无效否则d (float)depth[i] / m_depthShiftsensorData.h#L968-L978saveToPointCloud同样用d depth[i] / m_depthShiftsensorData.h#L1576。SensReader/c/src/main.cpp 的演示函数processFrame则按depth_in_meters sd.m_depthShift * depthData[i]书写与上述两处还原公式在乘除方向上不一致属于演示代码的笔误倾向实际换算应以除以m_depthShift为准这与 README 注释 conversion from float[m] to ushort (typically 1000.0f) 的语义自洽ushort 米 × 1000。4.2 无效位姿的约定SensReader/c/README.txt 的 Notes 部分说明invalid poses are marked with -inf values. They are result of lost tracking. Subsequent poses can be trusted, as they are result of global alignment in BundleFusion [Dai et al.]。源码中可以看到这一约定的实现痕迹RGBDFrame默认构造即把m_cameraToWorld置为全-infsensorData.h#L377-L385free()时也复位为-inf以便检测未初始化的帧sensorData.h#L459-L463saveToPointCloud在遇到transform[0] -inf || transform[0] 0时退回单位阵sensorData.h#L1572applyTransform对整条轨迹施加全局变换遇到-inf位姿直接跳过以避免产生 NaNsensorData.h#L1048-L1054。因此任何消费.sens位姿的代码例如投影 2D 标注、生成训练数据都应当先做-inf检测丢弃或跳过跟踪丢失的帧。5. C 工具链SensReader/c5.1 代码组织SensReader/c 目录非常精简核心只有一个头文件 一个演示入口SensReader/c/src/sensorData.hml::SensorData全部实现约 1960 行包含自包含的轻量线性代数类型vec3uc、vec3d、mat4f等sensorData.h#L122-L236、CalibrationData、RGBDFrame、IMUFrame、文件读写、图像导出、IMU 查询stb_image / stb_image_write 以单头文件形式内嵌编译sensorData.h#L51-L59。头文件顶部有两个可选开关_HAS_MLIB链接 mLib 后可用DepthImage32、PointCloudf等类型解锁computeDepthImage、computeColorImage、saveToPointCloud、applyTransform等函数与_USE_UPLINK_COMPRESSIONsensorData.h#L10-L11未定义_HAS_MLIB时头文件自带一套最小替身类型保证默认情况下单文件即可编译。SensReader/c/src/main.cpp命令行演示程序读取.sens并调用sd.saveToImages(outDir)。SensReader/c/Makefile 与 SensReader/c/sens.sln、sens.vcxproj分别对应 Linux 与 Windows 构建。5.2 构建与运行Linux 下按 SensReader/c/MakefileCXX g #CXX clang FLAGS-stdc11 -g main: $(CXX) $(FLAGS) -o sens src/main.cppWindows 下打开sens.slnVS2013 工具集x64。SensReader/c/README.txt 给出的测试环境为Windows 10 VS2013Ubuntu 14.04.1 下 g 与 clang。运行方式与 main.cpp#L28-L45 的 argv 解析一致./sens sensFile.sens outputDir第二个参数缺省为./out/两个参数都缺省时程序会交互式提示输入文件名。程序先打印SensorData的摘要版本、分辨率、m_depthShift、帧数等operator实现见 sensorData.h#L1941-L1955然后调用saveToImages导出全部帧。5.3 常用 API 与逐帧解码README 给出的最小使用示例与main.cpp中processFrame的演示互相印证// example get color frame, depth frame, pose (camera to world) SensorData sd(sensfile.sens); unsigned int frame 0; vec3uc* color sd.decompressColorAlloc(frame); // note: must be freed after use unsigned short* depth sd.decompressDepthAlloc(frame); // note: must be freed after use const mat4f cameraToWorld sd.m_frames[frame].getCameraToWorld(); std::free(color); std::free(depth); // if using mlib, can save a frame to a point cloud with: sd.saveToPointCloud(frame std::to_string(frame) .ply, frame);需要注意的三个事实decompressColorAlloc/decompressDepthAlloc返回的是malloc出来的堆内存用完后必须std::free头文件注释 needs std::free afterwards!sensorData.h#L928-L946越界索引会抛MLIB_EXCEPTION(out of bounds)。sd.m_frames[frameIdx].getCameraToWorld()直接得到该帧的 camera-to-world 4x4 矩阵mat4f行优先matrix[16]/matrix2[4][4]/_m00..._m33三种访问方式sensorData.h#L222-L235使用前应检查是否为-inf见 4.2 节。IMU 匹配用sd.findClosestIMUFrame(frameIdx, basedOnRGB true)以彩色或深度时间戳为 key 在按时间排序的m_IMUFrames上做二分查找返回时间上最接近的 IMU 帧sensorData.h#L999-L1044。saveToPointCloud需_HAS_MLIBsensorData.h#L1564-L1602展示了从.sens到带色点云的标准做法对每个非零深度像素先用深度内参的逆矩阵intrinsicInv反投影到深度相机坐标再经cameraToWorld变换到世界系得到点颜色则经 深度外参depth→color 基准系→ 颜色内参 投影回彩色图像采样越界像素置透明。5.4 saveToImages 的输出内容saveToImagessensorData.h#L1380-L1466导出 7-scenes 风格的目录结构文件名由StringCounter生成6 位零填充如frame-000000_info.txt元信息版本、传感器名、分辨率、m_depthShift、四块标定矩阵的 16 个元素、帧数frame-000000.color.png或.color.jpg按m_colorCompressionType选择后缀JPEG/PNG 数据直接落盘RAW 数据会被重新编码为 PNGframe-000000.depth.pgm二进制 PGMP516-bit 值域 65535写入前逐像素交换字节序以符合 PGM 的大端要求saveAsPGMsensorData.h#L1342-L1375frame-000000.pose.txtcamera-to-world 4x4 文本矩阵savePoseFilesensorData.h#L1706-L1714。SensReader/c/README.txt 还有一条实操建议keep the sens files as they are a nice representation——.sens本身就是紧凑、自描述的好载体导出图像仅作调试用途。6. Python 数据导出器SensReader/pythonSensReader/python/README.md 说明该工具Developed and tested with python 2.7用法python reader.py --filename [.sens file to export data from] --output_path [output directory to export data to] Options: --export_depth_images: export all depth frames as 16-bit pngs (depth shift 1000) --export_color_images: export all color frames as 8-bit rgb jpgs --export_poses: export all camera poses (4x4 matrix, camera to world) --export_intrinsics: export camera intrinsics (4x4 matrix)reader.py 用argparse实现了上述四个开关默认全部关闭set_defaults(... False)reader.py#L7-L15分别导出到output_path下的depth/、color/、pose/、intrinsic/子目录。实现上SensorData.py 用struct逐字节解析文件与第 3 节的布局表一一对应深度导出export_depth_imageszlib.decompress后np.fromstring(..., dtypenp.uint16)按(depth_height, depth_width)reshape可选cv2.resizeINTER_NEAREST最终以bitdepth16的 PNG 写出使用pypng的png.Writer支持frame_skip隔帧导出SensorData.py#L78-L91。彩色导出export_color_imagesimageio.imread(self.color_data)解码 JPEG 字节流后imwrite为.jpgSensorData.py#L93-L101。位姿导出export_poses每帧camera_to_world以 4 行 ×np.savetxt的%f格式写成frame.txtSensorData.py#L110-L115。标定导出export_intrinsics写出intrinsic_color.txt、extrinsic_color.txt、intrinsic_depth.txt、extrinsic_depth.txt四个 4x4 文本矩阵SensorData.py#L118-L125。使用限制需要特别注意脚本是 Python 2 风格print语句、np.fromstringREADME 声明仅在 Python 2.7 下开发测试在 Python 3 环境直接运行会报语法错误需自行改写或改用 Python 2 环境。它只支持 ScanNet 的典型编码组合JPEG 彩色 zlib 深度遇到raw/occi_ushort类型会直接抛异常SensorData.py#L24-L39也不导出 IMU 数据。它把整个文件一次性读入内存self.frames保存全部帧的原始压缩字节适合单场景文件不适合超大文件的流式处理——流式/多线程需求请看第 5 节 C 工具。7. 进阶流式读写与轨迹处理sensorData.h中还有几组面向整段扫描流式处理的类README 未提及但从源码结构看它们是该库的完整能力面RGBDFrameCacheRead后台线程持续decompressColorAlloc/decompressDepthAlloc主线程通过getNext()顺序取已解压帧cacheSize控制缓冲深度sensorData.h#L1717-L1831——适合边解压边做重建或标注避免把全部帧铺在内存里。RGBDFrameCacheWrite与_HAS_MLIB下的LiveSensorDataWriter反向通道采集端调用writeNextAndFree把新帧交给后台线程压缩落盘LiveSensorDataWriter还会在文件头先写 0、关闭时回写真实 RGB 帧数IMU 段写 0 帧支持边采边写sensorData.h#L1111-L1246、sensorData.h#L1833-L1935。append(const SensorData)把另一个SensorData的帧追加进来要求分辨率/压缩类型一致可推断用于分段扫描的拼接sensorData.h#L1606-L1624。applyTransform(mat4f)对整条轨迹左乘统一变换跳过-inf帧配合 Alignment 一类的全局对齐结果更新.sens中的位姿。8. 小结选择哪条路线解析 .sens场景推荐工具说明完整解析 逐帧解码 点云导出SensReader/csensorData.hmain.cpp支持全部压缩类型内存管理精细./sens file.sens outDir一键导出帧与元信息快速批量导出 16-bit 深度 PNG / 位姿 / 内参SensReader/pythonreader.py四个布尔开关按需导出仅限 JPEGzlib 组合与 Python 2.7只取标定参数二者皆可C 用m_calibrationColor/DepthPython 用--export_intrinsics得到 4 个 txt 矩阵IMU 数据必须走 Cm_IMUFrames/findClosestIMUFrame两套导出器都不会写 IMU 到磁盘无论选择哪条路线都有三个通用注意点版本必须为 4位姿为-inf的帧是跟踪丢失帧需过滤后再使用深度ushort还原为米要除以m_depthShift通常为 1000.0。掌握这些约定后scanId.sens中的每一帧颜色、深度、位姿与 IMU 数据都可以被稳定、可复现地读取。赞分享数据集计算机视觉3D视觉【免费下载链接】ScanNet项目地址https://gitcode.com/gh_mirrors/sc/ScanNet点击查看免费下载相关推荐ScanNet 数据集详解RGB-D 室内场景数据组织、.sens/.segs.json 数据格式与配套工具链ScanNet 数据集详解RGB D 室内场景数据组织、 .sens / .segs.json 数据格式与配套工具链 ScanNet 是一个包含 250 万帧数据集计算机视觉3D视觉ScanNet Converter 详解将 ScannerApp 原始采集数据转换为 .sens 传感器流的完整流程ScanNet Converter 详解将 ScannerApp 原始采集数据转换为 .sens 传感器流的完整流程 本文以 ScanNet 仓库中的 Con数据集计算机视觉3D视觉ScanNet ScannerApp 实战指南用 Structure Sensor 采集 RGB-D 数据、五种数据格式与上传机制详解ScanNet ScannerApp 实战指南用 Structure Sensor 采集 RGB D 数据、五种数据格式与上传机制详解 本文基于 ScanNe数据集计算机视觉3D视觉创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考