From 93bcc6c6924ef3d20202371663af113d6b67cff8 Mon Sep 17 00:00:00 2001 From: Alek-ban Date: Tue, 14 Apr 2026 22:30:26 +0300 Subject: [PATCH] feat: SampleCalibration View and ViewModel --- .../Behaviors/GridColumnHideBehavior.cs | 4 +- GSS2.UI.Core/Converters/DateTimeConverter.cs | 47 + GSS2.UI.Core/OpenCvImage.cs | 5 - .../AmineContentCalibrationViewModel.cs | 343 ------- ...ineContentSeparatorCalibrationViewModel.cs | 345 ------- .../ViewModels/AsyncImageViewModel.cs | 3 +- ...AmineContentSeparatorCalibrationView.axaml | 598 ------------- ...neContentSeparatorCalibrationView.axaml.cs | 11 - .../SampleCalibrationViewModel.cs | 650 +++++++++++++- .../AmineContent/SampleCalibrationView.axaml | 846 +++++++++++++++++- .../SeparatorCalibrationView.axaml | 1 - 11 files changed, 1543 insertions(+), 1310 deletions(-) create mode 100644 GSS2.UI.Core/Converters/DateTimeConverter.cs delete mode 100644 GSS2.UI.Core/ViewModels/AmineContentCalibrationViewModel.cs delete mode 100644 GSS2.UI.Core/ViewModels/AmineContentSeparatorCalibrationViewModel.cs delete mode 100644 GSS2.UI.Core/Views/AmineContentSeparatorCalibrationView.axaml delete mode 100644 GSS2.UI.Core/Views/AmineContentSeparatorCalibrationView.axaml.cs diff --git a/GSS2.UI.Core/Behaviors/GridColumnHideBehavior.cs b/GSS2.UI.Core/Behaviors/GridColumnHideBehavior.cs index ed027d1..e5a4461 100644 --- a/GSS2.UI.Core/Behaviors/GridColumnHideBehavior.cs +++ b/GSS2.UI.Core/Behaviors/GridColumnHideBehavior.cs @@ -1,4 +1,4 @@ -// Оригинальное решение для проблеммы сворачивания колнок в Grid от +// Оригинальное решение для проблемы сворачивания колонок в Grid от // https://github.com/AvaloniaUI/Avalonia/discussions/6773#discussioncomment-1514604 using Avalonia; @@ -39,4 +39,4 @@ public static class GridColumnHideBehavior { columnDefinition.SetValue(IsVisibleProperty, visibility); } -} \ No newline at end of file +} diff --git a/GSS2.UI.Core/Converters/DateTimeConverter.cs b/GSS2.UI.Core/Converters/DateTimeConverter.cs new file mode 100644 index 0000000..a21ffde --- /dev/null +++ b/GSS2.UI.Core/Converters/DateTimeConverter.cs @@ -0,0 +1,47 @@ +using System.Globalization; + +using Avalonia.Data.Converters; + +namespace GSS2.UI.Core.Converters; + +public class DateTimeConverter : IValueConverter +{ + private static readonly string[][] FORMATS = + { + ["dd", "d"], + ["."], + ["MM", "M"], + ["."], + ["yyyy", "yy"], + [" "], + ["HH", "H"], + [":"], + ["mm", "m"], + [":"], + ["ss", "s"] + }; + private static readonly string[] ALL_FORMATS = FORMATS + .Aggregate(new List { "" }, (acc, segments) => + acc.SelectMany(a => segments.Select(s => a + s)).ToList()) + .ToArray(); + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is not DateTime dateTime) + return Avalonia.Data.BindingNotification.ExtractError(new FormatException($"Не удаётся распознать значение \"{value}\" как дату и время")); + + return dateTime.ToLocalTime().ToString("dd.MM.yyyy HH:mm:ss"); + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is not string str) + return Avalonia.Data.BindingNotification.ExtractError(new FormatException($"Не удаётся распознать значение \"{value}\" как дату и время")); + + var success = DateTime.TryParseExact(str, ALL_FORMATS, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var dateTime); + if (!success) + return Avalonia.Data.BindingNotification.ExtractError(new FormatException($"Не удаётся распознать строку \"{str}\" как дату и время")); + + return dateTime.ToUniversalTime(); + } +} diff --git a/GSS2.UI.Core/OpenCvImage.cs b/GSS2.UI.Core/OpenCvImage.cs index 9122831..c5b1bbc 100644 --- a/GSS2.UI.Core/OpenCvImage.cs +++ b/GSS2.UI.Core/OpenCvImage.cs @@ -1,14 +1,9 @@ using Avalonia; -using Avalonia.Media; -using Avalonia.Input; -using Avalonia.Controls; using Avalonia.Media.Imaging; using Mat = OpenCvSharp.Mat; using Cv2 = OpenCvSharp.Cv2; -using GSS2.Core.Extentions; - namespace GSS2.UI.Core; public class OpenCvImage : ZoomPanImage diff --git a/GSS2.UI.Core/ViewModels/AmineContentCalibrationViewModel.cs b/GSS2.UI.Core/ViewModels/AmineContentCalibrationViewModel.cs deleted file mode 100644 index 14bc72e..0000000 --- a/GSS2.UI.Core/ViewModels/AmineContentCalibrationViewModel.cs +++ /dev/null @@ -1,343 +0,0 @@ -using System.Collections.Specialized; -using System.Collections.ObjectModel; - -using Microsoft.Extensions.Logging; - -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; - -using Avalonia.Media; -using Avalonia.Media.Imaging; -using Avalonia.Threading; - -using GSS2.Core.Hardware; -using GSS2.Core.Extentions; -using GSS2.Core.Analysis.AmineContent.Database.Calibration; - -namespace GSS2.UI.Core.ViewModels; - -public partial class AmineContentCalibrationViewModel : ViewModelBase -{ - private readonly ILogger _logger; - private readonly AmineContentCalibrationContext _context; - private readonly IlluminatorService _illuminatorService; - private readonly CameraService _cameraService; - private readonly ImageStorageService _imageStorageService; - - private CancellationTokenSource? _captureImagesTaskCts = null; - - [ObservableProperty] private ObservableCollection _records; - [ObservableProperty] private CalibrationRecord _currentRecord; - [ObservableProperty] private bool _isMenuOpen = false; - [ObservableProperty] private bool _isNewRecord = false; - - [ObservableProperty] private int _mainSectionsCurrentIndex = 0; - [ObservableProperty] private string _switchMainSectionButtonText = "К изображениям"; - - [ObservableProperty] private int _imageTypeSectionCurrentIndex = 0; - [ObservableProperty] private string _switchImageTypeSectionButtonText = "К изображениям пробы"; - - [ObservableProperty] private Task? _captureImagesTask = null; - - [ObservableProperty] private ObservableCollection> _separatorImages = new(); - [ObservableProperty] private bool _separatorImagesIsCapturing = false; - [ObservableProperty] private string _separatorImagesCapturingProgress = ""; - [ObservableProperty] private int _separatorImagesSectionCurrentIndex = 0; - [ObservableProperty] private bool _separatorImagesSectionCanScrollForward = false; - [ObservableProperty] private bool _separatorImagesSectionCanScrollBackward = false; - - [ObservableProperty] private ObservableCollection> _sampleImages = new(); - [ObservableProperty] private bool _sampleImagesIsCapturing = false; - [ObservableProperty] private string _sampleImagesCapturingProgress = ""; - [ObservableProperty] private int _sampleImagesSectionCurrentIndex = 0; - [ObservableProperty] private bool _sampleImagesSectionCanScrollForward = false; - [ObservableProperty] private bool _sampleImagesSectionCanScrollBackward = false; - - public AmineContentCalibrationViewModel(ILogger logger, AmineContentCalibrationContext context, IlluminatorService illuminatorService, CameraService cameraService, ImageStorageService imageStorageService) - { - _logger = logger; - _logger.LogInformation("Initialization"); - - _context = context; - _illuminatorService = illuminatorService; - _cameraService = cameraService; - _imageStorageService = imageStorageService; - - Records = new ObservableCollection(_context.CalibrationRecords); - - if (Records.Count() > 0) - CurrentRecord = Records.First(); - else - { - CurrentRecord = new CalibrationRecord() - { - SampleName = null, - SampleComment = null, - SampleBrand = null, - SampleMass = null, - SamplingDateTime = null, - SamplingPlace = null, - MixtureName = null, - MixtureAmineContent = null, - MixtureNormalRate = null, - MixtureActualRate = null, - SampleImages = new List(), - SeparatorImages = new List() - }; - IsNewRecord = true; - } - - _logger.LogInformation("Initialized"); - } - - partial void OnRecordsChanged(ObservableCollection? oldValue, ObservableCollection newValue) - { - oldValue?.CollectionChanged -= OnRecordsCollectionChanged; - newValue?.CollectionChanged += OnRecordsCollectionChanged; - } - partial void OnCurrentRecordChanged(CalibrationRecord value) - { - SeparatorImages = new( - value.SeparatorImages - .Select(i => new KeyValuePair(_imageStorageService.GetFullPath(i.ImagePath, "calibration"), i)) - .Select(kv => new KeyValuePair(new Bitmap(kv.Key), kv.Value)) - ); - - SampleImages = new( - value.SampleImages - .Select(i => new KeyValuePair(_imageStorageService.GetFullPath(i.ImagePath, "calibration"), i)) - .Select(kv => new KeyValuePair(new Bitmap(kv.Key), kv.Value)) - ); - } - - private void OnRecordsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs ea) - { - Console.WriteLine($"RecordsCollectionChanged {ea.Action}"); - } - - [RelayCommand] private void ToggleMenu() => IsMenuOpen = !IsMenuOpen; - [RelayCommand] private void CloseMenu() => IsMenuOpen = false; - - [RelayCommand] - private void CreateRecord() - { - var record = new CalibrationRecord() - { - SampleName = null, - SampleComment = null, - SampleBrand = null, - SampleMass = null, - SamplingDateTime = null, - SamplingPlace = null, - MixtureName = null, - MixtureAmineContent = null, - MixtureNormalRate = null, - MixtureActualRate = null, - SampleImages = new List(), - SeparatorImages = new List() - }; - CurrentRecord = record; - IsNewRecord = true; - } - - // [RelayCommand] - // private void DeleteRecord() - // { - // //TODO - // // if (Record == null) return; - - // // _context.CalibrationRecords.Remove(Record); - // // Records.Remove(Record); - // // if (Records.Count() > 0) - // // Record = Records.First(); - // // else - // // { - // // var record = new CalibrationRecord(); - // // _context.CalibrationRecords.Add(record); - // // Records.Add(record); - // // Record = record; - // // } - // IsNewRecord = true; - // CreateRecord(); - // } - - // [RelayCommand] - // private void SaveRecord() - // { - // //TODO - // // _context.SaveChanges(); - // IsNewRecord = false; - // } - - [RelayCommand] - private void SwitchMainSection() - { - MainSectionsCurrentIndex = MainSectionsCurrentIndex == 0 ? 1 : 0; - SwitchMainSectionButtonText = MainSectionsCurrentIndex == 0 ? - "К изображениям" : - "К общей информации"; - } - - [RelayCommand] - private void SwitchImageTypeSection() - { - ImageTypeSectionCurrentIndex = ImageTypeSectionCurrentIndex == 0 ? 1 : 0; - SwitchImageTypeSectionButtonText = ImageTypeSectionCurrentIndex == 0 ? - "К изображениям пробы" : - "К изображениям сепаратора"; - } - - [RelayCommand] - private void CaptureImage() - { - if (CaptureImagesTask is not null) - return; - - _captureImagesTaskCts = new CancellationTokenSource(); - var cancellationToken = _captureImagesTaskCts.Token; - - var imageTypeSectionCurrentIndex = ImageTypeSectionCurrentIndex; - CaptureImagesTask = new Task(async () => - { - _illuminatorService.TurnOn(); - (double visible, double uv365, double uv254)[] intensities = - { - (0.02500, 0.0, 0.0), - (0.01250, 0.0, 0.0), - (0.00625, 0.0, 0.0), - (0.00000, 1.0, 0.0), - (0.00000, 0.0, 1.0), - (0.00000, 1.0, 1.0), - (0.01250, 1.0, 0.0), - (0.01250, 0.0, 1.0), - (0.01250, 1.0, 1.0), - (0.00625, 1.0, 0.0), - (0.00625, 0.0, 1.0), - (0.00625, 1.0, 1.0) - }; - - Dispatcher.UIThread.Invoke(() => - { - if (imageTypeSectionCurrentIndex == 0) - SeparatorImagesIsCapturing = true; - else - SampleImagesIsCapturing = true; - }); - - try - { - var imageRecords = new List(); - - foreach (var (i, intensity) in intensities.Enumerate()) - { - cancellationToken.ThrowIfCancellationRequested(); - - Dispatcher.UIThread.Invoke(() => - { - if (imageTypeSectionCurrentIndex == 0) - SeparatorImagesCapturingProgress = $"Получение изображений: {i + 1} / {intensities.Count()}"; - else - SampleImagesCapturingProgress = $"Получение изображений: {i + 1} / {intensities.Count()}"; - }); - - _illuminatorService.SetIntensity(intensity.visible, intensity.uv365, intensity.uv254); - - OpenCvSharp.Mat? image; - image = await _cameraService.CaptureImage(cancellationToken, 5); - if (image is null) - { - _logger.LogError("Cannot get image"); - return; - } - - var bytes = image.ImEncode(".png"); - string fileName; - using (var stream = new MemoryStream(bytes)) - fileName = await _imageStorageService.SaveAsync(stream, ".png", "calibration", cancellationToken); - - image.Dispose(); - image = null; - - imageRecords.Add( - new ImageRecord() - { - ImagePath = fileName, - VisibleIntensity = intensity.visible, - Uv365Intensity = intensity.uv365, - Uv254Intensity = intensity.uv254, - } - ); - } - - _illuminatorService.TurnOff(); - - Dispatcher.UIThread.Invoke(() => - { - if (imageTypeSectionCurrentIndex == 0) - { - CurrentRecord.SeparatorImages.Clear(); - CurrentRecord.SeparatorImages.AddRange(imageRecords); - - SeparatorImages.Clear(); - imageRecords - .Select(i => new KeyValuePair(_imageStorageService.GetFullPath(i.ImagePath, "calibration"), i)) - .Select(kv => new KeyValuePair(new Bitmap(kv.Key), kv.Value)) - .ToList() - .ForEach(SeparatorImages.Add); - } - else - { - CurrentRecord.SampleImages.Clear(); - CurrentRecord.SampleImages.AddRange(imageRecords); - - SampleImages.Clear(); - imageRecords - .Select(i => new KeyValuePair(_imageStorageService.GetFullPath(i.ImagePath, "calibration"), i)) - .Select(kv => new KeyValuePair(new Bitmap(kv.Key), kv.Value)) - .ToList() - .ForEach(SampleImages.Add); - } - }); - } - catch (TaskCanceledException) - { } - catch (Exception ex) - { - _logger.LogError(ex, "Exception while image capturing"); - } - finally - { - _illuminatorService.TurnOff(); - _captureImagesTaskCts = null; - Dispatcher.UIThread.Invoke(() => - { - if (imageTypeSectionCurrentIndex == 0) - { - SeparatorImagesIsCapturing = false; - SeparatorImagesCapturingProgress = ""; - } - else - { - SampleImagesIsCapturing = false; - SampleImagesCapturingProgress = ""; - } - CaptureImagesTask = null; - }); - } - }, cancellationToken); - - CaptureImagesTask.Start(); - } - - [RelayCommand] private void CencelImageCapturing() => _captureImagesTaskCts?.Cancel(); - [RelayCommand] private void SeparatorImagesSectionPrevious() => SeparatorImagesSectionCurrentIndex--; - [RelayCommand] private void SeparatorImagesSectionNext() => SeparatorImagesSectionCurrentIndex++; - [RelayCommand] private void SampleImagesSectionPrevious() => SampleImagesSectionCurrentIndex--; - [RelayCommand] private void SampleImagesSectionNext() => SampleImagesSectionCurrentIndex++; - - // [RelayCommand] - // private void SelectImagesFromAnotherRecord() - // { - - // } -} \ No newline at end of file diff --git a/GSS2.UI.Core/ViewModels/AmineContentSeparatorCalibrationViewModel.cs b/GSS2.UI.Core/ViewModels/AmineContentSeparatorCalibrationViewModel.cs deleted file mode 100644 index 19a330b..0000000 --- a/GSS2.UI.Core/ViewModels/AmineContentSeparatorCalibrationViewModel.cs +++ /dev/null @@ -1,345 +0,0 @@ -using System.Collections.Specialized; -using System.Collections.ObjectModel; - -using Microsoft.Extensions.Logging; - -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; - -using Avalonia.Media; -using Avalonia.Media.Imaging; -using Avalonia.Threading; - -using GSS2.Core.Hardware; -using GSS2.Core.Extensions; -using GSS2.Core.Analysis.AmineContent.Database.Calibration; -using Microsoft.EntityFrameworkCore; - -namespace GSS2.UI.Core.ViewModels; - -public partial class AmineContentSeparatorCalibrationViewModel : ViewModelBase -{ - private readonly ILogger _logger; - private readonly AmineContentCalibrationContext _context; - private readonly IlluminatorService _illuminatorService; - private readonly CameraService _cameraService; - private readonly ImageStorageService _imageStorageService; - - private CancellationTokenSource? _captureImagesTaskCts = null; - - [ObservableProperty] private ObservableCollection _records; - [ObservableProperty] private SeparatorRecord? _selectedRecord; - [ObservableProperty] private SeparatorRecord _editingRecord; - [ObservableProperty] private bool _isMenuOpen = false; - - [ObservableProperty] private int _mainSectionsCurrentIndex = 0; - [ObservableProperty] private bool _mainSectionCanScrollBackward = false; - [ObservableProperty] private bool _mainSectionCanScrollForward = true; - [ObservableProperty] private bool _mainSectionIsScrolling = true; - - [ObservableProperty] private Task? _captureImagesTask = null; - - [ObservableProperty] private ObservableCollection _images = new(); - [ObservableProperty] private bool _imagesIsCapturing = false; - [ObservableProperty] private string _imagesCapturingProgress = ""; - [ObservableProperty] private int _imagesSectionCurrentIndex = 0; - [ObservableProperty] private bool _imagesSectionCanScrollForward = false; - [ObservableProperty] private bool _imagesSectionCanScrollBackward = false; - [ObservableProperty] private bool _imagesSectionIsScrolling = true; - - public AmineContentSeparatorCalibrationViewModel(ILogger logger, AmineContentCalibrationContext context, IlluminatorService illuminatorService, CameraService cameraService, ImageStorageService imageStorageService) - { - _logger = logger; - _logger.LogInformation("Initialization"); - - _context = context; - _illuminatorService = illuminatorService; - _cameraService = cameraService; - _imageStorageService = imageStorageService; - - Records = new ObservableCollection(_context.SeparatorRecords.Include(r => r.Images)); - - SelectedRecord = Records.FirstOrDefault(); - if (SelectedRecord is null) - EditingRecord = new() - { - Type = "", - Batch = "", - Images = new() - }; - else - EditingRecord = CopyRecord(SelectedRecord); - - _logger.LogInformation("Initialized"); - } - - partial void OnSelectedRecordChanged(SeparatorRecord? value) - { - if (SelectedRecord is null) - EditingRecord = new() - { - Type = "", - Batch = "", - Images = new() - }; - else - EditingRecord = CopyRecord(SelectedRecord); - } - partial void OnEditingRecordChanged(SeparatorRecord value) - { - var images = value.Images - .Select(i => - { - var path = _imageStorageService.GetFullPath(i.ImagePath, "separator"); - if (path is null) - return null; - return new AsyncImageRecordViewModel(path, i); - }) - .OfType(); - - Images = new(images); - } - - [RelayCommand] private void ToggleMenu() => IsMenuOpen = !IsMenuOpen; - [RelayCommand] private void CloseMenu() => IsMenuOpen = false; - - [RelayCommand] private void CreateRecord() => SelectedRecord = null; - - [RelayCommand] - private void DeleteRecord() - { - var deletedRecord = SelectedRecord; - CreateRecord(); - if (deletedRecord is not null) - { - Records.Remove(deletedRecord); - _context.SeparatorRecords.Remove(deletedRecord); - _context.SaveChanges(); - } - } - - [RelayCommand] - private void SaveRecord() - { - if (SelectedRecord is null) - { - var newEntity = CopyRecord(EditingRecord); - - for (int i = 0; i < newEntity.Images.Count(); i++) - { - var image = newEntity.Images[i]; - if (_context.Entry(image).State is not EntityState.Detached) - continue; - - var attachedImage = _context.ImageRecords.Add(image); - newEntity.Images.RemoveAt(i); - newEntity.Images.Insert(i, attachedImage.Entity); - } - if (_context.Entry(newEntity).State is EntityState.Detached) - { - var attachedRecord = _context.SeparatorRecords.Add(newEntity); - newEntity = attachedRecord.Entity; - } - - _context.SaveChanges(); - - Records.Add(newEntity); - SelectedRecord = newEntity; - } - else - { - SelectedRecord.Type = EditingRecord.Type; - SelectedRecord.Batch = EditingRecord.Batch; - - var imagesToRemove = SelectedRecord.Images - .Where(e => EditingRecord.Images.All(i => i.Id != e.Id)) - .ToList(); - - foreach (var image in imagesToRemove) - SelectedRecord.Images.Remove(image); - - foreach (var editedImage in EditingRecord.Images) - { - var existing = EditingRecord.Images - .FirstOrDefault(i => i.Id == editedImage.Id); - - if (existing is null) - { - SelectedRecord.Images.Add( - new ImageRecord - { - ImagePath = editedImage.ImagePath, - VisibleIntensity = editedImage.VisibleIntensity, - Uv365Intensity = editedImage.Uv365Intensity, - Uv254Intensity = editedImage.Uv254Intensity - } - ); - } - else - { - existing.ImagePath = editedImage.ImagePath; - existing.VisibleIntensity = editedImage.VisibleIntensity; - existing.Uv365Intensity = editedImage.Uv365Intensity; - existing.Uv254Intensity = editedImage.Uv254Intensity; - } - } - - for (int i = 0; i < SelectedRecord.Images.Count(); i++) - { - var image = SelectedRecord.Images[i]; - if (_context.Entry(image).State is not EntityState.Detached) - continue; - - var attachedImage = _context.ImageRecords.Add(image); - SelectedRecord.Images.RemoveAt(i); - SelectedRecord.Images.Insert(i, attachedImage.Entity); - } - if (_context.Entry(SelectedRecord).State is EntityState.Detached) - { - var attachedRecord = _context.SeparatorRecords.Add(SelectedRecord); - var index = Records.IndexOf(SelectedRecord); - Records[index] = attachedRecord.Entity; - SelectedRecord = attachedRecord.Entity; - } - - _context.SaveChanges(); - } - } - - [RelayCommand] private void SwitchMainSection() => MainSectionsCurrentIndex = MainSectionsCurrentIndex == 0 ? 1 : 0; - - [RelayCommand] - private void CaptureImage() - { - if (CaptureImagesTask is not null) - return; - - _captureImagesTaskCts = new CancellationTokenSource(); - var cancellationToken = _captureImagesTaskCts.Token; - - CaptureImagesTask = Task.Run(async () => - { - _illuminatorService.TurnOn(); - (double visible, double uv365, double uv254)[] intensities = - { - (0.02500, 0.0, 0.0), - (0.01250, 0.0, 0.0), - (0.00625, 0.0, 0.0), - (0.00000, 1.0, 0.0), - (0.00000, 0.0, 1.0), - (0.00000, 1.0, 1.0), - (0.01250, 1.0, 0.0), - (0.01250, 0.0, 1.0), - (0.01250, 1.0, 1.0), - (0.00625, 1.0, 0.0), - (0.00625, 0.0, 1.0), - (0.00625, 1.0, 1.0) - }; - - Dispatcher.UIThread.Invoke(() => ImagesIsCapturing = true); - - try - { - var imageRecords = new List(); - - foreach (var (i, intensity) in intensities.Enumerate()) - { - _logger.LogInformation("Capturing images: {} / {} ({};{};{})", i + 1, intensities.Count(), intensity.visible, intensity.uv365, intensity.uv254); - cancellationToken.ThrowIfCancellationRequested(); - - Dispatcher.UIThread.Invoke(() => ImagesCapturingProgress = $"Получение изображений: {i + 1} / {intensities.Count()}"); - - _illuminatorService.SetIntensity(intensity.visible, intensity.uv365, intensity.uv254); - - OpenCvSharp.Mat? image; - image = await _cameraService.CaptureImage(cancellationToken, 5); - if (image is null) - { - _logger.LogError("Cannot get image"); - return; - } - - var bytes = image.ImEncode(".png"); - string fileName; - using (var stream = new MemoryStream(bytes)) - fileName = await _imageStorageService.SaveAsync(stream, ".png", "separator", cancellationToken); - - image.Dispose(); - image = null; - - imageRecords.Add( - new ImageRecord() - { - ImagePath = fileName, - VisibleIntensity = intensity.visible, - Uv365Intensity = intensity.uv365, - Uv254Intensity = intensity.uv254, - } - ); - } - - _illuminatorService.TurnOff(); - - var images = imageRecords - .Select(i => - { - var path = _imageStorageService.GetFullPath(i.ImagePath, "separator"); - if (path is null) - return null; - return new AsyncImageRecordViewModel(path, i); - }) - .OfType(); - - Dispatcher.UIThread.Invoke(() => - { - EditingRecord.Images.Clear(); - EditingRecord.Images.AddRange(imageRecords); - - Images.Clear(); - Images = new(images); - }); - } - catch (TaskCanceledException) - { } - catch (Exception ex) - { - _logger.LogError(ex, "Exception while image capturing"); - } - finally - { - _illuminatorService.TurnOff(); - _captureImagesTaskCts = null; - Dispatcher.UIThread.Invoke(() => - { - ImagesIsCapturing = false; - ImagesCapturingProgress = ""; - CaptureImagesTask = null; - }); - } - }, cancellationToken); - } - - [RelayCommand] private void CancelImageCapturing() => _captureImagesTaskCts?.Cancel(); - [RelayCommand] private void ImagesSectionPrevious() => ImagesSectionCurrentIndex--; - [RelayCommand] private void ImagesSectionNext() => ImagesSectionCurrentIndex++; - - private static SeparatorRecord CopyRecord(SeparatorRecord source) - { - return new SeparatorRecord - { - Id = source.Id, - Type = source.Type, - Batch = source.Batch, - Images = source.Images - .Select(i => new ImageRecord - { - Id = i.Id, - ImagePath = i.ImagePath, - VisibleIntensity = i.VisibleIntensity, - Uv365Intensity = i.Uv365Intensity, - Uv254Intensity = i.Uv254Intensity - }) - .ToList() - }; - } -} \ No newline at end of file diff --git a/GSS2.UI.Core/ViewModels/AsyncImageViewModel.cs b/GSS2.UI.Core/ViewModels/AsyncImageViewModel.cs index 0543696..cdfaad1 100644 --- a/GSS2.UI.Core/ViewModels/AsyncImageViewModel.cs +++ b/GSS2.UI.Core/ViewModels/AsyncImageViewModel.cs @@ -39,8 +39,9 @@ public partial class AsyncImageRecordViewModel : ViewModelBase IsLoading = false; }); } - catch + catch (Exception ex) { + Console.Error.WriteLine($"Ошибка во время загрузки изображения:\n{ex.Message}\n{ex.StackTrace}"); await Dispatcher.UIThread.InvokeAsync(() => IsLoading = false); } finally diff --git a/GSS2.UI.Core/Views/AmineContentSeparatorCalibrationView.axaml b/GSS2.UI.Core/Views/AmineContentSeparatorCalibrationView.axaml deleted file mode 100644 index a4d4e4a..0000000 --- a/GSS2.UI.Core/Views/AmineContentSeparatorCalibrationView.axaml +++ /dev/null @@ -1,598 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GSS2/Views/AmineContent/SeparatorCalibrationView.axaml b/GSS2/Views/AmineContent/SeparatorCalibrationView.axaml index 856c2eb..30e06db 100644 --- a/GSS2/Views/AmineContent/SeparatorCalibrationView.axaml +++ b/GSS2/Views/AmineContent/SeparatorCalibrationView.axaml @@ -435,7 +435,6 @@ -