forked from amkovkov/GranuSightSoftware2
343 lines
13 KiB
C#
343 lines
13 KiB
C#
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<AmineContentCalibrationViewModel> _logger;
|
|
private readonly AmineContentCalibrationContext _context;
|
|
private readonly IlluminatorService _illuminatorService;
|
|
private readonly CameraService _cameraService;
|
|
private readonly ImageStorageService _imageStorageService;
|
|
|
|
private CancellationTokenSource? _captureImagesTaskCts = null;
|
|
|
|
[ObservableProperty] private ObservableCollection<CalibrationRecord> _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<KeyValuePair<IImage, ImageRecord>> _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<KeyValuePair<IImage, ImageRecord>> _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<AmineContentCalibrationViewModel> 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<CalibrationRecord>(_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<ImageRecord>(),
|
|
SeparatorImages = new List<ImageRecord>()
|
|
};
|
|
IsNewRecord = true;
|
|
}
|
|
|
|
_logger.LogInformation("Initialized");
|
|
}
|
|
|
|
partial void OnRecordsChanged(ObservableCollection<CalibrationRecord>? oldValue, ObservableCollection<CalibrationRecord> newValue)
|
|
{
|
|
oldValue?.CollectionChanged -= OnRecordsCollectionChanged;
|
|
newValue?.CollectionChanged += OnRecordsCollectionChanged;
|
|
}
|
|
partial void OnCurrentRecordChanged(CalibrationRecord value)
|
|
{
|
|
SeparatorImages = new(
|
|
value.SeparatorImages
|
|
.Select(i => new KeyValuePair<string, ImageRecord>(_imageStorageService.GetFullPath(i.ImagePath, "calibration"), i))
|
|
.Select(kv => new KeyValuePair<IImage, ImageRecord>(new Bitmap(kv.Key), kv.Value))
|
|
);
|
|
|
|
SampleImages = new(
|
|
value.SampleImages
|
|
.Select(i => new KeyValuePair<string, ImageRecord>(_imageStorageService.GetFullPath(i.ImagePath, "calibration"), i))
|
|
.Select(kv => new KeyValuePair<IImage, ImageRecord>(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<ImageRecord>(),
|
|
SeparatorImages = new List<ImageRecord>()
|
|
};
|
|
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<ImageRecord>();
|
|
|
|
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<string, ImageRecord>(_imageStorageService.GetFullPath(i.ImagePath, "calibration"), i))
|
|
.Select(kv => new KeyValuePair<IImage, ImageRecord>(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<string, ImageRecord>(_imageStorageService.GetFullPath(i.ImagePath, "calibration"), i))
|
|
.Select(kv => new KeyValuePair<IImage, ImageRecord>(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()
|
|
// {
|
|
|
|
// }
|
|
} |