File size: 7,208 Bytes
5c1bb37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#!/usr/bin/env python3
"""
HM3D语义信息读取工具

用于从semantic.txt或semantic.glb文件中读取房间语义信息
"""

import os
from pathlib import Path
from typing import Dict, List, Optional, Tuple
import numpy as np


def parse_semantic_txt(semantic_txt_path: str) -> Dict[int, List[int]]:
    """
    解析semantic.txt文件,提取房间ID到对象ID的映射
    
    semantic.txt格式:
    ID,颜色,类别名,房间ID
    
    Args:
        semantic_txt_path: semantic.txt文件路径
    
    Returns:
        room_to_objects: {room_id: [object_ids]} 字典
    """
    room_to_objects: Dict[int, List[int]] = {}
    
    if not os.path.exists(semantic_txt_path):
        return room_to_objects
    
    with open(semantic_txt_path, 'r', encoding='utf-8') as f:
        lines = f.readlines()
        
        # 跳过第一行标题(如果有)
        start_idx = 0
        if len(lines) > 0 and 'HM3D Semantic Annotations' in lines[0]:
            start_idx = 1
        
        for line in lines[start_idx:]:
            line = line.strip()
            if not line:
                continue
            
            # 解析格式: ID,颜色,类别名,房间ID
            parts = line.split(',')
            if len(parts) >= 4:
                try:
                    object_id = int(parts[0].strip())
                    room_id_str = parts[3].strip()
                    
                    # 房间ID可能是数字或空字符串
                    if room_id_str.isdigit():
                        room_id = int(room_id_str)
                        if room_id not in room_to_objects:
                            room_to_objects[room_id] = []
                        room_to_objects[room_id].append(object_id)
                except (ValueError, IndexError):
                    continue
    
    return room_to_objects


def load_semantic_from_glb(semantic_glb_path: str) -> Dict[int, List[int]]:
    """
    从semantic.glb文件中读取语义信息
    
    Args:
        semantic_glb_path: semantic.glb文件路径
    
    Returns:
        room_to_objects: {room_id: [object_ids]} 字典
    """
    room_to_objects: Dict[int, List[int]] = {}
    
    if not os.path.exists(semantic_glb_path):
        return room_to_objects
    
    try:
        import trimesh
        
        scene = trimesh.load(semantic_glb_path, process=False)
        
        if isinstance(scene, trimesh.Scene):
            # 遍历场景中的所有几何体
            for name, geom in scene.geometry.items():
                if isinstance(geom, trimesh.Trimesh):
                    # 尝试从对象名称或材质中提取房间ID
                    # HM3D的semantic.glb中,对象名称可能包含房间信息
                    # 或者通过材质索引来区分房间
                    # 这里需要根据实际格式调整
                    # 暂时返回空字典,因为semantic.txt更可靠
                    pass
    except ImportError:
        print("[WARN] trimesh未安装,无法从GLB读取语义信息")
    except Exception as e:
        print(f"[WARN] 从GLB读取语义信息失败: {e}")
    
    return room_to_objects


def find_semantic_file(mesh_path: str) -> Optional[str]:
    """
    根据GLB文件路径查找对应的语义文件
    
    查找顺序:
    1. semantic.txt文件(优先)
    2. semantic.glb文件
    
    Args:
        mesh_path: GLB文件路径
    
    Returns:
        语义文件路径,如果不存在则返回None
    """
    mesh_path_obj = Path(mesh_path)
    mesh_dir = mesh_path_obj.parent
    mesh_stem = mesh_path_obj.stem  # 不含扩展名的文件名
    
    # 尝试查找semantic.txt
    # 路径模式:从 hm3d-example-glb-v0.2/... 到 hm3d-example-semantic-annots-v0.2/...
    semantic_txt_path = None
    semantic_glb_path = None
    
    # 方法1: 在同一目录下查找
    semantic_txt_candidate = mesh_dir / f"{mesh_stem}.semantic.txt"
    if semantic_txt_candidate.exists():
        semantic_txt_path = str(semantic_txt_candidate)
    
    semantic_glb_candidate = mesh_dir / f"{mesh_stem}.semantic.glb"
    if semantic_glb_candidate.exists():
        semantic_glb_path = str(semantic_glb_candidate)
    
    # 方法2: 在语义标注目录中查找
    # 从 glb-v0.2 推断到 semantic-annots-v0.2
    if 'glb-v0.2' in str(mesh_dir):
        semantic_dir = str(mesh_dir).replace('glb-v0.2', 'semantic-annots-v0.2')
        semantic_dir_obj = Path(semantic_dir)
        
        if semantic_dir_obj.exists():
            semantic_txt_candidate = semantic_dir_obj / f"{mesh_stem}.semantic.txt"
            if semantic_txt_candidate.exists():
                semantic_txt_path = str(semantic_txt_candidate)
            
            semantic_glb_candidate = semantic_dir_obj / f"{mesh_stem}.semantic.glb"
            if semantic_glb_candidate.exists():
                semantic_glb_path = str(semantic_glb_candidate)
    
    # 方法3: 在上级目录的语义标注目录中查找
    if semantic_txt_path is None and semantic_glb_path is None:
        # 尝试在dataset_HM3D目录下查找
        dataset_root = mesh_dir.parent.parent if 'glb-v0.2' in str(mesh_dir) else mesh_dir.parent
        semantic_annots_dir = dataset_root / "hm3d-example-semantic-annots-v0.2"
        
        if semantic_annots_dir.exists():
            # 查找场景目录
            for scene_dir in semantic_annots_dir.iterdir():
                if scene_dir.is_dir():
                    semantic_txt_candidate = scene_dir / f"{mesh_stem}.semantic.txt"
                    if semantic_txt_candidate.exists():
                        semantic_txt_path = str(semantic_txt_candidate)
                        break
                    
                    semantic_glb_candidate = scene_dir / f"{mesh_stem}.semantic.glb"
                    if semantic_glb_candidate.exists():
                        semantic_glb_path = str(semantic_glb_candidate)
                        break
    
    # 优先返回semantic.txt
    if semantic_txt_path:
        return semantic_txt_path
    elif semantic_glb_path:
        return semantic_glb_path
    else:
        return None


def load_semantic_info(mesh_path: str) -> Tuple[Optional[Dict[int, List[int]]], Optional[str]]:
    """
    加载语义信息(优先使用semantic.txt,如果不存在则使用semantic.glb)
    
    Args:
        mesh_path: GLB文件路径
    
    Returns:
        (room_to_objects, semantic_file_path): 
        - room_to_objects: {room_id: [object_ids]} 字典,如果不存在则返回None
        - semantic_file_path: 使用的语义文件路径,如果不存在则返回None
    """
    semantic_file_path = find_semantic_file(mesh_path)
    
    if semantic_file_path is None:
        return None, None
    
    # 根据文件类型选择解析方法
    if semantic_file_path.endswith('.txt'):
        room_to_objects = parse_semantic_txt(semantic_file_path)
        return room_to_objects, semantic_file_path
    elif semantic_file_path.endswith('.glb'):
        room_to_objects = load_semantic_from_glb(semantic_file_path)
        return room_to_objects, semantic_file_path
    else:
        return None, None