0xZohar commited on
Commit
c96c6e8
·
verified ·
1 Parent(s): c4f4426

Add code/cube3d/training/ldr_coordinate_analyzer.py

Browse files
code/cube3d/training/ldr_coordinate_analyzer.py ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+ from matplotlib.ticker import MaxNLocator
6
+ import pandas as pd
7
+ from glob import glob
8
+
9
+ # 设置中文字体
10
+ plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
11
+ plt.rcParams["axes.unicode_minus"] = False # 正确显示负号
12
+
13
+ def parse_ldr_file(file_path):
14
+ """解析LDR文件,提取零件的XYZ坐标(修复:用空格分割,兼容不同格式)"""
15
+ coordinates = []
16
+
17
+ with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
18
+ for line_num, line in enumerate(f, 1):
19
+ line = line.strip()
20
+ # 只处理以1开头的零件行,且排除空行
21
+ if line.startswith('1') and len(line.split()) >= 5:
22
+ try:
23
+ # 核心修复:用split()按任意空格分割,取第3、4、5个元素(索引2、3、4)
24
+ parts = line.split()
25
+ x = float(parts[2]) # 原正则的group(3)对应split后的索引2
26
+ y = float(parts[3]) # 原正则的group(4)对应split后的索引3
27
+ z = float(parts[4]) # 原正则的group(5)对应split后的索引4
28
+ coordinates.append((x, y, z))
29
+ except (ValueError, IndexError) as e:
30
+ # 详细打印错误行,方便排查格式问题
31
+ print(f"警告: 文件 {os.path.basename(file_path)} 第 {line_num} 行解析失败 - {e}")
32
+ print(f" 错误行内容: {line}")
33
+
34
+ return np.array(coordinates) if coordinates else None
35
+
36
+ def translate_coordinates(coords):
37
+ """将坐标平移到原点附近,平移量为max_x/2, max_y/2, max_z/2"""
38
+ if coords is None or len(coords) == 0:
39
+ return None, (0, 0, 0)
40
+
41
+ # 计算各维度最大值(确保坐标≥0的前提下)
42
+ max_x = np.max(coords[:, 0])
43
+ max_y = np.max(coords[:, 1])
44
+ max_z = np.max(coords[:, 2])
45
+
46
+ # 计算平移量(向原点方向移动一半最大值)
47
+ tx = max_x / 2
48
+ ty = max_y / 2
49
+ tz = max_z / 2
50
+
51
+ # 执行平移
52
+ translated = coords - np.array([tx, ty, tz])
53
+
54
+ return translated, (tx, ty, tz)
55
+
56
+ def analyze_ldr_folder(folder_path):
57
+ """分析文件夹中所有LDR文件的坐标分布"""
58
+ all_coords = []
59
+ # 递归获取所有LDR文件(包括子文件夹)
60
+ ldr_files = glob(os.path.join(folder_path, '**', '*.ldr'), recursive=True)
61
+
62
+ if not ldr_files:
63
+ print(f"错误:在 {folder_path} 中未找到任何LDR文件")
64
+ return None
65
+
66
+ print(f"找到 {len(ldr_files)} 个LDR文件,开始分析...")
67
+
68
+ for file_idx, file_path in enumerate(ldr_files, 1):
69
+ # 解析单个文件的坐标
70
+ coords = parse_ldr_file(file_path)
71
+ if coords is None or len(coords) == 0:
72
+ print(f"文件 {file_idx}/{len(ldr_files)}: {os.path.basename(file_path)} 中未找到有效坐标")
73
+ continue
74
+
75
+ # 平移坐标到原点附近
76
+ translated_coords, translation = translate_coordinates(coords)
77
+
78
+ # 收集所有平移后的坐标
79
+ all_coords.append(translated_coords)
80
+
81
+ # 每处理10个文件或最后一个文件时,打印进度
82
+ if file_idx % 10 == 0 or file_idx == len(ldr_files):
83
+ total_parts = sum(len(c) for c in all_coords)
84
+ print(f"已处理 {file_idx}/{len(ldr_files)} 个文件,累计零件数: {total_parts}")
85
+
86
+ if not all_coords:
87
+ print("未找到任何有效坐标数据,终止分析")
88
+ return None
89
+
90
+ # 合并所有文件的坐标(按行堆叠)
91
+ all_coords = np.vstack(all_coords)
92
+ print(f"\n分析完成!共处理 {len(all_coords)} 个零件坐标")
93
+
94
+ return all_coords
95
+
96
+ def plot_coordinate_distributions(coords, output_dir):
97
+ """绘制XYZ三个维度的坐标分布直方图"""
98
+ if coords is None or len(coords) == 0:
99
+ print("没有可绘制的坐标数据")
100
+ return
101
+
102
+ # 创建输出目录(不存在则自动创建)
103
+ os.makedirs(output_dir, exist_ok=True)
104
+
105
+ # 提取XYZ三个维度的坐标
106
+ x_coords = coords[:, 0]
107
+ y_coords = coords[:, 1]
108
+ z_coords = coords[:, 2]
109
+
110
+ # 计算各维度的统计信息(最小值、最大值、平均值、标准差)
111
+ stats = {
112
+ 'X轴': {
113
+ '最小值': np.min(x_coords),
114
+ '最大值': np.max(x_coords),
115
+ '平均值': np.mean(x_coords),
116
+ '标准差': np.std(x_coords)
117
+ },
118
+ 'Y轴': {
119
+ '最小值': np.min(y_coords),
120
+ '最大值': np.max(y_coords),
121
+ '平均值': np.mean(y_coords),
122
+ '标准差': np.std(y_coords)
123
+ },
124
+ 'Z轴': {
125
+ '最小值': np.min(z_coords),
126
+ '最大值': np.max(z_coords),
127
+ '平均值': np.mean(z_coords),
128
+ '标准差': np.std(z_coords)
129
+ }
130
+ }
131
+
132
+ # 打印统计信息(控制台直观查看)
133
+ print("\n=== 坐标分布统计信息 ===")
134
+ for axis, info in stats.items():
135
+ print(f"{axis}:")
136
+ for key, val in info.items():
137
+ print(f" {key}: {val:.2f}")
138
+
139
+ # 保存统计信息到CSV文件(便于后续分析)
140
+ stats_df = pd.DataFrame(stats).T
141
+ stats_csv_path = os.path.join(output_dir, 'coordinate_stats.csv')
142
+ stats_df.to_csv(stats_csv_path, encoding='utf-8-sig')
143
+ print(f"\n统计信息已保存到: {stats_csv_path}")
144
+
145
+ # 绘制XYZ三个维度的分布直方图(1行3列布局)
146
+ fig, axes = plt.subplots(1, 3, figsize=(18, 6))
147
+ bins = 50 # 直方图分箱数(可根据数据量调整,50适合中等数据量)
148
+
149
+ # X轴坐标分布(红色)
150
+ axes[0].hist(x_coords, bins=bins, alpha=0.7, color='#FF6B6B')
151
+ axes[0].set_title(f'X轴坐标分布\n(均值: {stats["X轴"]["平均值"]:.2f}, 标准差: {stats["X轴"]["标准差"]:.2f})', pad=15)
152
+ axes[0].set_xlabel('坐标值', fontsize=12)
153
+ axes[0].set_ylabel('频数', fontsize=12)
154
+ axes[0].grid(True, alpha=0.3)
155
+ axes[0].xaxis.set_major_locator(MaxNLocator(6)) # 限制X轴刻度数量,避免拥挤
156
+
157
+ # Y轴坐标分布(绿色)
158
+ axes[1].hist(y_coords, bins=bins, alpha=0.7, color='#4ECDC4')
159
+ axes[1].set_title(f'Y轴坐标分布\n(均值: {stats["Y轴"]["平均值"]:.2f}, 标准差: {stats["Y轴"]["标准差"]:.2f})', pad=15)
160
+ axes[1].set_xlabel('坐标值', fontsize=12)
161
+ axes[1].set_ylabel('频数', fontsize=12)
162
+ axes[1].grid(True, alpha=0.3)
163
+ axes[1].xaxis.set_major_locator(MaxNLocator(6))
164
+
165
+ # Z轴坐标分布(蓝色)
166
+ axes[2].hist(z_coords, bins=bins, alpha=0.7, color='#45B7D1')
167
+ axes[2].set_title(f'Z轴坐标分布\n(均值: {stats["Z轴"]["平均值"]:.2f}, 标准差: {stats["Z轴"]["标准差"]:.2f})', pad=15)
168
+ axes[2].set_xlabel('坐标值', fontsize=12)
169
+ axes[2].set_ylabel('频数', fontsize=12)
170
+ axes[2].grid(True, alpha=0.3)
171
+ axes[2].xaxis.set_major_locator(MaxNLocator(6))
172
+
173
+ # 调整子图间距,避免标题/标签重叠
174
+ plt.tight_layout()
175
+
176
+ # 保存图片(高分辨率300dpi,适合后续使用)
177
+ plot_path = os.path.join(output_dir, 'coordinate_distributions.png')
178
+ plt.savefig(plot_path, dpi=300, bbox_inches='tight')
179
+ print(f"坐标分布图已保存到: {plot_path}")
180
+
181
+ # 显示图片(如果运行环境支持GUI)
182
+ plt.show()
183
+
184
+ if __name__ == "__main__":
185
+ # 配置路径(请根据实际情况修改)
186
+ LDR_FOLDER = "/public/home/wangshuo/gap/assembly/data/car_1k/subset_self/ldr_l30_rotrans_expand_wom" # LDR文件根目录
187
+ OUTPUT_DIR = "./ldr_coordinate_analysis" # 结果输出目录(统计CSV+分布图)
188
+
189
+ # 1. 分析所有LDR文件的坐标
190
+ all_translated_coords = analyze_ldr_folder(LDR_FOLDER)
191
+
192
+ # 2. 绘制并保存坐标分布图
193
+ if all_translated_coords is not None:
194
+ plot_coordinate_distributions(all_translated_coords, OUTPUT_DIR)