Files
XplorePlane/XP.Scan/Documents/ScanConfig.Design.md
T
2026-04-22 15:16:43 +08:00

10 KiB

XP.Scan 扫描配置文件设计文档

1. 需求概述

在平面CT扫描采集过程中,需要将当前扫描的所有参数信息(项目信息、射线源参数、探测器参数、运动控制参数、扫描配置、校正配置)打包为一个配置对象,最终序列化为 INI 格式文件传递给重构电脑。

INI 文件结构与立式CT采集配置兼容,包含 6 个 Section:

  • [Project_Information] — 项目基本信息
  • [XRay] — 射线源参数
  • [Detector] — 探测器参数
  • [Move_Control] — 运动控制轴位置
  • [Scan_Config] — 扫描配置
  • [Correction_Config] — 校正参数

2. 设计方案对比

方案 优点 缺点 推荐
A. 单个大类 ScanConfig 简单直接 字段太多,职责不清
B. 分组模型 + 序列化服务 职责清晰,可测试,可扩展 类稍多
C. Dictionary + 手写序列化 灵活 无类型安全,易出错

选择方案 B:用分组模型类映射 INI 的每个 Section,加一个序列化服务负责读写 INI 文件。

3. 数据模型设计

3.1 整体结构

ScanConfigData (顶层聚合)
├── ProjectInfo          → [Project_Information]
├── XRayConfig           → [XRay]
├── DetectorConfig       → [Detector]
├── MoveControlConfig    → [Move_Control]
├── ScanSettings         → [Scan_Config]
└── CorrectionConfig     → [Correction_Config]

3.2 类定义

namespace XP.Scan.Models
{
    /// <summary>
    /// 扫描配置数据(顶层聚合,对应完整 INI 文件)
    /// </summary>
    public class ScanConfigData
    {
        public ProjectInfo ProjectInfo { get; set; } = new();
        public XRayConfig XRay { get; set; } = new();
        public DetectorConfig Detector { get; set; } = new();
        public MoveControlConfig MoveControl { get; set; } = new();
        public ScanSettings ScanSettings { get; set; } = new();
        public CorrectionConfig Correction { get; set; } = new();
    }
}

[Project_Information]

public class ProjectInfo
{
    /// <summary>图像保存路径</summary>
    public string FileSave { get; set; } = string.Empty;

    /// <summary>滤波片1</summary>
    public string Filter1 { get; set; } = "None";

    /// <summary>滤波片2</summary>
    public string Filter2 { get; set; } = "None";

    /// <summary>项目名称</summary>
    public string Project { get; set; } = string.Empty;

    /// <summary>样品编号</summary>
    public string SampleNo { get; set; } = string.Empty;

    /// <summary>扫描模式名称</summary>
    public string ScanMode { get; set; } = "QuickScan";
}

[XRay]

public class XRayConfig
{
    /// <summary>管电流 (μA)</summary>
    public int Current_uA { get; set; }

    /// <summary>焦点尺寸</summary>
    public string Focus { get; set; } = string.Empty;

    /// <summary>管电压 (kV)</summary>
    public int Voltage_kV { get; set; }
}

[Detector]

public class DetectorConfig
{
    /// <summary>帧合并数</summary>
    public int Det_Avg_Frames { get; set; } = 1;

    /// <summary>Binning 模式</summary>
    public string Det_Binning { get; set; } = "1*1";

    /// <summary>帧率</summary>
    public int Det_Frame_rate { get; set; } = 2;

    /// <summary>增益 (PGA)</summary>
    public int Det_PGA { get; set; } = 6;

    // ROI 参数
    public int Image_ROI_Height { get; set; }
    public int Image_ROI_Width { get; set; }
    public int Image_ROI_xStart { get; set; }
    public int Image_ROI_xEnd { get; set; }
    public int Image_ROI_yStart { get; set; }
    public int Image_ROI_yEnd { get; set; }
    public int Image_ROI_zStart { get; set; }
    public int Image_ROI_zEnd { get; set; }

    // 图像尺寸
    public int Image_Size_Height { get; set; }
    public int Image_Size_Width { get; set; }

    // 物理尺寸 (mm)
    public double Physical_Size_X { get; set; }
    public double Physical_Size_Y { get; set; }

    // 像素尺寸 (mm)
    public double Pixel_X { get; set; }
    public double Pixel_Y { get; set; }
}

[Move_Control]

public class MoveControlConfig
{
    /// <summary>探测器 X 位置 (mm)</summary>
    public double DetX { get; set; }

    /// <summary>探测器 Y 位置 (mm)</summary>
    public double DetY { get; set; }

    /// <summary>探测器 Z 位置 (mm)</summary>
    public double DetZ { get; set; }

    /// <summary>旋转台角度 (°)</summary>
    public double Rotation { get; set; }

    /// <summary>样品台 X 位置 (mm) — 即 SOD</summary>
    public double X { get; set; }

    /// <summary>射线源 Z 位置 (mm)</summary>
    public double XRAYZ { get; set; }

    /// <summary>样品台 Y 位置 (mm)</summary>
    public double Y { get; set; }
}

[Scan_Config]

public class ScanSettings
{
    /// <summary>采集张数</summary>
    public int AcquiresNums { get; set; }

    /// <summary>旋转角度 (°)</summary>
    public double RotateDegree { get; set; }

    /// <summary>扫描模式描述</summary>
    public string ScanMode { get; set; } = string.Empty;

