diff --git a/XplorePlane/ViewModels/Main/MainViewModel.cs b/XplorePlane/ViewModels/Main/MainViewModel.cs index a61340f..945c18d 100644 --- a/XplorePlane/ViewModels/Main/MainViewModel.cs +++ b/XplorePlane/ViewModels/Main/MainViewModel.cs @@ -10,7 +10,10 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows; +using System.Windows.Media; using System.Windows.Media.Imaging; +using Emgu.CV; +using Emgu.CV.Structure; using XplorePlane.Events; using XplorePlane.Services.MainViewport; using XplorePlane.Services.Storage; @@ -116,6 +119,13 @@ namespace XplorePlane.ViewModels // 辅助线命令 public DelegateCommand ToggleCrosshairCommand { get; } + // 图像处理命令 + public DelegateCommand WhiteBackgroundDetectionCommand { get; } + public DelegateCommand BlackBackgroundDetectionCommand { get; } + public DelegateCommand GrayscaleCommand { get; } + public DelegateCommand SharpenCommand { get; } + public DelegateCommand EnhanceCommand { get; } + // 设置命令 public DelegateCommand OpenLanguageSwitcherCommand { get; } @@ -301,6 +311,13 @@ namespace XplorePlane.ViewModels ToggleCrosshairCommand = new DelegateCommand(() => _eventAggregator.GetEvent().Publish()); + // 图像处理命令 + WhiteBackgroundDetectionCommand = new DelegateCommand(ExecuteWhiteBackgroundDetection); + BlackBackgroundDetectionCommand = new DelegateCommand(ExecuteBlackBackgroundDetection); + GrayscaleCommand = new DelegateCommand(ExecuteGrayscale); + SharpenCommand = new DelegateCommand(ExecuteSharpen); + EnhanceCommand = new DelegateCommand(ExecuteEnhance); + AxisResetCommand = new DelegateCommand(ExecuteAxisReset); OpenDoorCommand = new DelegateCommand(ExecuteOpenDoor); CloseDoorCommand = new DelegateCommand(ExecuteCloseDoor); @@ -761,7 +778,7 @@ namespace XplorePlane.ViewModels if (viewportVm?.ImageSource != null) return true; } catch { } - HexMessageBox.Show("Please load an image first", MessageBoxButton.OK, MessageBoxImage.Information); + HexMessageBox.Show("Please load an image first!", MessageBoxButton.OK, MessageBoxImage.Information); return false; } @@ -862,6 +879,150 @@ namespace XplorePlane.ViewModels _bubbleMeasurePanel.Show(); } + private void ExecuteWhiteBackgroundDetection() + { + if (!CheckImageLoaded()) return; + _logger.Info("White background detection triggered."); + // TODO: 实现白底检测逻辑 + } + + private void ExecuteBlackBackgroundDetection() + { + if (!CheckImageLoaded()) return; + _logger.Info("Black background detection triggered."); + // TODO: 实现黑底检测逻辑 + } + + private void ExecuteGrayscale() + { + if (!CheckImageLoaded()) return; + _logger.Info("Grayscale conversion triggered."); + // TODO: 实现灰度转换逻辑 + } + + private void ExecuteSharpen() + { + if (!CheckImageLoaded()) return; + _logger.Info("Sharpen triggered."); + + try + { + var viewportVm = _containerProvider.Resolve(); + var imageSource = viewportVm?.ImageSource as BitmapSource; + if (imageSource == null) return; + + var inputImage = BitmapSourceToImage(imageSource); + if (inputImage == null) return; + + var processor = new XP.ImageProcessing.Processors.SharpenProcessor(); + processor.SetParameter("Method", "UnsharpMask"); + processor.SetParameter("Strength", 0.2); + processor.SetParameter("KernelSize", 3); + + var result = processor.Process(inputImage); + var resultBitmap = ImageToBitmapSource(result); + + _mainViewportService.SetManualImage(resultBitmap, "Sharpen"); + + inputImage.Dispose(); + result.Dispose(); + + _logger.Info("Sharpen completed."); + } + catch (Exception ex) + { + _logger.Error(ex, "Sharpen failed."); + HexMessageBox.Show($"Sharpen failed: {ex.Message}", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + private void ExecuteEnhance() + { + if (!CheckImageLoaded()) return; + _logger.Info("Enhance triggered."); + + try + { + var viewportVm = _containerProvider.Resolve(); + var imageSource = viewportVm?.ImageSource as BitmapSource; + if (imageSource == null) return; + + var inputImage = BitmapSourceToImage(imageSource); + if (inputImage == null) return; + + var processor = new XP.ImageProcessing.Processors.HistogramEqualizationProcessor(); + + var result = processor.Process(inputImage); + var resultBitmap = ImageToBitmapSource(result); + + _mainViewportService.SetManualImage(resultBitmap, "Enhance"); + + inputImage.Dispose(); + result.Dispose(); + + _logger.Info("Enhance completed."); + } + catch (Exception ex) + { + _logger.Error(ex, "Enhance failed."); + HexMessageBox.Show($"Enhance failed: {ex.Message}", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + private Image? BitmapSourceToImage(BitmapSource bitmapSource) + { + // 转换为可用的图像格式 + BitmapSource source = bitmapSource; + + // 如果不是 Gray8 格式,转换为 Gray8 + if (bitmapSource.Format != PixelFormats.Gray8) + { + source = new FormatConvertedBitmap(bitmapSource, PixelFormats.Gray8, null, 0); + } + + // 获取原始像素数据 + int width = source.PixelWidth; + int height = source.PixelHeight; + int stride = width; // Gray8 每个像素 1 字节 + byte[] pixels = new byte[width * height]; + source.CopyPixels(pixels, stride, 0); + + // 创建 Emgu CV Image + var image = new Image(width, height); + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + image.Data[y, x, 0] = pixels[y * stride + x]; + } + } + + return image; + } + + private BitmapSource ImageToBitmapSource(Image image) + { + int width = image.Width; + int height = image.Height; + int stride = width; + byte[] pixels = new byte[width * height]; + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + pixels[y * stride + x] = image.Data[y, x, 0]; + } + } + + var bitmapSource = BitmapSource.Create( + width, height, 96, 96, + PixelFormats.Gray8, null, pixels, stride); + + bitmapSource.Freeze(); + return bitmapSource; + } + private void ExecuteOpenLanguageSwitcher() { try diff --git a/XplorePlane/Views/Main/MainWindow.xaml b/XplorePlane/Views/Main/MainWindow.xaml index 7f8e53f..7a110f8 100644 --- a/XplorePlane/Views/Main/MainWindow.xaml +++ b/XplorePlane/Views/Main/MainWindow.xaml @@ -167,6 +167,7 @@ Text="辅助线" /> @@ -174,11 +175,13 @@ @@ -186,11 +189,13 @@