修复CNC结束时导航合成截图归档
This commit is contained in:
@@ -7,7 +7,11 @@ XplorePlane 系统用于控制平面 CT 设备的各个子系统(射线源、
|
||||
### 总体架构
|
||||
|
||||
- 客户端框架: WPF + Prism MVVM(目标框架 net8.0-windows)
|
||||
- 图像处理内核: ImageProcessing.Core(算子基类)+ ImageProcessing.Processors(具体算子),基于 EmguCV
|
||||
- 图像处理内核: `XP.ImageProcessing.Processors`,基于 Emgu.CV
|
||||
- `Core/`:包含 `ImageProcessorBase`、`ProcessorParameter` 及 ROI/对齐等核心模型和算子基类
|
||||
- 各功能目录:包含图像变换、滤波、增强、边缘检测、检测分析和模板匹配等具体算子
|
||||
- `ImageProcessingService`:负责算子程序集扫描、反射发现、注册及执行
|
||||
- 统一使用 16 位图像处理通道,并通过适配器兼容 8 位算子
|
||||
- 相机控制: XP.Camera(Basler pylon SDK 封装,支持软件触发、参数读写)
|
||||
- 硬件抽象: XP.Common + XP.Hardware.RaySource(射线源控制)
|
||||
- 日志: Serilog
|
||||
@@ -27,11 +31,15 @@ XplorePlane.sln
|
||||
├── XP.Hardware.RaySource/ # 射线源控制模块
|
||||
├── XP.Hardware.RaySource.Comet.Host/ # Comet 射线源独立 Host 进程
|
||||
├── XP.Hardware.RaySource.Comet.Messages/# Comet Host 通信消息定义
|
||||
├── XP.ImageProcessing.Core/ # 图像处理算子基类与核心模型
|
||||
├── XP.ImageProcessing.Processors/ # 具体图像处理算子实现
|
||||
├── XP.ImageProcessing.CfgControl/ # 图像处理配置控件
|
||||
├── XP.ImageProcessing.RoiControl/ # ROI 绘制与测量控件
|
||||
├── XP.ImageProcessing.SmokeTest/ # 图像处理冒烟测试程序
|
||||
├── XP.ImageProcessing.Processors/ # 图像处理核心与具体算子实现
|
||||
│ ├── Core/ # 算子基类、参数模型、ROI/对齐模型
|
||||
│ ├── 图像变换/ # 灰度、旋转、镜像、阈值等
|
||||
│ ├── 滤波处理/ # 滤波算子
|
||||
│ ├── 图像增强/ # 增强算子
|
||||
│ ├── 边缘检测/ # 边缘检测算子
|
||||
│ ├── 检测分析/ # BGA、QFN、空洞率及测量算子
|
||||
│ └── 定位识别/ # 模板匹配和定位算子
|
||||
├── XP.ImageProcessing.RoiControl/ # ROI 绘制与测量控件
|
||||
├── XP.Scan/ # 扫描模式相关模块
|
||||
├── XP.Calibration/ # 校准模块
|
||||
├── XP.ReportEngine/ # 报告生成模块
|
||||
|
||||
@@ -779,10 +779,19 @@ namespace XplorePlane.Services.Cnc
|
||||
/// 注意:与 HomeAll()(机械回零,驱动轴到机械零点建立坐标系)不同,MoveToSafePosition 是移动到用户配置的坐标。
|
||||
/// 运动服务不可用时优雅降级(仿真模式直接返回)。
|
||||
/// </summary>
|
||||
private BitmapSource GetInspectionMapOverviewImage(BitmapSource fallbackImage)
|
||||
{
|
||||
if (_navigationFrameProvider?.TryGetLatestBitmapSource(out var navigationOverview) == true)
|
||||
{
|
||||
private BitmapSource GetInspectionMapOverviewImage(BitmapSource fallbackImage)
|
||||
{
|
||||
if (_navigationFrameProvider?.TryCaptureCompositeBitmapSource(out var compositeOverview) == true)
|
||||
{
|
||||
_logger.ForModule<CncExecutionService>().Info(
|
||||
"检查标记图 overview 使用导航窗体合成截图:{0}x{1}",
|
||||
compositeOverview.PixelWidth,
|
||||
compositeOverview.PixelHeight);
|
||||
return compositeOverview;
|
||||
}
|
||||
|
||||
if (_navigationFrameProvider?.TryGetLatestBitmapSource(out var navigationOverview) == true)
|
||||
{
|
||||
_logger.ForModule<CncExecutionService>().Info(
|
||||
"检查标记图 overview 使用导航相机大视野图:{0}x{1}",
|
||||
navigationOverview.PixelWidth,
|
||||
|
||||
@@ -10,8 +10,14 @@ namespace XplorePlane.Services.Hardware.Camera
|
||||
|
||||
void UpdateFrame(byte[] pixelData, int width, int height, string pixelFormat);
|
||||
void UpdateFrame(BitmapSource bitmap);
|
||||
|
||||
bool TryGetLatestBitmapSource(out BitmapSource bitmap);
|
||||
|
||||
/// <summary>注册导航窗体的合成截图回调(相机图像 + 标记叠加层)。</summary>
|
||||
void SetCompositeCapture(Func<BitmapSource> capture);
|
||||
|
||||
/// <summary>获取导航窗体当前实际渲染的合成图像。</summary>
|
||||
bool TryCaptureCompositeBitmapSource(out BitmapSource bitmap);
|
||||
|
||||
bool TryGetLatestBitmapSource(out BitmapSource bitmap);
|
||||
}
|
||||
|
||||
/// <summary>导航摄像头帧提供器</summary>
|
||||
@@ -26,8 +32,37 @@ namespace XplorePlane.Services.Hardware.Camera
|
||||
private int _height;
|
||||
private string _pixelFormat = string.Empty;
|
||||
private BitmapSource _bitmap;
|
||||
private Func<BitmapSource> _compositeCapture;
|
||||
|
||||
public DateTime? LatestCapturedAtUtc { get; private set; }
|
||||
public DateTime? LatestCapturedAtUtc { get; private set; }
|
||||
|
||||
public void SetCompositeCapture(Func<BitmapSource> capture)
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
_compositeCapture = capture;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryCaptureCompositeBitmapSource(out BitmapSource bitmap)
|
||||
{
|
||||
Func<BitmapSource> capture;
|
||||
lock (_syncRoot)
|
||||
{
|
||||
capture = _compositeCapture;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bitmap = capture?.Invoke();
|
||||
return bitmap != null && bitmap.PixelWidth > 0 && bitmap.PixelHeight > 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
bitmap = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateFrame(byte[] pixelData, int width, int height, string pixelFormat)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using XplorePlane.Services.Hardware.Camera;
|
||||
using XplorePlane.Services.Hardware.Coordinate;
|
||||
using XplorePlane.Views.Main.Overlays;
|
||||
|
||||
@@ -54,6 +55,17 @@ namespace XplorePlane.Views.Main
|
||||
ResolveViewModel();
|
||||
AttachMarkOverlay();
|
||||
|
||||
// 将导航窗体实际渲染结果注册给 CNC 归档服务,包含标记叠加层。
|
||||
try
|
||||
{
|
||||
var frameProvider = AppBootstrapper.Instance?.Container.Resolve<INavigationCameraFrameProvider>();
|
||||
frameProvider?.SetCompositeCapture(CaptureCompositeImage);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_diag.Warning(ex, "注册导航合成截图回调失败");
|
||||
}
|
||||
|
||||
// 订阅 ViewModel 属性变化,驱动红十字线位置更新
|
||||
if (_viewModel != null)
|
||||
{
|
||||
@@ -71,6 +83,9 @@ namespace XplorePlane.Views.Main
|
||||
/// </summary>
|
||||
private BitmapSource? CaptureCompositeImage()
|
||||
{
|
||||
if (!Dispatcher.CheckAccess())
|
||||
return Dispatcher.Invoke(CaptureCompositeImage);
|
||||
|
||||
var target = cameraDisplayHost;
|
||||
if (target == null)
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user