Files
XplorePlane/XP.Hardware.MotionControl/Documents/Calibration_README.md
T

361 lines
16 KiB
Markdown
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.
# 像素-载物台映射子模块 | Pixel-to-Stage Mapping Submodule
> 文档版本:v2.0
> 创建日期:2026-06-30
> 更新日期:2026-07-01
> 适用模块:XP.Hardware.MotionControl / Calibration
---
## 1. 概述 | Overview
本子模块建立**图像像素坐标**与**载物台物理运动距离**之间的映射关系,使系统能够根据当前放大倍率,将图像上的像素偏移量转换为载物台的实际运动距离(mm)。
### 1.1 推荐方式:基于几何配置直接计算(v2.0 新增)
核心公式:
```
mmPerPixelX = DetectorPixelSizeX / M
mmPerPixelY = DetectorPixelSizeY / M
```
其中:
- `DetectorPixelSizeX`:探测器单像素 X 方向物理尺寸(mm),由探测器硬件规格决定,配置在 App.config 中
- `DetectorPixelSizeY`:探测器单像素 Y 方向物理尺寸(mm),通常与 X 相同(正方形像素)
- `M`:当前放大倍率(Magnification),由 FDD / FOD 实时计算得出(参见 GeometryWithDetectorSwing.md
**原理说明**:探测器感光面上每个像素对应固定的物理尺寸(如 0.139mm),经过锥束放大后,载物台平面上每个像素对应的实际物理尺寸 = 像素物理尺寸 / 放大比。这是纯几何关系,无需标定即可直接计算。
**优势**
- 无需手动标定流程,配置一次即可使用
- 放大比变化时自动适配(因为 M 是实时计算的)
- 精度取决于机构精度(FOD/FDD 的准确性),对于大多数定位应用已足够
### 1.2 已废弃方式:手动标定向导
旧方式通过两点标定求取标定常数 K,公式为 `mmPerPixel = K / M`。该方式已标记为 `[Obsolete]`,代码保留用于向后兼容,但不再推荐使用。
`DetectorPixelSizeX` 配置为 0 或未配置时,系统会自动回退到手动标定数据(如果存在)。
典型应用场景:用户在图像上点击某一点,系统计算该点相对图像中心的像素偏移,自动将载物台移动到使该点居中的物理位置。
---
## 2. 目录结构 | Directory Structure
```
XP.Hardware.MotionControl/Calibration/
├── Interfaces/ # 服务接口定义 | Service interfaces
│ └── IMagnificationCalibrationService.cs
├── Models/ # 数据模型(已废弃的标定数据)| Data models (deprecated)
│ └── MagnificationCalibrationData.cs
├── Implementations/ # 服务实现 | Service implementations
│ └── MagnificationCalibrationService.cs
├── ViewModels/ # 向导 ViewModel(已废弃)| Wizard ViewModel (deprecated)
│ └── CalibrationWizardViewModel.cs
└── Views/ # 向导窗口(已废弃)| Wizard window (deprecated)
├── CalibrationWizardWindow.xaml
└── CalibrationWizardWindow.xaml.cs
```
---
## 3. 配置参数 | Configuration
`App.config``<appSettings>` 中配置,键名前缀为 `MotionControl:Geometry:`
| 参数 | 键名 | 默认值 | 单位 | 说明 |
|------|------|--------|------|------|
| 探测器像素物理尺寸X | `Geometry:DetectorPixelSizeX` | 0.139 | mm | 探测器单像素 X 方向物理尺寸,由探测器规格书获取 |
| 探测器像素物理尺寸Y | `Geometry:DetectorPixelSizeY` | 0.139 | mm | 探测器单像素 Y 方向物理尺寸,通常与 X 相同 |
| 像素方向系数X | `Geometry:PixelDirectionX` | 1 | — | 对齐图像 X 轴方向与载物台 X 运动方向(+1 或 -1) |
| 像素方向系数Y | `Geometry:PixelDirectionY` | -1 | — | 对齐图像 Y 轴方向与载物台 Y 运动方向(+1 或 -1) |
### App.config 配置示例
```xml
<!-- 探测器像素物理尺寸(mm| Detector pixel physical size (mm) -->
<!-- 用于直接计算像素到载物台距离的映射:mmPerPixel = PixelSize / Magnification -->
<add key="MotionControl:Geometry:DetectorPixelSizeX" value="0.139" />
<add key="MotionControl:Geometry:DetectorPixelSizeY" value="0.139" />
<!-- 像素方向系数:对齐图像像素坐标方向与载物台运动方向(+1 或 -1| Pixel direction coefficients -->
<add key="MotionControl:Geometry:PixelDirectionX" value="1" />
<add key="MotionControl:Geometry:PixelDirectionY" value="-1" />
```
### 如何确定 DetectorPixelSizeX / Y
从探测器规格书中获取。例如:
- Varex 3072×3060 探测器:像素尺寸 0.139mm × 0.139mm
- 当使用 2×2 Binning 时:等效像素尺寸 0.278mm × 0.278mm
**注意**:如果使用了 Binning 模式,需要将像素尺寸乘以 Binning 倍数。
### 如何确定 PixelDirectionX / Y
实验方法:
1. 在图像中观察某物体,记下其在图像中的位置(如偏左)
2. 手动向 X+ 方向移动载物台
3. 观察物体在图像中的运动方向:
- 如果物体向图像 X+ 方向移动 → `PixelDirectionX = 1`
- 如果物体向图像 X- 方向移动 → `PixelDirectionX = -1`
4. Y 方向同理
---
## 4. 核心组件 | Core Components
### 4.1 IMagnificationCalibrationService(服务接口)
| 成员 | 类型 | 说明 |
|------|------|------|
| `IsReady` | `bool` (get) | 是否可以进行像素到载物台转换(几何配置有效 或 手动标定已完成) |
| `IsCalibrated` | `bool` (get) | ⚠️ 已废弃。是否已完成手动标定 |
| `CurrentData` | `MagnificationCalibrationData` (get) | ⚠️ 已废弃。当前手动标定数据 |
| `LoadCalibration()` | `bool` | ⚠️ 已废弃。从 JSON 加载手动标定数据 |
| `SaveCalibration(data)` | `bool` | ⚠️ 已废弃。保存手动标定数据到 JSON |
| `PixelsToStageMovement(dx, dy, M)` | `(double, double)` | 像素偏移 → 载物台移动距离转换 |
### 4.2 转换逻辑优先级 | Conversion Logic Priority
```
PixelsToStageMovement(dxPixels, dyPixels, currentMagnification):
1. 优先:几何直接计算(当 DetectorPixelSizeX > 0 时)
mmPerPixelX = DetectorPixelSizeX / M
mmPerPixelY = DetectorPixelSizeY / M
stageDx = dxPixels × mmPerPixelX × PixelDirectionX
stageDy = dyPixels × mmPerPixelY × PixelDirectionY
2. 回退:手动标定数据(当几何配置无效且标定文件存在时)
mmPerPixel = K / M
stageDx = dxPixels × mmPerPixel × DirectionX
stageDy = dyPixels × mmPerPixel × DirectionY
3. 异常:两者均不可用时抛出 InvalidOperationException
```
### 4.3 MagnificationCalibrationService(服务实现)
- 通过构造函数注入 `ILoggerService``MotionControlConfig`
- 启动时自动判断使用几何计算模式还是手动标定模式,并输出日志
- 标定文件路径:`{AppBaseDirectory}/Calibration/MagnificationCalibration.json`(仅作为 fallback
- 作为**单例**注册到 `MotionControlModule` 的 DI 容器
**异常约定 | Exception Contract**
| 条件 | 异常类型 | 说明 |
|------|----------|------|
| `IsReady == false` 时调用转换 | `InvalidOperationException` | 几何配置无效且未完成手动标定 |
| `currentMagnification <= 0` | `ArgumentException` | 放大倍率必须为正数 |
---
## 5. 关键算法 | Key Algorithms
### 5.1 几何直接计算(推荐)| Geometry Direct Calculation (Recommended)
```
stageDx_mm = dxPixels × (DetectorPixelSizeX / M) × PixelDirectionX
stageDy_mm = dyPixels × (DetectorPixelSizeY / M) × PixelDirectionY
```
**物理意义**
- 探测器感光面上每个像素的物理尺寸是固定的(由硬件决定)
- 锥束投影下,载物台平面上的等效像素尺寸 = 探测器像素尺寸 / 放大比
- 放大比 M = FDD / FOD,由几何计算器根据当前轴位置实时计算
**精度分析**
- 假设 DetectorPixelSizeX = 0.139mm(精确值,来自规格书)
- 放大比 M 的精度取决于 FOD/FDD 的精度(即轴位置 + 几何原点偏移的精度)
- 若 FOD 有 1mm 误差(500mm 中),放大比相对误差约 0.2%
- 对于 100mm 视场范围,位置误差约 0.2mm,满足绝大多数定位需求
### 5.2 手动标定(已废弃)| Manual Calibration (Deprecated)
```
K = M × FovDistance / DetectorPixelCountX (标定常数计算)
mmPerPixel = K / currentMagnification (使用时转换)
```
K 本质上就是探测器单像素的物理尺寸(理想情况下 K ≈ DetectorPixelSizeX),手动标定的意义在于:
- 修正 FOD/FDD 的系统性偏差
- 补偿探测器实际像素尺寸与标称值的差异
- 对精度要求极高的场景仍可使用
---
## 6. 模块集成 | Module Integration
`MotionControlModule.RegisterTypes` 中注册:
```csharp
// 注册放大比标定服务(单例)| Register magnification calibration service (singleton)
containerRegistry.RegisterSingleton<IMagnificationCalibrationService, MagnificationCalibrationService>();
```
### 外部调用示例 | External Usage Example
```csharp
public class SomeViewModel
{
private readonly IMotionControlService _motion;
public SomeViewModel(IMotionControlService motion)
{
_motion = motion;
}
// 用户点击图像某点,计算相对图像中心的像素偏移后,一键驱动载物台移动
// User clicks a point on image, calculates pixel offset from center, and drives stage movement
public void CenterOnPixel(double dxPixels, double dyPixels)
{
// 直接驱动载物台移动(内部自动获取放大比、计算距离、执行运动)
// Directly drives stage move (internally gets magnification, calculates distance, executes motion)
var result = _motion.MoveStageByPixelOffset(dxPixels, dyPixels);
if (!result.Success)
{
// 处理错误 | Handle error
MessageBox.Show(result.ErrorMessage);
}
}
// 仅预览计算结果,不实际移动 | Preview calculation only, no actual move
public string PreviewMove(double dxPixels, double dyPixels)
{
var result = _motion.MoveStageByPixelOffset(dxPixels, dyPixels, executeMove: false);
return result.ErrorMessage; // 成功时包含计算的位移信息 | Contains displacement info on success
}
}
```
也可以使用底层接口单独计算(不驱动运动):
```csharp
public class AnotherViewModel
{
private readonly IMagnificationCalibrationService _calibration;
private readonly IMotionControlService _motion;
public AnotherViewModel(
IMagnificationCalibrationService calibration,
IMotionControlService motion)
{
_calibration = calibration;
_motion = motion;
}
// 仅计算像素偏移对应的载物台距离(不移动)
// Calculate only, no move
public (double dx, double dy) CalculateOffset(double dxPixels, double dyPixels)
{
if (!_calibration.IsReady) return (0, 0);
var geometry = _motion.GetCurrentGeometry();
return _calibration.PixelsToStageMovement(dxPixels, dyPixels, geometry.Magnification);
}
}
```
### 6.1 两种用途辨析:点击居中 vs 坐标系补偿 | Click-to-Center vs Coordinate Compensation
`MoveStageByPixelOffset` 与坐标系补偿接口都基于相同的像素→mm 换算(内部统一由私有方法 `TryConvertPixelToStageMm` 计算),但用途不同:
| 用途 | 接口 | 是否记录补偿 | 说明 |
|------|------|--------------|------|
| 点击居中 | `MoveStageByPixelOffset(dx, dy)` | 否 | 用户点击图像某点,一次性把该点移到中心,不影响后续运动 |
| 坐标系补偿 | `ApplyPixelOffsetCompensation(dx, dy)` | 是 | 主框架坐标匹配后记录补偿并修正到位,后续定点运动可叠加补偿 |
坐标系补偿的完整说明见 `MotionControl_Design.md` 第 14 节与 `GUIDENCE.md` 第 11 节。
---
## 7. 版本变更说明 | Change Log
### v2.12026-07-28
**新增坐标系补偿功能**
- **新增** `IMotionControlService` 坐标系补偿接口:`ApplyPixelOffsetCompensation``RecordPixelOffsetCompensation``GetStageCompensation``SetStageCompensation``ResetStageCompensation`
- **新增** `CompensationMode` 枚举(`Replace` 默认 / `Accumulate`
- **新增** `StageCompensationChangedEvent` 事件
- **变更** `MoveToTarget` / `MoveAllToTarget` 增加 `applyCompensation` 参数(默认 `false`),仅对 StageX/StageY 叠加补偿
- **重构** 将 `MoveStageByPixelOffset` 的像素→mm 换算抽为私有方法 `TryConvertPixelToStageMm`,供补偿接口复用(对外行为不变)
- 补偿功能复用现有几何配置,无需新增 App.config 参数
### v2.02026-07-01
**重大变更:从手动标定改为基于几何配置的直接计算**
- **新增** `GeometryConfig.DetectorPixelSizeX` / `DetectorPixelSizeY`:探测器像素物理尺寸配置
- **新增** `GeometryConfig.PixelDirectionX` / `PixelDirectionY`:像素方向系数配置
- **新增** `IMagnificationCalibrationService.IsReady` 属性:替代 `IsCalibrated`
- **废弃** 手动标定向导流程:标记为 `[Obsolete]`,代码保留但不再推荐使用
- **废弃** `IsCalibrated``CurrentData``LoadCalibration()``SaveCalibration()` 接口成员
- **变更** `MagnificationCalibrationService` 构造函数:新增 `MotionControlConfig` 依赖注入
- **变更** `PixelsToStageMovement` 转换逻辑:优先使用几何计算,回退到手动标定数据
**迁移指南**
1. 在 App.config 中配置 `DetectorPixelSizeX``DetectorPixelSizeY`(从探测器规格书获取)
2. 配置 `PixelDirectionX``PixelDirectionY`(通过实验确定方向对应关系)
3. 将代码中的 `IsCalibrated` 替换为 `IsReady`
4. 无需再运行标定向导,系统启动后即可使用像素映射功能
### v1.02026-06-30
- 初始版本,基于两点手动标定的像素-载物台映射
---
## 8. 已废弃:标定向导流程 | Deprecated: Calibration Wizard Flow
> ⚠️ 以下内容为 v1.0 的手动标定向导,已废弃。仅在 `DetectorPixelSizeX` 未配置时作为 fallback 使用。
向导窗口 `CalibrationWizardWindow` 基于 **Telerik RadWizard + Crystal 主题**,分为五步:
| 步骤 | 名称 | 主要内容 | 下一步条件 |
|------|------|----------|-----------|
| Step 1 | 标定介绍 | 显示标定原理和核心公式;输入探测器 X 方向像素数 | `DetectorPixelCountX > 0` |
| Step 2 | 标定点 1 | 输入 M1、X 视野实际距离;实时显示 K1 | `M1 > 0``FovDistance1 > 0` |
| Step 3 | 标定点 2 | 输入 M2、X 视野实际距离;实时显示 K2、一致性检查结果 | `M2 > 0``FovDistance2 > 0` |
| Step 4 | 方向标定 | 选择 X/Y 方向系数(+1/-1 | — |
| Step 5 | 验证与保存 | 标定结果汇总;输入测试放大比显示 mm/pixel;保存 | 保存成功后关闭窗口 |
标定文件路径:`{AppBaseDirectory}/Calibration/MagnificationCalibration.json`
---
## 9. 多语言支持 | Localization
所有向导界面文本通过模块级 Resources 资源文件管理,支持简体中文(zh-CN)、繁体中文(zh-TW)和英文(en-US)。
- 资源文件位置:`XP.Hardware.MotionControl/Resources/Resources*.resx`
- 资源键前缀:`Calibration_`
- XAML 绑定方式:`{loc:Localization Calibration_WizardTitle}`
- 服务日志输出采用双语格式(中文 | English)
---
## 10. 错误处理与日志 | Error Handling & Logging
- 启动时输出当前模式信息(几何直接计算 / 手动标定 fallback
- 几何配置无效时输出 Warn 级别日志
- 标定文件加载失败时输出 Error/Warn 级别日志(不影响几何计算模式)
- `PixelsToStageMovement` 在非法输入时抛出明确异常
- 统一使用 `ILoggerService.ForModule<MagnificationCalibrationService>()` 获取模块化日志实例
---
## 11. 关联文档 | Related Documents
| 文档 | 说明 |
|------|------|
| `README.md` | MotionControl 模块总体说明 |
| `GeometryWithDetectorSwing.md` | FOD/FDD/放大倍率(M)几何计算模型 |
| `MotionControl_Design.md` | 运动控制模块设计文档 |
---
**最后更新 | Last Updated**: 2026-07-01