feat: 实现快捷工具栏白底检测功能

This commit is contained in:
李伟
2026-05-14 15:54:15 +08:00
parent 5960f28bcf
commit 1fb789190c
3 changed files with 313 additions and 2 deletions
@@ -138,6 +138,26 @@ namespace XplorePlane.Views
{
ToggleLineProfile();
}, Prism.Events.ThreadOption.UIThread);
// 白底检测:进入ROI绘制模式
ea2?.GetEvent<WhiteBackgroundDetectionEvent>().Subscribe(() =>
{
_whiteDetectDrawing = false;
_whiteDetectMode = true;
// 注册鼠标事件(只注册一次)
RoiCanvas.PreviewMouseLeftButtonDown -= OnMainCanvasPreviewMouseDown;
RoiCanvas.PreviewMouseLeftButtonDown += OnMainCanvasPreviewMouseDown;
RoiCanvas.PreviewMouseMove -= OnMainCanvasPreviewMouseMove;
RoiCanvas.PreviewMouseMove += OnMainCanvasPreviewMouseMove;
RoiCanvas.PreviewMouseLeftButtonUp -= OnMainCanvasPreviewMouseUp;
RoiCanvas.PreviewMouseLeftButtonUp += OnMainCanvasPreviewMouseUp;
}, Prism.Events.ThreadOption.UIThread);
// 白底检测:渲染结果
ea2?.GetEvent<WhiteBackgroundResultEvent>().Subscribe(payload =>
{
RenderWhiteBackgroundResult(payload);
}, Prism.Events.ThreadOption.UIThread);
}
catch { }
}
@@ -380,6 +400,175 @@ namespace XplorePlane.Views
#endregion
#region
private bool _whiteDetectMode;
private bool _whiteDetectDrawing;
private System.Windows.Point _whiteDetectStart;
private System.Windows.Shapes.Rectangle _whiteDetectPreview;
private readonly System.Collections.Generic.List<System.Windows.UIElement> _whiteDetectOverlays = new();
// 需要在 mainCanvas 的 MouseDown/Move/Up 中处理
// 由于 PolygonRoiCanvas 内部已经处理了鼠标事件,我们通过 PreviewMouse 事件来拦截
private void OnMainCanvasPreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (!_whiteDetectMode || e.LeftButton != System.Windows.Input.MouseButtonState.Pressed) return;
var canvas = FindChildByName<System.Windows.Controls.Canvas>(RoiCanvas, "mainCanvas");
if (canvas == null) return;
_whiteDetectStart = e.GetPosition(canvas);
_whiteDetectDrawing = true;
// 创建预览矩形(不清除之前的检测结果)
_whiteDetectPreview = new System.Windows.Shapes.Rectangle
{
Stroke = System.Windows.Media.Brushes.Blue,
StrokeThickness = 1,
StrokeDashArray = new System.Windows.Media.DoubleCollection { 4, 2 }
};
System.Windows.Controls.Canvas.SetLeft(_whiteDetectPreview, _whiteDetectStart.X);
System.Windows.Controls.Canvas.SetTop(_whiteDetectPreview, _whiteDetectStart.Y);
canvas.Children.Add(_whiteDetectPreview);
RoiCanvas.CaptureMouse();
e.Handled = true;
}
private void OnMainCanvasPreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (!_whiteDetectDrawing || _whiteDetectPreview == null) return;
var canvas = FindChildByName<System.Windows.Controls.Canvas>(RoiCanvas, "mainCanvas");
if (canvas == null) return;
var current = e.GetPosition(canvas);
double x = Math.Min(_whiteDetectStart.X, current.X);
double y = Math.Min(_whiteDetectStart.Y, current.Y);
double w = Math.Abs(current.X - _whiteDetectStart.X);
double h = Math.Abs(current.Y - _whiteDetectStart.Y);
System.Windows.Controls.Canvas.SetLeft(_whiteDetectPreview, x);
System.Windows.Controls.Canvas.SetTop(_whiteDetectPreview, y);
_whiteDetectPreview.Width = Math.Max(1, w);
_whiteDetectPreview.Height = Math.Max(1, h);
}
private void OnMainCanvasPreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (!_whiteDetectDrawing) return;
_whiteDetectDrawing = false;
_whiteDetectMode = false;
RoiCanvas.ReleaseMouseCapture();
var canvas = FindChildByName<System.Windows.Controls.Canvas>(RoiCanvas, "mainCanvas");
if (canvas == null) return;
var end = e.GetPosition(canvas);
int x = (int)Math.Min(_whiteDetectStart.X, end.X);
int y = (int)Math.Min(_whiteDetectStart.Y, end.Y);
int w = (int)Math.Abs(end.X - _whiteDetectStart.X);
int h = (int)Math.Abs(end.Y - _whiteDetectStart.Y);
// 移除预览矩形
if (_whiteDetectPreview != null)
{
canvas.Children.Remove(_whiteDetectPreview);
_whiteDetectPreview = null;
}
if (w < 10 || h < 10) return; // 太小忽略
// 发布ROI绘制完成事件
try
{
var ea = ContainerLocator.Current?.Resolve<Prism.Events.IEventAggregator>();
ea?.GetEvent<WhiteBackgroundRoiDrawnEvent>().Publish(new System.Windows.Int32Rect(x, y, w, h));
}
catch { }
e.Handled = true;
}
private void RenderWhiteBackgroundResult(WhiteBackgroundResultPayload payload)
{
var canvas = FindChildByName<System.Windows.Controls.Canvas>(RoiCanvas, "mainCanvas");
if (canvas == null || payload?.Detections == null) return;
// 绘制ROI矩形(蓝色实线)
var roiRect = new System.Windows.Shapes.Rectangle
{
Stroke = System.Windows.Media.Brushes.Blue,
StrokeThickness = 1,
Width = payload.RoiRect.Width,
Height = payload.RoiRect.Height,
IsHitTestVisible = false
};
System.Windows.Controls.Canvas.SetLeft(roiRect, payload.RoiRect.X);
System.Windows.Controls.Canvas.SetTop(roiRect, payload.RoiRect.Y);
canvas.Children.Add(roiRect);
_whiteDetectOverlays.Add(roiRect);
// 绘制每个检测到的黑色区域
foreach (var (center, radius, sizeMm) in payload.Detections)
{
// 红色虚线圆
var circle = new System.Windows.Shapes.Ellipse
{
Stroke = System.Windows.Media.Brushes.Red,
StrokeThickness = 1,
StrokeDashArray = new System.Windows.Media.DoubleCollection { 4, 2 },
Width = radius * 2,
Height = radius * 2,
IsHitTestVisible = false
};
System.Windows.Controls.Canvas.SetLeft(circle, center.X - radius);
System.Windows.Controls.Canvas.SetTop(circle, center.Y - radius);
canvas.Children.Add(circle);
_whiteDetectOverlays.Add(circle);
// 45°直径标注线(从圆心向左上到右下)
double offset = radius * 0.707; // cos(45°) * radius
var diamLine = new System.Windows.Shapes.Line
{
X1 = center.X - offset,
Y1 = center.Y - offset,
X2 = center.X + offset,
Y2 = center.Y + offset,
Stroke = System.Windows.Media.Brushes.Red,
StrokeThickness = 1,
IsHitTestVisible = false
};
canvas.Children.Add(diamLine);
_whiteDetectOverlays.Add(diamLine);
// 尺寸标注(在斜线右上方)
string label = sizeMm >= 1000 ? $"{sizeMm / 1000:F2} mm" : $"{sizeMm:F0} μm";
var text = new System.Windows.Controls.TextBlock
{
Text = label,
Foreground = System.Windows.Media.Brushes.Red,
FontSize = 11,
IsHitTestVisible = false
};
System.Windows.Controls.Canvas.SetLeft(text, center.X + offset + 3);
System.Windows.Controls.Canvas.SetTop(text, center.Y - offset - 14);
canvas.Children.Add(text);
_whiteDetectOverlays.Add(text);
}
}
private void ClearWhiteDetectOverlays(System.Windows.Controls.Canvas canvas)
{
foreach (var el in _whiteDetectOverlays)
canvas.Children.Remove(el);
_whiteDetectOverlays.Clear();
}
#endregion
private static T FindChildByName<T>(DependencyObject parent, string name) where T : FrameworkElement
{
int count = VisualTreeHelper.GetChildrenCount(parent);