Files
massive-cloud/alg/train_measurement_system_v3.2_0629/src/measurement_logger.py

193 lines
6.8 KiB
Python
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.
"""测量详细日志记录器 - 记录测量过程的所有详细信息"""
import sys
from pathlib import Path
from datetime import datetime
from typing import Optional
class MeasurementLogger:
"""测量过程详细日志记录器"""
def __init__(self, output_dir: str = "results"):
"""
初始化测量日志记录器
Args:
output_dir: 输出目录路径
"""
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
# 生成日志文件名
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
self.log_file = self.output_dir / f"measurement_detail_{timestamp}.log"
# 打开日志文件
self.file_handle = open(self.log_file, 'w', encoding='utf-8')
# 写入头部
self._write_header()
def _write_header(self):
"""写入日志头部"""
self.log("=" * 80)
self.log("点云测量系统 - 详细测量日志")
self.log("=" * 80)
self.log(f"开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
self.log("=" * 80)
self.log("")
def log(self, message: str, also_print: bool = True):
"""
记录日志信息
Args:
message: 日志消息
also_print: 是否同时输出到控制台
"""
# 写入文件
self.file_handle.write(message + "\n")
self.file_handle.flush() # 立即刷新到文件
# 输出到控制台
if also_print:
print(message)
def log_task_start(self, task_index: int, total_tasks: int, task_name: str):
"""记录任务开始"""
self.log("")
self.log("=" * 80)
self.log(f"[{task_index}/{total_tasks}] 开始执行任务: {task_name}")
self.log("=" * 80)
def log_roi_extraction(self, roi_name: str, point_count: int, bbox_min: list, bbox_max: list):
"""
记录ROI提取信息
Args:
roi_name: ROI名称(如"源平面ROI"、"目标平面ROI")
point_count: 提取到的点数
bbox_min: ROI最小边界 [x, y, z]
bbox_max: ROI最大边界 [x, y, z]
"""
self.log(f" {roi_name}:")
self.log(f" 边界: X[{bbox_min[0]:.2f}, {bbox_max[0]:.2f}], "
f"Y[{bbox_min[1]:.2f}, {bbox_max[1]:.2f}], "
f"Z[{bbox_min[2]:.2f}, {bbox_max[2]:.2f}]")
self.log(f" 提取点数: {point_count:,} 个点")
def log_ransac_fitting(self, plane_name: str, total_points: int,
inlier_count: int, inlier_ratio: float,
plane_equation: Optional[tuple] = None):
"""
记录RANSAC平面拟合信息
Args:
plane_name: 平面名称(如"源平面"、"目标平面")
total_points: 参与拟合的总点数
inlier_count: 内点数量
inlier_ratio: 内点率(0-1之间的浮点数)
plane_equation: 平面方程 (a, b, c, d),满足 ax + by + cz + d = 0
"""
self.log(f" {plane_name} RANSAC拟合:")
self.log(f" 拟合点数: {total_points:,} 个点")
self.log(f" 内点数量: {inlier_count:,} 个点")
self.log(f" 内点率: {inlier_ratio:.2%}")
if plane_equation:
a, b, c, d = plane_equation
self.log(f" 平面方程: {a:.6f}x + {b:.6f}y + {c:.6f}z + {d:.6f} = 0")
# 计算法向量
import numpy as np
normal = np.array([a, b, c])
norm = np.linalg.norm(normal)
if norm > 0:
normal = normal / norm
self.log(f" 法向量: ({normal[0]:.6f}, {normal[1]:.6f}, {normal[2]:.6f})")
def log_sampling(self, sample_count: int, method: str = "均匀采样"):
"""
记录采样信息
Args:
sample_count: 采样点数
method: 采样方法
"""
self.log(f" 采样策略: {method}")
self.log(f" 采样点数: {sample_count} 个点")
def log_distance_result(self, mean_distance: float, std_distance: float,
min_distance: float, max_distance: float):
"""
记录距离测量结果
Args:
mean_distance: 平均距离
std_distance: 标准差
min_distance: 最小距离
max_distance: 最大距离
"""
self.log(f" 测量结果:")
self.log(f" 平均距离: {mean_distance:.4f} mm")
self.log(f" 标准差: {std_distance:.4f} mm")
self.log(f" 最小距离: {min_distance:.4f} mm")
self.log(f" 最大距离: {max_distance:.4f} mm")
self.log(f" 距离范围: [{min_distance:.4f}, {max_distance:.4f}] mm")
def log_task_success(self, execution_time: float):
"""记录任务成功"""
self.log(f" 任务状态: ✅ 成功")
self.log(f" 执行时间: {execution_time:.2f} 秒")
def log_task_failure(self, error_message: str, execution_time: float):
"""记录任务失败"""
self.log(f" 任务状态: ❌ 失败")
self.log(f" 错误信息: {error_message}")
self.log(f" 执行时间: {execution_time:.2f} 秒")
def log_circle_fitting(self, circle_name: str, center: tuple, radius: float,
point_count: int):
"""
记录圆拟合信息
Args:
circle_name: 圆的名称
center: 圆心坐标 (x, y, z)
radius: 半径
point_count: 拟合点数
"""
self.log(f" {circle_name}:")
self.log(f" 圆心: ({center[0]:.4f}, {center[1]:.4f}, {center[2]:.4f})")
self.log(f" 半径: {radius:.4f} mm")
self.log(f" 拟合点数: {point_count:,} 个点")
def log_kdtree_optimization(self, original_points: int, filtered_points: int,
percentage: float):
"""
记录KDTree优化信息
Args:
original_points: 原始点数
filtered_points: 筛选后点数
percentage: 保留百分比
"""
self.log(f" KDTree优化:")
self.log(f" 原始点数: {original_points:,} 个点")
self.log(f" 筛选后: {filtered_points:,} 个点 ({percentage:.2f}%)")
def close(self):
"""关闭日志文件"""
self.log("")
self.log("=" * 80)
self.log(f"结束时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
self.log("=" * 80)
if self.file_handle:
self.file_handle.close()
print(f"\n详细测量日志已保存到: {self.log_file}")
def __del__(self):
"""析构函数,确保文件被关闭"""
if hasattr(self, 'file_handle') and self.file_handle:
self.file_handle.close()