三维信息保存格式

数据类型 本质 维度 典型用途
深度图 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(h5py、PyTables)
  • 不能直接可视化,需要提取数据
  • 对于小数据集,过度设计

多模态数据存入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需要特殊处理)