行灰度功能添加
This commit is contained in:
@@ -25,4 +25,9 @@ namespace XplorePlane.Events
|
|||||||
/// 十字辅助线切换事件
|
/// 十字辅助线切换事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ToggleCrosshairEvent : PubSubEvent { }
|
public class ToggleCrosshairEvent : PubSubEvent { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 行灰度分布切换事件
|
||||||
|
/// </summary>
|
||||||
|
public class ToggleLineProfileEvent : PubSubEvent { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -961,8 +961,8 @@ namespace XplorePlane.ViewModels
|
|||||||
private void ExecuteGrayscale()
|
private void ExecuteGrayscale()
|
||||||
{
|
{
|
||||||
if (!CheckImageLoaded()) return;
|
if (!CheckImageLoaded()) return;
|
||||||
_logger.Info("Grayscale conversion triggered.");
|
_logger.Info("Line profile toggled.");
|
||||||
// TODO: 实现灰度转换逻辑
|
_eventAggregator.GetEvent<ToggleLineProfileEvent>().Publish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecuteSharpen()
|
private void ExecuteSharpen()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
@@ -128,8 +129,178 @@ namespace XplorePlane.Views
|
|||||||
var vm = GetMainVm();
|
var vm = GetMainVm();
|
||||||
if (vm != null) vm.CursorInfoText = RoiCanvas.CursorInfo;
|
if (vm != null) vm.CursorInfoText = RoiCanvas.CursorInfo;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 行灰度分布
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var ea2 = ContainerLocator.Current?.Resolve<Prism.Events.IEventAggregator>();
|
||||||
|
ea2?.GetEvent<ToggleLineProfileEvent>().Subscribe(() =>
|
||||||
|
{
|
||||||
|
ToggleLineProfile();
|
||||||
|
}, Prism.Events.ThreadOption.UIThread);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region 行灰度分布
|
||||||
|
|
||||||
|
private bool _lineProfileEnabled;
|
||||||
|
private System.Windows.Shapes.Line _profileRefLine; // 透明命中区域
|
||||||
|
private System.Windows.Shapes.Line _profileRefLineVisible; // 1px红线显示
|
||||||
|
private System.Windows.Shapes.Polyline _profileCurve;
|
||||||
|
private double _profileLineY;
|
||||||
|
private bool _profileDragging;
|
||||||
|
|
||||||
|
private void ToggleLineProfile()
|
||||||
|
{
|
||||||
|
_lineProfileEnabled = !_lineProfileEnabled;
|
||||||
|
var canvas = FindChildByName<System.Windows.Controls.Canvas>(RoiCanvas, "mainCanvas");
|
||||||
|
if (canvas == null) return;
|
||||||
|
|
||||||
|
if (_lineProfileEnabled)
|
||||||
|
{
|
||||||
|
// 参考线默认在图像中间
|
||||||
|
_profileLineY = RoiCanvas.CanvasHeight / 2;
|
||||||
|
|
||||||
|
// 创建参考线(红色水平线,可拖动)
|
||||||
|
// 用透明粗线作为命中区域,叠加1px红线显示
|
||||||
|
_profileRefLine = new System.Windows.Shapes.Line
|
||||||
|
{
|
||||||
|
X1 = 0,
|
||||||
|
Y1 = _profileLineY,
|
||||||
|
X2 = RoiCanvas.CanvasWidth,
|
||||||
|
Y2 = _profileLineY,
|
||||||
|
Stroke = System.Windows.Media.Brushes.Transparent,
|
||||||
|
StrokeThickness = 7, // 上下3px命中区域
|
||||||
|
IsHitTestVisible = true,
|
||||||
|
Cursor = System.Windows.Input.Cursors.SizeNS
|
||||||
|
};
|
||||||
|
_profileRefLineVisible = new System.Windows.Shapes.Line
|
||||||
|
{
|
||||||
|
X1 = 0,
|
||||||
|
Y1 = _profileLineY,
|
||||||
|
X2 = RoiCanvas.CanvasWidth,
|
||||||
|
Y2 = _profileLineY,
|
||||||
|
Stroke = System.Windows.Media.Brushes.Red,
|
||||||
|
StrokeThickness = 1,
|
||||||
|
IsHitTestVisible = false
|
||||||
|
};
|
||||||
|
_profileRefLine.MouseLeftButtonDown += ProfileLine_MouseDown;
|
||||||
|
_profileRefLine.MouseMove += ProfileLine_MouseMove;
|
||||||
|
_profileRefLine.MouseLeftButtonUp += ProfileLine_MouseUp;
|
||||||
|
canvas.Children.Add(_profileRefLineVisible);
|
||||||
|
canvas.Children.Add(_profileRefLine);
|
||||||
|
|
||||||
|
// 创建灰度折线(固定显示在图像中间位置)
|
||||||
|
_profileCurve = new System.Windows.Shapes.Polyline
|
||||||
|
{
|
||||||
|
Stroke = System.Windows.Media.Brushes.Red,
|
||||||
|
StrokeThickness = 1,
|
||||||
|
IsHitTestVisible = false
|
||||||
|
};
|
||||||
|
canvas.Children.Add(_profileCurve);
|
||||||
|
|
||||||
|
UpdateLineProfile();
|
||||||
|
SetStatus("行灰度分布:拖动红线改变采样行,再次点击按钮关闭");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_profileRefLine != null)
|
||||||
|
{
|
||||||
|
canvas.Children.Remove(_profileRefLine);
|
||||||
|
_profileRefLine = null;
|
||||||
|
}
|
||||||
|
if (_profileRefLineVisible != null)
|
||||||
|
{
|
||||||
|
canvas.Children.Remove(_profileRefLineVisible);
|
||||||
|
_profileRefLineVisible = null;
|
||||||
|
}
|
||||||
|
if (_profileCurve != null)
|
||||||
|
{
|
||||||
|
canvas.Children.Remove(_profileCurve);
|
||||||
|
_profileCurve = null;
|
||||||
|
}
|
||||||
|
SetStatus("行灰度分布已关闭");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProfileLine_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
_profileDragging = true;
|
||||||
|
_profileRefLine?.CaptureMouse();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProfileLine_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (!_profileDragging || _profileRefLine == null) return;
|
||||||
|
|
||||||
|
var canvas = FindChildByName<System.Windows.Controls.Canvas>(RoiCanvas, "mainCanvas");
|
||||||
|
if (canvas == null) return;
|
||||||
|
|
||||||
|
var pos = e.GetPosition(canvas);
|
||||||
|
_profileLineY = Math.Clamp(pos.Y, 0, RoiCanvas.CanvasHeight - 1);
|
||||||
|
|
||||||
|
_profileRefLine.Y1 = _profileLineY;
|
||||||
|
_profileRefLine.Y2 = _profileLineY;
|
||||||
|
_profileRefLineVisible.Y1 = _profileLineY;
|
||||||
|
_profileRefLineVisible.Y2 = _profileLineY;
|
||||||
|
|
||||||
|
UpdateLineProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProfileLine_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
_profileDragging = false;
|
||||||
|
_profileRefLine?.ReleaseMouseCapture();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLineProfile()
|
||||||
|
{
|
||||||
|
if (_profileCurve == null) return;
|
||||||
|
|
||||||
|
// 从当前显示图像获取像素数据
|
||||||
|
var viewportVm = DataContext as ViewportPanelViewModel;
|
||||||
|
var imageSource = viewportVm?.ImageSource as System.Windows.Media.Imaging.BitmapSource;
|
||||||
|
if (imageSource == null) return;
|
||||||
|
|
||||||
|
int imgWidth = imageSource.PixelWidth;
|
||||||
|
int imgHeight = imageSource.PixelHeight;
|
||||||
|
int row = (int)Math.Clamp(_profileLineY, 0, imgHeight - 1);
|
||||||
|
|
||||||
|
// 转为 Gray8 获取行像素
|
||||||
|
System.Windows.Media.Imaging.BitmapSource gray8;
|
||||||
|
if (imageSource.Format != System.Windows.Media.PixelFormats.Gray8)
|
||||||
|
gray8 = new System.Windows.Media.Imaging.FormatConvertedBitmap(
|
||||||
|
imageSource, System.Windows.Media.PixelFormats.Gray8, null, 0);
|
||||||
|
else
|
||||||
|
gray8 = imageSource;
|
||||||
|
|
||||||
|
byte[] rowPixels = new byte[imgWidth];
|
||||||
|
int stride = imgWidth;
|
||||||
|
gray8.CopyPixels(new System.Windows.Int32Rect(0, row, imgWidth, 1), rowPixels, stride, 0);
|
||||||
|
|
||||||
|
// 构建折线点集:折线固定显示在图像垂直中间位置
|
||||||
|
// 参考线位置决定采样哪一行,折线位置固定在画布中间
|
||||||
|
double canvasH = RoiCanvas.CanvasHeight;
|
||||||
|
double curveCenter = canvasH / 2.0; // 折线基线固定在图像中间
|
||||||
|
double displayHeight = canvasH * 0.25; // 折线振幅为画布高度的25%
|
||||||
|
|
||||||
|
var points = new System.Windows.Media.PointCollection(imgWidth);
|
||||||
|
for (int x = 0; x < imgWidth; x++)
|
||||||
|
{
|
||||||
|
double normalizedGray = rowPixels[x] / 255.0;
|
||||||
|
double y = curveCenter - normalizedGray * displayHeight;
|
||||||
|
points.Add(new System.Windows.Point(x, y));
|
||||||
|
}
|
||||||
|
_profileCurve.Points = points;
|
||||||
|
|
||||||
|
SetStatus($"行灰度分布 | Y={row} | 均值={rowPixels.Select(b => (double)b).Average():F1} | 最大={rowPixels.Max()} | 最小={rowPixels.Min()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.OldValue is INotifyPropertyChanged oldVm)
|
if (e.OldValue is INotifyPropertyChanged oldVm)
|
||||||
|
|||||||
Reference in New Issue
Block a user