Spaces:
Paused
Paused
| import os | |
| import re | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| from matplotlib.ticker import MaxNLocator | |
| import pandas as pd | |
| from glob import glob | |
| # 设置中文字体 | |
| plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"] | |
| plt.rcParams["axes.unicode_minus"] = False # 正确显示负号 | |
| def parse_ldr_file(file_path): | |
| """解析LDR文件,提取零件的XYZ坐标(修复:用空格分割,兼容不同格式)""" | |
| coordinates = [] | |
| with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: | |
| for line_num, line in enumerate(f, 1): | |
| line = line.strip() | |
| # 只处理以1开头的零件行,且排除空行 | |
| if line.startswith('1') and len(line.split()) >= 5: | |
| try: | |
| # 核心修复:用split()按任意空格分割,取第3、4、5个元素(索引2、3、4) | |
| parts = line.split() | |
| x = float(parts[2]) # 原正则的group(3)对应split后的索引2 | |
| y = float(parts[3]) # 原正则的group(4)对应split后的索引3 | |
| z = float(parts[4]) # 原正则的group(5)对应split后的索引4 | |
| coordinates.append((x, y, z)) | |
| except (ValueError, IndexError) as e: | |
| # 详细打印错误行,方便排查格式问题 | |
| print(f"警告: 文件 {os.path.basename(file_path)} 第 {line_num} 行解析失败 - {e}") | |
| print(f" 错误行内容: {line}") | |
| return np.array(coordinates) if coordinates else None | |
| def translate_coordinates(coords): | |
| """将坐标平移到原点附近,平移量为max_x/2, max_y/2, max_z/2""" | |
| if coords is None or len(coords) == 0: | |
| return None, (0, 0, 0) | |
| # 计算各维度最大值(确保坐标≥0的前提下) | |
| max_x = np.max(coords[:, 0]) | |
| max_y = np.max(coords[:, 1]) | |
| max_z = np.max(coords[:, 2]) | |
| # 计算平移量(向原点方向移动一半最大值) | |
| tx = max_x / 2 | |
| ty = max_y / 2 | |
| tz = max_z / 2 | |
| # 执行平移 | |
| translated = coords - np.array([tx, ty, tz]) | |
| return translated, (tx, ty, tz) | |
| def analyze_ldr_folder(folder_path): | |
| """分析文件夹中所有LDR文件的坐标分布""" | |
| all_coords = [] | |
| # 递归获取所有LDR文件(包括子文件夹) | |
| ldr_files = glob(os.path.join(folder_path, '**', '*.ldr'), recursive=True) | |
| if not ldr_files: | |
| print(f"错误:在 {folder_path} 中未找到任何LDR文件") | |
| return None | |
| print(f"找到 {len(ldr_files)} 个LDR文件,开始分析...") | |
| for file_idx, file_path in enumerate(ldr_files, 1): | |
| # 解析单个文件的坐标 | |
| coords = parse_ldr_file(file_path) | |
| if coords is None or len(coords) == 0: | |
| print(f"文件 {file_idx}/{len(ldr_files)}: {os.path.basename(file_path)} 中未找到有效坐标") | |
| continue | |
| # 平移坐标到原点附近 | |
| translated_coords, translation = translate_coordinates(coords) | |
| # 收集所有平移后的坐标 | |
| all_coords.append(translated_coords) | |
| # 每处理10个文件或最后一个文件时,打印进度 | |
| if file_idx % 10 == 0 or file_idx == len(ldr_files): | |
| total_parts = sum(len(c) for c in all_coords) | |
| print(f"已处理 {file_idx}/{len(ldr_files)} 个文件,累计零件数: {total_parts}") | |
| if not all_coords: | |
| print("未找到任何有效坐标数据,终止分析") | |
| return None | |
| # 合并所有文件的坐标(按行堆叠) | |
| all_coords = np.vstack(all_coords) | |
| print(f"\n分析完成!共处理 {len(all_coords)} 个零件坐标") | |
| return all_coords | |
| def plot_coordinate_distributions(coords, output_dir): | |
| """绘制XYZ三个维度的坐标分布直方图""" | |
| if coords is None or len(coords) == 0: | |
| print("没有可绘制的坐标数据") | |
| return | |
| # 创建输出目录(不存在则自动创建) | |
| os.makedirs(output_dir, exist_ok=True) | |
| # 提取XYZ三个维度的坐标 | |
| x_coords = coords[:, 0] | |
| y_coords = coords[:, 1] | |
| z_coords = coords[:, 2] | |
| # 计算各维度的统计信息(最小值、最大值、平均值、标准差) | |
| stats = { | |
| 'X轴': { | |
| '最小值': np.min(x_coords), | |
| '最大值': np.max(x_coords), | |
| '平均值': np.mean(x_coords), | |
| '标准差': np.std(x_coords) | |
| }, | |
| 'Y轴': { | |
| '最小值': np.min(y_coords), | |
| '最大值': np.max(y_coords), | |
| '平均值': np.mean(y_coords), | |
| '标准差': np.std(y_coords) | |
| }, | |
| 'Z轴': { | |
| '最小值': np.min(z_coords), | |
| '最大值': np.max(z_coords), | |
| '平均值': np.mean(z_coords), | |
| '标准差': np.std(z_coords) | |
| } | |
| } | |
| # 打印统计信息(控制台直观查看) | |
| print("\n=== 坐标分布统计信息 ===") | |
| for axis, info in stats.items(): | |
| print(f"{axis}:") | |
| for key, val in info.items(): | |
| print(f" {key}: {val:.2f}") | |
| # 保存统计信息到CSV文件(便于后续分析) | |
| stats_df = pd.DataFrame(stats).T | |
| stats_csv_path = os.path.join(output_dir, 'coordinate_stats.csv') | |
| stats_df.to_csv(stats_csv_path, encoding='utf-8-sig') | |
| print(f"\n统计信息已保存到: {stats_csv_path}") | |
| # 绘制XYZ三个维度的分布直方图(1行3列布局) | |
| fig, axes = plt.subplots(1, 3, figsize=(18, 6)) | |
| bins = 50 # 直方图分箱数(可根据数据量调整,50适合中等数据量) | |
| # X轴坐标分布(红色) | |
| axes[0].hist(x_coords, bins=bins, alpha=0.7, color='#FF6B6B') | |
| axes[0].set_title(f'X轴坐标分布\n(均值: {stats["X轴"]["平均值"]:.2f}, 标准差: {stats["X轴"]["标准差"]:.2f})', pad=15) | |
| axes[0].set_xlabel('坐标值', fontsize=12) | |
| axes[0].set_ylabel('频数', fontsize=12) | |
| axes[0].grid(True, alpha=0.3) | |
| axes[0].xaxis.set_major_locator(MaxNLocator(6)) # 限制X轴刻度数量,避免拥挤 | |
| # Y轴坐标分布(绿色) | |
| axes[1].hist(y_coords, bins=bins, alpha=0.7, color='#4ECDC4') | |
| axes[1].set_title(f'Y轴坐标分布\n(均值: {stats["Y轴"]["平均值"]:.2f}, 标准差: {stats["Y轴"]["标准差"]:.2f})', pad=15) | |
| axes[1].set_xlabel('坐标值', fontsize=12) | |
| axes[1].set_ylabel('频数', fontsize=12) | |
| axes[1].grid(True, alpha=0.3) | |
| axes[1].xaxis.set_major_locator(MaxNLocator(6)) | |
| # Z轴坐标分布(蓝色) | |
| axes[2].hist(z_coords, bins=bins, alpha=0.7, color='#45B7D1') | |
| axes[2].set_title(f'Z轴坐标分布\n(均值: {stats["Z轴"]["平均值"]:.2f}, 标准差: {stats["Z轴"]["标准差"]:.2f})', pad=15) | |
| axes[2].set_xlabel('坐标值', fontsize=12) | |
| axes[2].set_ylabel('频数', fontsize=12) | |
| axes[2].grid(True, alpha=0.3) | |
| axes[2].xaxis.set_major_locator(MaxNLocator(6)) | |
| # 调整子图间距,避免标题/标签重叠 | |
| plt.tight_layout() | |
| # 保存图片(高分辨率300dpi,适合后续使用) | |
| plot_path = os.path.join(output_dir, 'coordinate_distributions.png') | |
| plt.savefig(plot_path, dpi=300, bbox_inches='tight') | |
| print(f"坐标分布图已保存到: {plot_path}") | |
| # 显示图片(如果运行环境支持GUI) | |
| plt.show() | |
| if __name__ == "__main__": | |
| # 配置路径(请根据实际情况修改) | |
| LDR_FOLDER = "/public/home/wangshuo/gap/assembly/data/car_1k/subset_self/ldr_l30_rotrans_expand_wom" # LDR文件根目录 | |
| OUTPUT_DIR = "./ldr_coordinate_analysis" # 结果输出目录(统计CSV+分布图) | |
| # 1. 分析所有LDR文件的坐标 | |
| all_translated_coords = analyze_ldr_folder(LDR_FOLDER) | |
| # 2. 绘制并保存坐标分布图 | |
| if all_translated_coords is not None: | |
| plot_coordinate_distributions(all_translated_coords, OUTPUT_DIR) |