0xZohar commited on
Commit
fc3484d
·
verified ·
1 Parent(s): f065664

Add code/cube3d/training/copy_obj_from_json.py

Browse files
code/cube3d/training/copy_obj_from_json.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ import json
4
+ import re
5
+ from collections import defaultdict
6
+
7
+
8
+ def extract_leading_digits(prefix):
9
+ """提取前缀中最前面的连续数字,无数字则返回None"""
10
+ match = re.match(r'^(\d+)', prefix)
11
+ return match.group(1) if match else None
12
+
13
+
14
+ def compare_json_and_prefixes(json_file_path):
15
+ """对比JSON中的.dat键名和提取的前缀,找出差异"""
16
+ try:
17
+ print("\n" + "=" * 80)
18
+ print("第一步:JSON键名与提取前缀对比分析")
19
+ print("=" * 80)
20
+
21
+ # 1. 读取JSON所有.dat键名
22
+ json_keys = []
23
+ with open(json_file_path, 'r', encoding='utf-8') as f:
24
+ dat_mapping = json.load(f)
25
+ for key in dat_mapping.keys():
26
+ key_stripped = key.strip()
27
+ if key_stripped.endswith('.dat'):
28
+ json_keys.append(key_stripped)
29
+
30
+ total_json_keys = len(json_keys)
31
+ print(f"1. 从JSON中读取到 {total_json_keys} 个.dat键名")
32
+
33
+ # 2. 提取前缀并分析
34
+ extracted_prefixes = {}
35
+ prefix_to_keys = defaultdict(list) # 记录前缀对应的所有键名
36
+ for key in json_keys:
37
+ original_prefix = os.path.splitext(key)[0].strip()
38
+ lower_prefix = original_prefix.lower()
39
+ extracted_prefixes[lower_prefix] = original_prefix
40
+ prefix_to_keys[lower_prefix].append(key)
41
+
42
+ total_extracted = len(extracted_prefixes)
43
+ print(f"2. 提取到 {total_extracted} 个唯一前缀")
44
+
45
+ # 3. 分析差异原因
46
+ if total_extracted < total_json_keys:
47
+ diff_count = total_json_keys - total_extracted
48
+ print(f"\n⚠️ 发现差异:前缀数比JSON键名少 {diff_count} 个")
49
+ print(" 原因:存在不同键名对应相同前缀的情况(如下所示)")
50
+
51
+ # 显示前5个存在重复前缀的例子
52
+ duplicate_prefixes = {p: keys for p, keys in prefix_to_keys.items() if len(keys) > 1}
53
+ print(f"\n 存在重复前缀的键名数量:{len(duplicate_prefixes)} 组")
54
+ for i, (prefix, keys) in enumerate(list(duplicate_prefixes.items())[:5], 1):
55
+ print(f" 示例 {i}: 前缀 '{prefix}' 对应 {len(keys)} 个键名 → {keys[:2]}...")
56
+ else:
57
+ print("\n✅ 前缀数与JSON键名数一致,无差异")
58
+
59
+ return json_keys, prefix_to_keys
60
+
61
+ except Exception as e:
62
+ print(f"❌ 对比分析失败: {str(e)}")
63
+ return [], {}
64
+
65
+
66
+ def copy_obj_files(json_file_path, obj_source_dir, dest_dir, json_keys):
67
+ """复制OBJ文件,基于JSON中的.dat键名"""
68
+ try:
69
+ print("\n" + "=" * 80)
70
+ print("第二步:OBJ文件复制操作")
71
+ print("=" * 80)
72
+
73
+ # 1. 初始化目录
74
+ os.makedirs(dest_dir, exist_ok=True)
75
+ print(f"📂 目标目录已准备:{dest_dir}")
76
+
77
+ # 2. 预处理OBJ文件
78
+ obj_lower_to_info = {}
79
+ for filename in os.listdir(obj_source_dir):
80
+ if filename.lower().endswith('.obj'):
81
+ obj_original_prefix = os.path.splitext(filename)[0].strip()
82
+ obj_lower_prefix = obj_original_prefix.lower()
83
+ obj_full_path = os.path.join(obj_source_dir, filename)
84
+ obj_lower_to_info[obj_lower_prefix] = (obj_original_prefix, obj_full_path)
85
+ print(f"🔍 已预处理 {len(obj_lower_to_info)} 个OBJ文件")
86
+
87
+ # 3. 提取所有dat前缀(保留原始顺序)
88
+ dat_prefixes = [os.path.splitext(key)[0].strip() for key in json_keys]
89
+ print(f"📋 待匹配的dat前缀总数:{len(dat_prefixes)} 个")
90
+
91
+ # 4. 第一次匹配:完整前缀匹配
92
+ first_copied = [] # [(dat前缀, OBJ文件名)]
93
+ for prefix in dat_prefixes:
94
+ lower_prefix = prefix.lower()
95
+ if lower_prefix in obj_lower_to_info:
96
+ obj_original, obj_path = obj_lower_to_info[lower_prefix]
97
+ obj_filename = os.path.basename(obj_path)
98
+ dest_path = os.path.join(dest_dir, obj_filename)
99
+
100
+ if not os.path.exists(dest_path):
101
+ shutil.copy2(obj_path, dest_path)
102
+ first_copied.append((prefix, obj_filename))
103
+
104
+ print(f"\n第一次匹配完成:{len(first_copied)} 个前缀匹配成功")
105
+
106
+ # 5. 第二次匹配:未匹配前缀提取前导数字
107
+ matched_prefixes = {p for p, _ in first_copied}
108
+ not_found_first = [p for p in dat_prefixes if p not in matched_prefixes]
109
+ print(f"初始未匹配的前缀:{len(not_found_first)} 个")
110
+
111
+ second_copied = [] # [(dat前缀, OBJ文件名, 提取的数字)]
112
+ if not_found_first:
113
+ for prefix in not_found_first:
114
+ leading_digits = extract_leading_digits(prefix)
115
+ if not leading_digits:
116
+ continue
117
+
118
+ target_lower = leading_digits.lower()
119
+ if target_lower in obj_lower_to_info:
120
+ obj_original, obj_path = obj_lower_to_info[target_lower]
121
+ obj_filename = os.path.basename(obj_path)
122
+ dest_path = os.path.join(dest_dir, obj_filename)
123
+
124
+ if not os.path.exists(dest_path):
125
+ shutil.copy2(obj_path, dest_path)
126
+ second_copied.append((prefix, obj_filename, leading_digits))
127
+
128
+ print(f"第二次匹配完成:{len(second_copied)} 个前缀匹配成功")
129
+
130
+ # 6. 最终结果汇总
131
+ print("\n" + "=" * 60)
132
+ print("最终结果汇总")
133
+ print("=" * 60)
134
+ total_matched = len(first_copied) + len(second_copied)
135
+ print(f"📊 统计信息:")
136
+ print(f" - JSON中.dat键名总数:{len(json_keys)}")
137
+ print(f" - 第一次匹配成功:{len(first_copied)}")
138
+ print(f" - 第二次匹配成功:{len(second_copied)}")
139
+ print(f" - 总匹配成功:{total_matched}")
140
+ print(f" - 最终未匹配:{len(dat_prefixes) - total_matched}")
141
+
142
+ print(f"\n🏁 所有操作完成!复制的文件保存至:{dest_dir}")
143
+
144
+ except Exception as e:
145
+ print(f"❌ 复制操作失败: {str(e)}")
146
+
147
+
148
+ def main():
149
+ # 配置文件路径
150
+ JSON_FILE_PATH = "/public/home/wangshuo/gap/assembly/data/car_1k/subset_self/label_mapping_freq.json"
151
+ OBJ_SOURCE_DIR = "/public/home/wangshuo/gap/assembly/data/part_obj"
152
+ DEST_DIR = "/public/home/wangshuo/gap/assembly/data/part_obj_300"
153
+
154
+ # 执行完整流程
155
+ print("=" * 80)
156
+ print("JSON键名分析与OBJ文件复制工具")
157
+ print("=" * 80)
158
+
159
+ # 第一步:分析JSON键名与前缀的关系
160
+ json_keys, _ = compare_json_and_prefixes(JSON_FILE_PATH)
161
+ if not json_keys:
162
+ print("❌ 未获取到有效的JSON键名,无法继续操作")
163
+ return
164
+
165
+ # 第二步:基于分析结果进行OBJ文件复制
166
+ copy_obj_files(JSON_FILE_PATH, OBJ_SOURCE_DIR, DEST_DIR, json_keys)
167
+
168
+
169
+ if __name__ == "__main__":
170
+ main()
171
+