Files
worldmodel/plans/iphone/data_format_specification.md
T
gaojie dbcbdbb59e chore: 为所有 md 文件添加 Hugo front matter
- 处理: 74 个 .md 文件
- 跳过: 0 个(无已存在的 front matter)
- 异常: 3 个(H1 缺失,用文件名兜底)
  - plans/PRISM/.research/readmes/3d-llm.md
  - plans/PRISM/.research/readmes/openmask3d.md
  - plans/PRISM/.research/readmes/openscene.md
2026-05-20 22:42:22 +08:00

855 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "酒店场景建模项目 - 数据格式规范"
date: 2026-05-20
draft: false
tags: ["iPhone", "3D 重建", "RoomPlan", "SLAM", "IMU", "点云"]
categories: ["worldmodel"]
---
# 酒店场景建模项目 - 数据格式规范
## 📋 文档概述
本文档详细定义了酒店场景数字孪生项目中所有数据的存储格式、命名规范和交换标准,确保数据的可复用性、可扩展性和跨平台兼容性。
---
## 一、数据组织结构
### 1.1 目录树结构
```
hotel_dataset/
├── metadata.json # 全局元数据
├── calibration/ # 传感器标定
│ ├── camera_intrinsics.yaml
│ ├── lidar_camera_extrinsics.yaml
│ ├── imu_camera_extrinsics.yaml
│ └── calibration_report.pdf
├── scenes/ # 场景数据
│ ├── lobby_01/ # 大堂场景1
│ │ ├── scene_info.json # 场景元数据
│ │ ├── raw/ # 原始数据
│ │ │ ├── lidar/ # LiDAR点云
│ │ │ │ ├── 0000000.pcd
│ │ │ │ ├── 0000001.pcd
│ │ │ │ └── ...
│ │ │ ├── rgb/ # RGB图像
│ │ │ │ ├── 0000000.jpg
│ │ │ │ ├── 0000001.jpg
│ │ │ │ └── ...
│ │ │ ├── depth/ # 深度图
│ │ │ │ ├── 0000000.png # 16-bit PNG
│ │ │ │ ├── 0000001.png
│ │ │ │ └── ...
│ │ │ ├── imu/ # IMU数据
│ │ │ │ └── imu_data.csv
│ │ │ ├── polarized/ # 偏振图像(卫生间)
│ │ │ │ ├── 0deg/
│ │ │ │ ├── 45deg/
│ │ │ │ ├── 90deg/
│ │ │ │ └── 135deg/
│ │ │ └── timestamps.txt # 时间戳对齐
│ │ ├── processed/ # 处理后数据
│ │ │ ├── slam/ # SLAM结果
│ │ │ │ ├── trajectory.txt # 相机轨迹
│ │ │ │ ├── sparse_map.ply # 稀疏点云
│ │ │ │ ├── dense_map.ply # 稠密点云
│ │ │ │ └── loop_closures.json # 回环信息
│ │ │ ├── colmap/ # COLMAP输出
│ │ │ │ ├── cameras.txt
│ │ │ │ ├── images.txt
│ │ │ │ ├── points3D.txt
│ │ │ │ └── sparse/
│ │ │ ├── 3dgs/ # 3D Gaussian Splatting
│ │ │ │ ├── point_cloud.ply # 初始点云
│ │ │ │ ├── cameras.json # 相机参数
│ │ │ │ ├── cfg_args # 训练配置
│ │ │ │ ├── input.ply # 优化后高斯
│ │ │ │ └── iteration_30000/ # 检查点
│ │ │ ├── nerf/ # NeRF/Ref-NeRF
│ │ │ │ ├── transforms.json # NeRF格式位姿
│ │ │ │ ├── model.pth # 模型权重
│ │ │ │ └── config.yaml
│ │ │ ├── mesh/ # 网格模型
│ │ │ │ ├── scene.obj # 主网格
│ │ │ │ ├── scene.mtl # 材质文件
│ │ │ │ ├── textures/ # 纹理贴图
│ │ │ │ │ ├── diffuse.png
│ │ │ │ │ ├── normal.png
│ │ │ │ │ └── roughness.png
│ │ │ │ └── scene_watertight.obj # 水密网格
│ │ │ ├── semantic/ # 语义信息
│ │ │ │ ├── detections/ # 2D检测
│ │ │ │ │ ├── yolo_results.json
│ │ │ │ │ └── sam_masks/
│ │ │ │ ├── instances_3d.json # 3D实例
│ │ │ │ ├── scene_graph.json # 场景图
│ │ │ │ ├── clip_features.npy # CLIP特征
│ │ │ │ └── semantic_map.ply # 语义点云
│ │ │ └── physics/ # 物理属性
│ │ │ ├── scene.usd # USD场景
│ │ │ ├── collision_meshes/ # 碰撞网格
│ │ │ ├── articulation.json # 铰接信息
│ │ │ └── material_props.json # 材质物理属性
│ │ └── renders/ # 渲染结果
│ │ ├── novel_views/ # 新视角
│ │ ├── depth_maps/ # 深度图
│ │ └── semantic_maps/ # 语义图
│ ├── room_301/ # 客房场景
│ │ └── ...(结构同上)
│ └── bathroom_301/ # 卫生间场景
│ └── ...(结构同上)
├── annotations/ # 人工标注(可选)
│ ├── object_labels.json
│ ├── spatial_relations.json
│ └── physics_properties.json
└── benchmarks/ # 评测数据
├── test_views/ # 测试视角
├── ground_truth/ # 真值数据
└── metrics/ # 评测结果
```
### 1.2 命名规范
```yaml
场景命名:
格式: {scene_type}_{id}
示例: lobby_01, room_301, bathroom_301
scene_type:
- lobby: 大堂
- corridor: 走廊
- room: 客房
- bathroom: 卫生间
- restaurant: 餐厅
- gym: 健身房
文件命名:
时序数据: {frame_id:07d}.{ext}
示例: 0000000.jpg, 0000001.pcd
处理结果: {descriptor}_{version}.{ext}
示例: dense_map_v2.ply, scene_graph_final.json
版本控制:
格式: v{major}.{minor}.{patch}
示例: v1.0.0, v1.2.3
```
---
## 二、原始数据格式
### 2.1 点云数据(LiDAR
#### 格式:PCDPoint Cloud Data
```yaml
文件格式: ASCII 或 Binary PCD
编码: UTF-8
字段:
- x, y, z: 坐标(float32, 单位:米)
- intensity: 反射强度(uint8, 0-255
- timestamp: 时间戳(float64, Unix时间)
- ring: 激光环IDuint16, 可选)
示例文件头:
VERSION 0.7
FIELDS x y z intensity timestamp
SIZE 4 4 4 1 8
TYPE F F F U F
COUNT 1 1 1 1 1
WIDTH 65536
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 65536
DATA binary
```
**Python读取示例**
```python
import open3d as o3d
import numpy as np
def load_pcd(filepath):
"""加载PCD点云"""
pcd = o3d.io.read_point_cloud(filepath)
# 提取数据
points = np.asarray(pcd.points) # (N, 3)
# 如果有颜色
if pcd.has_colors():
colors = np.asarray(pcd.colors) # (N, 3)
# 如果有法线
if pcd.has_normals():
normals = np.asarray(pcd.normals) # (N, 3)
return pcd, points
# 保存PCD
def save_pcd(filepath, points, colors=None, normals=None):
"""保存PCD点云"""
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points)
if colors is not None:
pcd.colors = o3d.utility.Vector3dVector(colors)
if normals is not None:
pcd.normals = o3d.utility.Vector3dVector(normals)
o3d.io.write_point_cloud(filepath, pcd, write_ascii=False)
```
### 2.2 RGB图像
#### 格式:JPEG / PNG
```yaml
RGB图像:
格式: JPEG(有损压缩)
分辨率: 1920×1080 或更高
色彩空间: sRGB
质量: 95JPEG质量参数)
命名: {frame_id:07d}.jpg
高质量纹理:
格式: PNG(无损)
分辨率: 4K (3840×2160) 或更高
色彩深度: 8-bit per channel
命名: texture_{id:04d}.png
```
**EXIF元数据**(嵌入图像):
```json
{
"DateTime": "2026:05:16 10:30:45",
"Make": "Apple",
"Model": "iPhone 15 Pro Max",
"FocalLength": 24.0,
"FNumber": 1.78,
"ISO": 100,
"ExposureTime": "1/120",
"GPSLatitude": 31.2304,
"GPSLongitude": 121.4737,
"GPSAltitude": 10.5
}
```
### 2.3 深度图
#### 格式:16-bit PNG
```yaml
格式: PNG
位深度: 16-bit unsigned integer
编码: 深度值(毫米)
范围: 0-65535 mm (0-65.535米)
无效值: 0(表示无深度数据)
深度值计算:
depth_meters = pixel_value / 1000.0
示例:
pixel_value = 1500 → depth = 1.5米
pixel_value = 0 → 无效深度
```
**Python读取示例**
```python
import cv2
import numpy as np
def load_depth(filepath):
"""加载16-bit深度图"""
depth_mm = cv2.imread(filepath, cv2.IMREAD_ANYDEPTH)
depth_m = depth_mm.astype(np.float32) / 1000.0
# 标记无效深度
depth_m[depth_mm == 0] = np.nan
return depth_m
def save_depth(filepath, depth_m):
"""保存深度图"""
depth_mm = (depth_m * 1000.0).astype(np.uint16)
depth_mm[np.isnan(depth_m)] = 0
cv2.imwrite(filepath, depth_mm)
```
### 2.4 IMU数据
#### 格式:CSV
```csv
timestamp,accel_x,accel_y,accel_z,gyro_x,gyro_y,gyro_z,mag_x,mag_y,mag_z
1715875845.123456,-0.05,0.02,9.81,0.001,-0.002,0.000,25.3,10.2,-42.1
1715875845.133456,-0.04,0.03,9.80,0.002,-0.001,0.001,25.4,10.1,-42.0
...
```
**字段说明**
```yaml
timestamp: Unix时间戳(秒,float64
accel_x/y/z: 加速度(m/s², float32
gyro_x/y/z: 角速度(rad/s, float32
mag_x/y/z: 磁场强度(μT, float32, 可选)
坐标系: 右手坐标系
X:
Y:
Z:
```
### 2.5 时间戳对齐文件
#### 格式:timestamps.txt
```
# Timestamp alignment file
# Format: frame_id timestamp_unix sensor_type
# timestamp_unix: seconds since epoch (float64)
0000000 1715875845.123456 lidar
0000000 1715875845.125678 rgb
0000000 1715875845.126789 depth
0000001 1715875845.223456 lidar
0000001 1715875845.225678 rgb
0000001 1715875845.226789 depth
...
```
---
## 三、处理后数据格式
### 3.1 SLAM轨迹
#### 格式:TUM格式(trajectory.txt
```
# TUM RGB-D SLAM trajectory format
# timestamp tx ty tz qx qy qz qw
# timestamp: Unix time (float64)
# tx ty tz: translation (meters)
# qx qy qz qw: rotation quaternion
1715875845.123456 0.000 0.000 0.000 0.000 0.000 0.000 1.000
1715875845.223456 0.050 0.001 0.002 0.001 0.002 0.003 0.999
1715875845.323456 0.102 0.003 0.004 0.002 0.004 0.006 0.998
...
```
**Python读取示例**
```python
import numpy as np
from scipy.spatial.transform import Rotation
def load_trajectory(filepath):
"""加载TUM格式轨迹"""
data = np.loadtxt(filepath)
timestamps = data[:, 0]
positions = data[:, 1:4] # (N, 3)
quaternions = data[:, 4:8] # (N, 4) [qx, qy, qz, qw]
# 转换为旋转矩阵
rotations = Rotation.from_quat(quaternions).as_matrix() # (N, 3, 3)
# 构建4x4变换矩阵
poses = np.zeros((len(data), 4, 4))
poses[:, :3, :3] = rotations
poses[:, :3, 3] = positions
poses[:, 3, 3] = 1.0
return timestamps, poses
def save_trajectory(filepath, timestamps, poses):
"""保存TUM格式轨迹"""
N = len(timestamps)
data = np.zeros((N, 8))
data[:, 0] = timestamps
data[:, 1:4] = poses[:, :3, 3] # 位置
# 旋转矩阵转四元数
rotations = Rotation.from_matrix(poses[:, :3, :3])
data[:, 4:8] = rotations.as_quat() # [qx, qy, qz, qw]
np.savetxt(filepath, data, fmt='%.6f')
```
### 3.2 COLMAP格式
#### cameras.txt
```
# Camera list with one line of data per camera:
# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]
# Number of cameras: 1
1 PINHOLE 1920 1080 1066.778 1067.487 960.000 540.000
```
#### images.txt
```
# Image list with two lines of data per image:
# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME
# POINTS2D[] as (X, Y, POINT3D_ID)
# Number of images: 500
1 0.999 0.001 0.002 0.003 0.000 0.000 0.000 1 0000000.jpg
512.5 384.2 1234 678.9 456.1 5678 ...
2 0.998 0.002 0.004 0.006 0.050 0.001 0.002 1 0000001.jpg
510.3 382.7 1235 680.1 458.3 5679 ...
...
```
#### points3D.txt
```
# 3D point list with one line of data per point:
# POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX)
# Number of points: 123456
1 0.123 0.456 0.789 255 128 64 0.5 1 512 2 510 ...
2 0.234 0.567 0.890 200 150 100 0.3 1 678 3 680 ...
...
```
### 3.3 3D Gaussian Splatting格式
#### point_cloud.ply(初始点云)
```
ply
format binary_little_endian 1.0
element vertex 123456
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
property float nx
property float ny
property float nz
end_header
<binary data>
```
#### cameras.json
```json
[
{
"id": 0,
"img_name": "0000000",
"width": 1920,
"height": 1080,
"position": [0.0, 0.0, 0.0],
"rotation": [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0]
],
"fy": 1067.487,
"fx": 1066.778
},
...
]
```
#### input.ply(优化后的高斯)
```
ply
format binary_little_endian 1.0
element vertex 500000
property float x
property float y
property float z
property float nx
property float ny
property float nz
property float f_dc_0
property float f_dc_1
property float f_dc_2
property float f_rest_0
...
property float f_rest_44
property float opacity
property float scale_0
property float scale_1
property float scale_2
property float rot_0
property float rot_1
property float rot_2
property float rot_3
end_header
<binary data>
```
**字段说明**
```yaml
x, y, z: 高斯中心位置
nx, ny, nz: 法线(可选)
f_dc_*: 球谐函数DC分量(RGB
f_rest_*: 球谐函数高阶分量(45个)
opacity: 不透明度
scale_*: 缩放(3个轴)
rot_*: 旋转四元数(4个分量)
```
### 3.4 NeRF格式
#### transforms.json
```json
{
"camera_angle_x": 0.6911112070083618,
"frames": [
{
"file_path": "./images/0000000",
"rotation": 0.012566370614359171,
"transform_matrix": [
[0.999, -0.001, 0.002, 0.000],
[0.001, 0.999, -0.003, 0.000],
[-0.002, 0.003, 0.999, 0.000],
[0.0, 0.0, 0.0, 1.0]
]
},
...
]
}
```
### 3.5 网格模型(Mesh
#### OBJ格式
```
# Wavefront OBJ file
# Vertices: 123456
# Faces: 234567
mtllib scene.mtl
v 0.123 0.456 0.789
v 0.234 0.567 0.890
...
vn 0.577 0.577 0.577
vn 0.707 0.000 0.707
...
vt 0.500 0.500
vt 0.600 0.400
...
usemtl material_0
f 1/1/1 2/2/2 3/3/3
f 4/4/4 5/5/5 6/6/6
...
```
#### MTL格式(材质)
```
# Material file
newmtl material_0
Ka 0.2 0.2 0.2
Kd 0.8 0.8 0.8
Ks 0.5 0.5 0.5
Ns 96.078431
map_Kd textures/diffuse_0.png
map_Bump textures/normal_0.png
map_Ks textures/roughness_0.png
```
---
## 四、语义数据格式
### 4.1 2D检测结果(YOLO
#### yolo_results.json
```json
{
"version": "1.0",
"model": "yolov9-world",
"images": [
{
"image_id": "0000000",
"image_path": "rgb/0000000.jpg",
"width": 1920,
"height": 1080,
"detections": [
{
"detection_id": 0,
"label": "bed",
"confidence": 0.95,
"bbox": [100, 200, 800, 600],
"bbox_format": "xyxy",
"mask_rle": "...",
"clip_feature": [0.123, 0.456, ...]
},
{
"detection_id": 1,
"label": "desk",
"confidence": 0.89,
"bbox": [1000, 300, 1500, 900],
"bbox_format": "xyxy"
}
]
}
]
}
```
### 4.2 3D实例
#### instances_3d.json
```json
{
"version": "1.0",
"scene_id": "room_301",
"coordinate_system": "right_hand_z_up",
"unit": "meter",
"instances": [
{
"instance_id": "bed_001",
"label": "bed",
"category": "furniture",
"confidence": 0.95,
"centroid": [1.5, 2.0, 0.5],
"bbox_min": [0.5, 1.0, 0.0],
"bbox_max": [2.5, 3.0, 1.0],
"oriented_bbox": {
"center": [1.5, 2.0, 0.5],
"extent": [2.0, 2.0, 1.0],
"rotation": [0.0, 0.0, 0.0, 1.0]
},
"volume": 4.0,
"mesh_path": "mesh/bed_001.obj",
"point_indices": [1234, 5678, ...],
"semantic_feature": [0.123, 0.456, ...],
"attributes": {
"material": "fabric",
"color": "white",
"state": "made",
"affordance": ["sittable", "lyable"]
}
}
]
}
```
### 4.3 场景图
#### scene_graph.json
```json
{
"version": "1.0",
"scene_id": "room_301",
"metadata": {
"room_type": "hotel_room",
"floor_area": 25.5,
"ceiling_height": 2.8,
"capture_date": "2026-05-16"
},
"nodes": [
{
"node_id": "bed_001",
"type": "object",
"label": "bed",
"instance_ref": "bed_001",
"properties": {
"size": "queen",
"material": "fabric",
"color": "white"
}
},
{
"node_id": "nightstand_001",
"type": "object",
"label": "nightstand",
"instance_ref": "nightstand_001"
},
{
"node_id": "lamp_001",
"type": "object",
"label": "lamp",
"instance_ref": "lamp_001"
}
],
"edges": [
{
"edge_id": 0,
"source": "lamp_001",
"target": "nightstand_001",
"relation": "supported_by",
"confidence": 0.98,
"properties": {
"contact_area": 0.05,
"stability": "stable"
}
},
{
"edge_id": 1,
"source": "nightstand_001",
"target": "bed_001",
"relation": "next_to",
"confidence": 0.95,
"properties": {
"distance": 0.1,
"side": "left"
}
}
]
}
```
---
## 五、物理数据格式
### 5.1 USD场景(Universal Scene Description
#### scene.usd(文本格式示例)
```python
#usda 1.0
(
defaultPrim = "World"
metersPerUnit = 1
upAxis = "Z"
)
def Xform "World"
{
def Mesh "Bed"
{
float3[] extent = [(-1, -1, 0), (1, 1, 1)]
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
int[] faceVertexIndices = [0, 1, 3, 2, ...]
point3f[] points = [(0.5, 1.0, 0.0), ...]
# 物理属性
def PhysicsRigidBodyAPI
{
bool kinematicEnabled = true
}
def PhysicsMassAPI
{
float mass = 50.0
}
def PhysicsCollisionAPI
{
}
def PhysicsMaterialAPI
{
float staticFriction = 0.5
float dynamicFriction = 0.4
float restitution = 0.1
}
}
def Mesh "Wardrobe_Door"
{
# 铰接物体
def PhysicsRevoluteJoint "Hinge"
{
rel body0 = </World/Wardrobe>
rel body1 = </World/Wardrobe_Door>
point3f localPos0 = (0, 0, 0)
point3f localPos1 = (0.5, 0, 0)
float3 axis = (0, 0, 1)
float lowerLimit = 0.0
float upperLimit = 120.0
}
}
}
```
### 5.2 铰接信息
#### articulation.json
```json
{
"version": "1.0",
"scene_id": "room_301",
"articulated_objects": [
{
"object_id": "wardrobe_door_001",
"base_link": "wardrobe_001",
"joint_type": "revolute",
"joint_axis": [0, 0, 1],
"joint_origin": [1.0, 2.0, 1.0],
"joint_limits": {
"lower": 0.0,
"upper": 2.094,
"effort": 10.0,
"velocity": 1.0
},
"damping": 0.5,
"friction": 0.1
},
{
"object_id": "drawer_001",
"base_link": "desk_001",
"joint_type": "prismatic",
"joint_axis": [1, 0, 0],
"joint_origin": [1.5, 1.0, 0.7],
"joint_limits": {
"lower": 0.0,
"upper": 0.4,
"effort": 5.0,
"velocity": 0.5
}
}
]
}
```
### 5.3 材质物理属性
#### material_props.json
```json
{
"version": "1.0",
"materials": [
{
"material_id": "wood_oak",
"density": 600.0,
"static_friction": 0.5,
"dynamic_friction": 0.4,
"restitution": 0.3,
"young_modulus": 11000000000.0,
"poisson_ratio": 0.3,
"damping": 0.1
},
{
"material_id": "fabric_cotton",
"density": 200.0,
"static_friction": 0.7,
"dynamic_