# 像素-载物台映射子模块 | 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` 的 `` 中配置,键名前缀为 `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 ``` ### 如何确定 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(); ``` ### 外部调用示例 | 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.1(2026-07-28) **新增坐标系补偿功能** - **新增** `IMotionControlService` 坐标系补偿接口:`ApplyPixelOffsetCompensation`、`RecordPixelOffsetCompensation`、`GetStageCompensation`、`SetStageCompensation`、`ResetStageCompensation` - **新增** `CompensationMode` 枚举(`Replace` 默认 / `Accumulate`) - **新增** `StageCompensationChangedEvent` 事件 - **变更** `MoveToTarget` / `MoveAllToTarget` 增加 `applyCompensation` 参数(默认 `false`),仅对 StageX/StageY 叠加补偿 - **重构** 将 `MoveStageByPixelOffset` 的像素→mm 换算抽为私有方法 `TryConvertPixelToStageMm`,供补偿接口复用(对外行为不变) - 补偿功能复用现有几何配置,无需新增 App.config 参数 ### v2.0(2026-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.0(2026-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()` 获取模块化日志实例 --- ## 11. 关联文档 | Related Documents | 文档 | 说明 | |------|------| | `README.md` | MotionControl 模块总体说明 | | `GeometryWithDetectorSwing.md` | FOD/FDD/放大倍率(M)几何计算模型 | | `MotionControl_Design.md` | 运动控制模块设计文档 | --- **最后更新 | Last Updated**: 2026-07-01