    /// <summary>SDD — 射线源到探测器距离 (mm)</summary>
    public double SDD { get; set; }

    /// <summary>SOD — 射线源到样品距离 (mm)</summary>
    public double SOD { get; set; }
}

[Correction_Config]

public class CorrectionConfig
{
    /// <summary>探测器水平偏移 (mm)</summary>
    public double Detector_Horizontal_Offset { get; set; }

    /// <summary>探测器旋转偏移 (°)</summary>
    public double Detector_Rotation_Offset { get; set; }
}

4. INI 序列化服务设计

4.1 接口

namespace XP.Scan.Services
{
    public interface IScanConfigSerializer
    {
        /// <summary>将配置数据序列化为 INI 格式字符串</summary>
        string Serialize(ScanConfigData config);

        /// <summary>将配置数据写入 INI 文件</summary>
        void SaveToFile(ScanConfigData config, string filePath);

        /// <summary>从 INI 文件读取配置数据</summary>
        ScanConfigData LoadFromFile(string filePath);
    }
}

4.2 实现方案

不引入第三方 INI 库,手写轻量级序列化,原因:

  • INI 结构简单固定(6 个 Section,字段已知)
  • 避免额外 NuGet 依赖
  • 完全可控,格式与立式CT兼容

核心思路:用 [IniSection("Section_Name")][IniKey("Key_Name")] 特性标注模型属性,序列化时通过反射自动生成 INI 内容。

4.3 特性定义

/// <summary>标记 INI Section 名称</summary>
[AttributeUsage(AttributeTargets.Class)]
public class IniSectionAttribute : Attribute
{
    public string SectionName { get; }
    public IniSectionAttribute(string sectionName) => SectionName = sectionName;
}

/// <summary>标记 INI Key 名称(可选,默认用属性名)</summary>
[AttributeUsage(AttributeTargets.Property)]
public class IniKeyAttribute : Attribute
{
    public string KeyName { get; }
    public IniKeyAttribute(string keyName) => KeyName = keyName;
}

4.4 模型标注示例

[IniSection("Project_Information")]
public class ProjectInfo
{
    [IniKey("fileSave")]
    public string FileSave { get; set; } = string.Empty;

    [IniKey("filter1")]
    public string Filter1 { get; set; } = "None";

    // ...
}

[IniSection("XRay")]
public class XRayConfig
{
    [IniKey("Current_uA")]
    public int Current_uA { get; set; }

    // ...
}

4.5 序列化输出示例

[Project_Information]
fileSave=D:\HexagonCTData\Test_2026-04-21\Image
filter1=Cu 0.2mm
filter2=None
Project=Test
SampleNo=
ScanMode=QuickScan

[XRay]
Current_uA=1000
Focus=450um
Voltage_kV=450

[Detector]
Det_Avg_Frames=1
Det_Binning=1*1
...

5. 文件结构规划

XP.Scan/
├── Models/
│   ├── ScanConfigData.cs          # 顶层聚合类
│   ├── ProjectInfo.cs             # [Project_Information]
│   ├── XRayConfig.cs              # [XRay]
│   ├── DetectorConfig.cs          # [Detector]
│   ├── MoveControlConfig.cs       # [Move_Control]
│   ├── ScanSettings.cs            # [Scan_Config]
│   └── CorrectionConfig.cs        # [Correction_Config]
│
├── Attributes/
│   ├── IniSectionAttribute.cs     # Section 特性
│   └── IniKeyAttribute.cs         # Key 特性
│
├── Services/
│   ├── IScanConfigSerializer.cs   # 序列化接口
│   └── ScanConfigSerializer.cs    # 序列化实现(反射 + 手写 INI)
│
└── ...

6. 使用流程

1. 扫描开始前,从各硬件服务收集参数 → 填充 ScanConfigData

   var config = new ScanConfigData();
   config.XRay.Voltage_kV = raySourceService.CurrentVoltage;
   config.XRay.Current_uA = raySourceService.CurrentCurrent;
   config.Detector.Det_Avg_Frames = detectorService.AvgFrames;
   config.MoveControl.X = motionService.GetPosition(AxisId.StageX);
   config.ScanSettings.AcquiresNums = acquisitionCount;
   // ...

2. 序列化为 INI 文件

   var serializer = new ScanConfigSerializer();
   serializer.SaveToFile(config, @"D:\HexagonCTData\Test\ScanConfig.ini");

3. 传递给重构电脑(文件拷贝或网络传输)

7. 设计决策

决策 选择 理由
数据模型 分组类(每个 Section 一个类) 职责清晰,属性有类型安全
序列化方式 自定义特性 + 反射 轻量,无第三方依赖,格式完全可控
INI Key 映射 [IniKey] 特性 属性名可以用 C# 命名规范,INI Key 保持与立式CT兼容
数值格式 InvariantCulture 避免不同系统区域设置导致小数点格式不一致
文件编码 UTF-8 无 BOM 兼容性最好

8. 扩展性

  • 新增 Section:创建新模型类 + 标注 [IniSection] + 在 ScanConfigData 中添加属性
  • 新增字段:在对应模型类中添加属性 + 标注 [IniKey]
  • 反序列化:LoadFromFile 支持从 INI 文件回读配置(用于加载历史扫描参数)
  • 验证:可在模型类中添加 Validate() 方法,检查参数范围合法性

版本: 1.0 最后更新: 2026-04-21