diff --git a/XplorePlane/Services/ImageConverter.cs b/XplorePlane/Services/ImageConverter.cs index 1e22b09..416e1e1 100644 --- a/XplorePlane/Services/ImageConverter.cs +++ b/XplorePlane/Services/ImageConverter.cs @@ -10,6 +10,19 @@ namespace XplorePlane.Services { public static class ImageConverter { + public static byte[] ExtractGray8Pixels(BitmapSource bitmapSource, out int width, out int height) + { + if (bitmapSource == null) throw new ArgumentNullException(nameof(bitmapSource)); + + var formatted = new FormatConvertedBitmap(bitmapSource, PixelFormats.Gray8, null, 0); + width = formatted.PixelWidth; + height = formatted.PixelHeight; + int stride = width; + byte[] pixels = new byte[height * stride]; + formatted.CopyPixels(pixels, stride, 0); + return pixels; + } + public static Image ToEmguCV(BitmapSource bitmapSource) { if (bitmapSource == null) throw new ArgumentNullException(nameof(bitmapSource)); @@ -26,6 +39,13 @@ namespace XplorePlane.Services return image; } + public static Image ToEmguCVFromPixels(byte[] pixels, int width, int height) + { + var image = new Image(width, height); + image.Bytes = pixels; + return image; + } + public static BitmapSource ToBitmapSource(Image emguImage) { if (emguImage == null) throw new ArgumentNullException(nameof(emguImage)); diff --git a/XplorePlane/Services/ImageProcessingService.cs b/XplorePlane/Services/ImageProcessingService.cs index c7f2799..18bba8d 100644 --- a/XplorePlane/Services/ImageProcessingService.cs +++ b/XplorePlane/Services/ImageProcessingService.cs @@ -99,13 +99,16 @@ namespace XplorePlane.Services if (!_processorRegistry.TryGetValue(processorName, out var processor)) throw new ArgumentException($"Processor not registered: {processorName}", nameof(processorName)); + // Extract pixels on the UI thread (BitmapSource / FormatConvertedBitmap are DependencyObjects) + var rawPixels = ImageConverter.ExtractGray8Pixels(source, out int imgWidth, out int imgHeight); + return await Task.Run(() => { cancellationToken.ThrowIfCancellationRequested(); try { - var emguImage = ImageConverter.ToEmguCV(source); + var emguImage = ImageConverter.ToEmguCVFromPixels(rawPixels, imgWidth, imgHeight); if (parameters != null) { @@ -118,6 +121,7 @@ namespace XplorePlane.Services progress?.Report(0.9); var result = ImageConverter.ToBitmapSource(processedEmgu); + result.Freeze(); // must freeze before crossing thread boundary progress?.Report(1.0); return result; diff --git a/XplorePlane/ViewModels/ImageProcessingViewModel.cs b/XplorePlane/ViewModels/ImageProcessingViewModel.cs index 1a4078d..09722b8 100644 --- a/XplorePlane/ViewModels/ImageProcessingViewModel.cs +++ b/XplorePlane/ViewModels/ImageProcessingViewModel.cs @@ -111,7 +111,6 @@ namespace XplorePlane.ViewModels try { - SelectedProcessor = processorName; var parameters = _imageProcessingService.GetProcessorParameters(processorName); CurrentParameters.Clear(); foreach (var param in parameters)