diff --git a/README.md b/README.md index a4c8aac..ca86f50 100644 --- a/README.md +++ b/README.md @@ -1,110 +1,110 @@ -## XplorePlane 平面CT软件 - -### 系统目标 - -XplorePlane 系统用于控制平面 CT 设备的各个子系统(射线源、探测器、运动控制、相机)并完成采集图像的处理与分析,为研发与调试提供统一的软件平台。 - -### 总体架构 - -- 客户端框架: WPF + Prism MVVM(目标框架 net8.0-windows) -- 图像处理内核: ImageProcessing.Core(算子基类)+ ImageProcessing.Processors(具体算子),基于 EmguCV -- 相机控制: XP.Camera(Basler pylon SDK 封装,支持软件触发、参数读写) -- 硬件抽象: XP.Common + XP.Hardware.RaySource(射线源控制) -- 日志: Serilog -- UI 组件: Telerik RadRibbonView、Fluent.Ribbon - -### 解决方案结构 - -``` -XplorePlane.sln -├── XplorePlane/ # 主应用程序(WPF) -├── XP.Camera/ # 相机控制库(Basler) -├── ImageProcessing/ # 独立图像处理应用 -├── ImageProcessing.Core/ # 图像处理算子基类 -├── ImageProcessing.Processors/ # 具体算子实现 -├── ImageProcessing.Controls/ # 图像显示控件(ImageCanvasControl) -├── ImageROIControl/ # ROI 绘制控件 -├── XplorePlane.Tests/ # 单元测试 -└── ExternalLibraries/ # 外部 DLL 和 ONNX 模型 -``` - -### XplorePlane 主项目结构 - -``` -XplorePlane/ -├── App.xaml / App.xaml.cs # 应用入口 + DI 容器配置(AppBootstrapper) -├── Views/ -│ ├── Main/ -│ │ ├── MainWindow.xaml # 主窗口(Telerik Ribbon + 三栏布局) -│ │ ├── NavigationPropertyPanelView.xaml # 相机实时预览面板 -│ │ └── MotionControlPanelView.xaml # 运动控制面板 -│ ├── Cnc/ # CNC 编辑器 / 矩阵编排视图 -│ ├── ImageProcessing/ # 图像处理面板视图 -│ └── CameraSettingsWindow.xaml # 相机参数设置对话框 -├── ViewModels/ -│ ├── Main/ -│ │ ├── MainViewModel.cs # 主窗口 ViewModel -│ │ └── NavigationPropertyPanelViewModel.cs # 相机预览 ViewModel -│ ├── Cnc/ # CNC / 矩阵 ViewModel -│ └── ImageProcessing/ # 图像处理 / 流水线 ViewModel -├── Services/ -│ ├── AppState/ # 全局状态管理(线程安全) -│ ├── Camera/ # 相机服务 -│ ├── Cnc/ # CNC 程序服务 -│ ├── Matrix/ # 矩阵编排服务 -│ ├── Measurement/ # 测量数据服务 -│ ├── Pipeline/ # 流水线执行 / 持久化 -│ └── Recipe/ # 检测配方服务 -├── Models/ # 数据模型(State、CNC、Matrix、Pipeline 等) -├── Events/ # Prism 事件 -├── Libs/ -│ ├── Hardware/ # 硬件库 DLL(XP.Common、XP.Hardware.RaySource) -│ └── Native/ # 原生依赖库 -└── Assets/Icons/ # 工具栏图标 -``` - -### 相机集成 - -相机实时影像集成在主窗口左下角的 NavigationPropertyPanelView 中: - -- 连接/断开相机(Basler,通过 ICameraController) -- 开始/停止采集(软件触发模式) -- 实时预览(Live View,勾选"实时"复选框) -- 鼠标悬停显示像素坐标 -- 相机参数设置对话框(曝光时间、增益、分辨率、像素格式) -- 主界面 Ribbon 硬件栏提供"相机设置"快捷按钮 - -相机控制逻辑移植自 ImageProcessing 项目,使用 XP.Camera.PixelConverter 进行像素数据转换,通过 Application.Dispatcher.Invoke 保证 UI 线程安全。 - -### 依赖注入(DI) - -使用 Prism + DryIoc,在 AppBootstrapper.RegisterTypes() 中统一注册: - -- ICameraFactory / ICameraController / ICameraService(单例) -- IRaySourceService / IRaySourceFactory(单例) -- IAppStateService(单例,线程安全状态管理) -- NavigationPropertyPanelViewModel(单例,相机预览共享实例) -- 各 Service 和 ViewModel(按需注册) - -### 构建 - -```bash -# Debug -dotnet build XplorePlane.sln -c Debug - -# Release -dotnet build XplorePlane.sln -c Release -``` - -### TO-DO List - -- [x] 软件基于 WPF + Prism 基础的框架 -- [x] 日志库的引用(通过 XP.Common.dll) -- [x] 按推荐的 DLL 目录结构进行修改 -- [x] 通过库依赖的方式调用日志功能 -- [x] 界面的布局 -- [x] 相机实时影像集成(连接、采集、Live View、像素坐标显示) -- [x] 相机参数设置对话框(曝光、增益、分辨率、像素格式) -- [x] 主界面硬件栏相机设置按钮 -- [ ] 打通与硬件层的调用流程 -- [ ] 打通与图像层的调用流程 +## XplorePlane 平面CT软件 + +### 系统目标 + +XplorePlane 系统用于控制平面 CT 设备的各个子系统(射线源、探测器、运动控制、相机)并完成采集图像的处理与分析,为研发与调试提供统一的软件平台。 + +### 总体架构 + +- 客户端框架: WPF + Prism MVVM(目标框架 net8.0-windows) +- 图像处理内核: ImageProcessing.Core(算子基类)+ ImageProcessing.Processors(具体算子),基于 EmguCV +- 相机控制: XP.Camera(Basler pylon SDK 封装,支持软件触发、参数读写) +- 硬件抽象: XP.Common + XP.Hardware.RaySource(射线源控制) +- 日志: Serilog +- UI 组件: Telerik RadRibbonView、Fluent.Ribbon + +### 解决方案结构 + +``` +XplorePlane.sln +├── XplorePlane/ # 主应用程序(WPF) +├── XP.Camera/ # 相机控制库(Basler) +├── ImageProcessing/ # 独立图像处理应用 +├── ImageProcessing.Core/ # 图像处理算子基类 +├── ImageProcessing.Processors/ # 具体算子实现 +├── ImageProcessing.Controls/ # 图像显示控件(ImageCanvasControl) +├── ImageROIControl/ # ROI 绘制控件 +├── XplorePlane.Tests/ # 单元测试 +└── ExternalLibraries/ # 外部 DLL 和 ONNX 模型 +``` + +### XplorePlane 主项目结构 + +``` +XplorePlane/ +├── App.xaml / App.xaml.cs # 应用入口 + DI 容器配置(AppBootstrapper) +├── Views/ +│ ├── Main/ +│ │ ├── MainWindow.xaml # 主窗口(Telerik Ribbon + 三栏布局) +│ │ ├── NavigationPropertyPanelView.xaml # 相机实时预览面板 +│ │ └── MotionControlPanelView.xaml # 运动控制面板 +│ ├── Cnc/ # CNC 编辑器 / 矩阵编排视图 +│ ├── ImageProcessing/ # 图像处理面板视图 +│ └── CameraSettingsWindow.xaml # 相机参数设置对话框 +├── ViewModels/ +│ ├── Main/ +│ │ ├── MainViewModel.cs # 主窗口 ViewModel +│ │ └── NavigationPropertyPanelViewModel.cs # 相机预览 ViewModel +│ ├── Cnc/ # CNC / 矩阵 ViewModel +│ └── ImageProcessing/ # 图像处理 / 流水线 ViewModel +├── Services/ +│ ├── AppState/ # 全局状态管理(线程安全) +│ ├── Camera/ # 相机服务 +│ ├── Cnc/ # CNC 程序服务 +│ ├── Matrix/ # 矩阵编排服务 +│ ├── Measurement/ # 测量数据服务 +│ ├── Pipeline/ # 流水线执行 / 持久化 +│ └── Recipe/ # 检测配方服务 +├── Models/ # 数据模型(State、CNC、Matrix、Pipeline 等) +├── Events/ # Prism 事件 +├── Libs/ +│ ├── Hardware/ # 硬件库 DLL(XP.Common、XP.Hardware.RaySource) +│ └── Native/ # 原生依赖库 +└── Assets/Icons/ # 工具栏图标 +``` + +### 相机集成 + +相机实时影像集成在主窗口左下角的 NavigationPropertyPanelView 中: + +- 连接/断开相机(Basler,通过 ICameraController) +- 开始/停止采集(软件触发模式) +- 实时预览(Live View,勾选"实时"复选框) +- 鼠标悬停显示像素坐标 +- 相机参数设置对话框(曝光时间、增益、分辨率、像素格式) +- 主界面 Ribbon 硬件栏提供"相机设置"快捷按钮 + +相机控制逻辑移植自 ImageProcessing 项目,使用 XP.Camera.PixelConverter 进行像素数据转换,通过 Application.Dispatcher.Invoke 保证 UI 线程安全。 + +### 依赖注入(DI) + +使用 Prism + DryIoc,在 AppBootstrapper.RegisterTypes() 中统一注册: + +- ICameraFactory / ICameraController / ICameraService(单例) +- IRaySourceService / IRaySourceFactory(单例) +- IAppStateService(单例,线程安全状态管理) +- NavigationPropertyPanelViewModel(单例,相机预览共享实例) +- 各 Service 和 ViewModel(按需注册) + +### 构建 + +```bash +# Debug +dotnet build XplorePlane.sln -c Debug + +# Release +dotnet build XplorePlane.sln -c Release +``` + +### TO-DO List + +- [x] 软件基于 WPF + Prism 基础的框架 +- [x] 日志库的引用(通过 XP.Common.dll) +- [x] 按推荐的 DLL 目录结构进行修改 +- [x] 通过库依赖的方式调用日志功能 +- [x] 界面的布局 +- [x] 相机实时影像集成(连接、采集、Live View、像素坐标显示) +- [x] 相机参数设置对话框(曝光、增益、分辨率、像素格式) +- [x] 主界面硬件栏相机设置按钮 +- [ ] 打通与硬件层的调用流程 +- [ ] 打通与图像层的调用流程 diff --git a/XP.Common/Helpers/ConfigLoader.cs b/XP.Common/Helpers/ConfigLoader.cs index dd70a1b..60d29ab 100644 --- a/XP.Common/Helpers/ConfigLoader.cs +++ b/XP.Common/Helpers/ConfigLoader.cs @@ -1,4 +1,4 @@ -using System.Configuration; +using System.Configuration; using XP.Common.Configs; using XP.Common.Dump.Configs; diff --git a/XP.Hardware.MotionControl/Services/MotionControlService.cs b/XP.Hardware.MotionControl/Services/MotionControlService.cs index a8de00a..af5af20 100644 --- a/XP.Hardware.MotionControl/Services/MotionControlService.cs +++ b/XP.Hardware.MotionControl/Services/MotionControlService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; diff --git a/XP.Hardware.PLC/Abstractions/IPlcClient.cs b/XP.Hardware.PLC/Abstractions/IPlcClient.cs index 6da338f..387ac5f 100644 --- a/XP.Hardware.PLC/Abstractions/IPlcClient.cs +++ b/XP.Hardware.PLC/Abstractions/IPlcClient.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/XP.Hardware.PLC/Services/PlcService.cs b/XP.Hardware.PLC/Services/PlcService.cs index d163de6..50d87c3 100644 --- a/XP.Hardware.PLC/Services/PlcService.cs +++ b/XP.Hardware.PLC/Services/PlcService.cs @@ -1,4 +1,4 @@ -using Prism.Mvvm; +using Prism.Mvvm; using System; using System.Collections.Generic; using System.Linq; diff --git a/XP.Hardware.RaySource/Module/RaySourceModule.cs b/XP.Hardware.RaySource/Module/RaySourceModule.cs index c9ef636..23c6545 100644 --- a/XP.Hardware.RaySource/Module/RaySourceModule.cs +++ b/XP.Hardware.RaySource/Module/RaySourceModule.cs @@ -1,4 +1,4 @@ -using Prism.Ioc; +using Prism.Ioc; using Prism.Modularity; using System.Resources; using XP.Common.Localization; diff --git a/XplorePlane/Services/ImageProcessing/ImageConverter.cs b/XplorePlane/Services/ImageProcessing/ImageConverter.cs index ed28a2b..539e7d1 100644 --- a/XplorePlane/Services/ImageProcessing/ImageConverter.cs +++ b/XplorePlane/Services/ImageProcessing/ImageConverter.cs @@ -28,11 +28,11 @@ namespace XplorePlane.Services var formatted = new FormatConvertedBitmap(bitmapSource, PixelFormats.Gray8, null, 0); int width = formatted.PixelWidth; int height = formatted.PixelHeight; - int stride = width; - byte[] pixels = new byte[height * stride]; - formatted.CopyPixels(pixels, stride, 0); var image = new Image(width, height); + int stride = image.Bytes.Length / height; + var pixels = new byte[height * stride]; + formatted.CopyPixels(pixels, stride, 0); image.Bytes = pixels; return image; } @@ -40,7 +40,19 @@ namespace XplorePlane.Services public static Image ToEmguCVFromPixels(byte[] pixels, int width, int height) { var image = new Image(width, height); - image.Bytes = pixels; + int required = image.Bytes.Length; + if (pixels.Length == required) + { + image.Bytes = pixels; + } + else + { + int stride = required / height; + var padded = new byte[required]; + for (int row = 0; row < height; row++) + Buffer.BlockCopy(pixels, row * width, padded, row * stride, width); + image.Bytes = padded; + } return image; } @@ -50,8 +62,8 @@ namespace XplorePlane.Services int width = emguImage.Width; int height = emguImage.Height; - int stride = width; byte[] pixels = emguImage.Bytes; + int stride = pixels.Length / height; return BitmapSource.Create(width, height, 96, 96, PixelFormats.Gray8, null, pixels, stride); }