三维信息保存格式

数据类型 本质 维度 典型用途
深度图 2D图像,每个像素存距离值 2D网格 单目/双目深度估计、RGB-D感知
PLY点云 3D点集合,存(x,y,z)及属性 无序3D点 3D重建、SLAM、三维检测
HDF5 容器格式,可存储任意数据 灵活 大规模数据集、多模态数据存储

实际案例对比

格式 开发者 本质 压缩 精度 典型用途
NPY NumPy 二进制数组 任意 Python单数组存储
NPZ NumPy ZIP压缩包 任意 Python多数组存储
PFM 学术界 浮点图像 32位浮点 深度图/视差图标准
PNG PNG Group 位图图像 无损 8-16位整型 RGB/深度图通用
PLY Stanford 3D网格/点云 可选 32位浮点 3D模型存储
HDF5 HDF Group 科学数据容器 任意 大规模多模态数据
格式 文件大小 保存时间 加载时间 精度损失 跨语言
NPY 8.3 MB 0.02s 0.01s
NPZ 4.1 MB 0.15s 0.12s
PFM 8.3 MB 0.03s 0.02s
PNG (16-bit) 1.2 MB 0.08s 0.05s ±0.15mm
PNG (8-bit) 0.6 MB 0.05s 0.03s ±39mm
HDF5 3.2 MB 0.25s 0.18s
PLY 24 MB 0.40s 0.35s

ScanNet 数据集为例(230万帧RGB-D + 3D重建):

数据 格式 存储方式 总大小
深度图 PNG 每帧单独文件 ~50GB
RGB图 JPG 每帧单独文件 ~200GB
相机位姿 TXT 每场景一个文件 ~10MB
3D重建 PLY 每场景一个文件 ~30GB
如果用HDF5 H5 每场景一个H5文件 ~150GB(压缩后)

HDF5(Hierarchical Data Format version 5)

定义:自描述的容器格式,可存储任意结构化数据,类似"文件系统中的文件系统"。

特点

  • 可同时存储图像、点云、标签、元数据
  • 支持分块存储、压缩、并行I/O
  • 支持随机访问,无需加载整个文件

优势

  • 多模态一体:深度图、RGB、点云、标注可存在同一个文件
  • 高效压缩:内置压缩算法,节省存储空间
  • 支持大规模数据:可处理TB级数据集
  • 跨平台/跨语言:Python、C++、MATLAB、Julia都支持

劣势

  • 需要学习API(h5pyPyTables
  • 不能直接可视化,需要提取数据
  • 对于小数据集,过度设计

多模态数据存入HDF5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import h5py
import numpy as np
import cv2

# 创建HDF5文件
with h5py.File('scene_001.h5', 'w') as f:
# 存储RGB图像
rgb = cv2.imread('rgb.png')
f.create_dataset('rgb', data=rgb, compression='gzip', compression_opts=4)

# 存储深度图
depth = cv2.imread('depth.png', cv2.IMREAD_UNCHANGED)
f.create_dataset('depth', data=depth, compression='gzip')

# 存储点云
points = np.load('points.npy') # (N, 3)
f.create_dataset('pointcloud', data=points, compression='gzip')

# 存储标签
labels = np.load('labels.npy')
f.create_dataset('labels', data=labels)

# 存储元数据(属性)
f.attrs['fx'] = 525.0
f.attrs['fy'] = 525.0
f.attrs['cx'] = 319.5
f.attrs['cy'] = 239.5
f.attrs['num_points'] = points.shape[0]

# 读取时只需加载需要的部分
with h5py.File('scene_001.h5', 'r') as f:
depth = f['depth'][:] # 只读深度图,点云不加载
print(f.attrs['fx']) # 读取元数据

PFM (Portable Float Map)

PFM (Portable Float Map) 是一种简单的、未压缩的浮点图像格式,支持单通道(灰度)或多通道(RGB),每个像素以32位浮点数存储,无压缩,文件较大。

PFM支持负值,可以表示深度图中常见的无效区域(用负数标记),而PNG/TIFF无法直接存储负数。

文件结构

1
2
3
4
PF
512 512 # 宽 高
-1.000000 # 缩放因子(负号表示大端序)
[浮点数据...] # 512×512 个 float32 值

读取和存入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def read_pfm(filename):
with open(filename, 'rb') as f:
header = f.readline().decode().strip()
if header == 'PF':
channels = 3
elif header == 'PF':
channels = 1
else:
raise ValueError('Not PFM file')

dims = f.readline().decode().strip().split()
width, height = int(dims[0]), int(dims[1])
scale = float(f.readline().decode().strip())

# 读取数据
data = np.fromfile(f, dtype='<f' if scale < 0 else '>f')
data = data.reshape((height, width, channels)) if channels > 1 else data.reshape((height, width))
data = data[::-1, :] # PFM存储是从底部开始
return data

def save_pfm(filename, data):
with open(filename, 'wb') as f:
f.write(b'PF\n')
f.write(f'{data.shape[1]} {data.shape[0]}\n'.encode())
f.write(b'-1.0\n') # 小端序
f.write(data[::-1, :].tobytes())

save_pfm('depth.pfm', depth)

NPZ 格式

多个NPY文件的ZIP压缩包。

多数组打包:一个文件存多个相关数组

内置压缩:savez_compressed自动压缩

按需加载:支持懒加载(mmap模式)

Python原生:与NPY一样简单

劣势

  • ❌ 同NPY的跨语言问题
  • ❌ 压缩/解压有CPU开销
  • ❌ 不适合超大文件(>4GB需要特殊处理)