using System.Collections.ObjectModel; using System.Drawing; using GSS2.Core.Extensions; using GSS2.Core.Hardware; using Microsoft.Extensions.Logging; using OpenCvSharp; namespace GSS2.Core.Analysis.AmineContent; public class AmineContentImageCapturerService { // Список интенсивностей освещения для каждого кадра public static readonly ReadOnlyCollection<(double visible, double uv365, double uv254)> IlluminatorIntensities = [ (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) ]; private readonly ILogger _logger; private readonly CameraService _camera; private readonly IlluminatorService _illuminator; private readonly LightsService _lights; public AmineContentImageCapturerService( ILogger logger, CameraService camera, IlluminatorService illuminator, LightsService lights ) { _logger = logger; _camera = camera; _illuminator = illuminator; _lights = lights; } public async Task CaptureImages(Action<(int i, double visible, double uv365, double uv254, Mat image)> callback, CancellationToken cancellationToken) => await CaptureImages(async (data) => callback(data), cancellationToken); public async Task CaptureImages(Func<(int i, double visible, double uv365, double uv254, Mat image), Task> callback, CancellationToken cancellationToken) { // Включаем осветитель _illuminator.TurnOn(); // Если ViewFinder запущен, то для съёмки изображений его нужно остановить // потом после съёмки снова запустить var needRestartViewFinder = _camera.ViewFinderStarted; if (needRestartViewFinder) _camera.StopViewFinder(); try { // Для каждой интенсивности foreach (var (i, (visible, uv365, uv254)) in IlluminatorIntensities.Enumerate()) { // Выбрасываем исключение если задача отменена cancellationToken.ThrowIfCancellationRequested(); // Логгируем прогресс _logger.LogInformation("Capturing images: {} / {} ({};{};{})", i + 1, IlluminatorIntensities.Count(), visible, uv365, uv254); // Отображаем прогресс на светодиодах _lights.Load(0.3, 1, (double)(i + 1) / IlluminatorIntensities.Count * 100, (double)i / IlluminatorIntensities.Count * 100, Color.Yellow); // Устанавливаем интенсивность _illuminator.SetIntensity(visible, uv365, uv254); // Получаем изображение Mat? image; image = await _camera.CaptureImage(cancellationToken, 2); if (image is null) throw new Exception("Image capture failed"); // Вызываем коллбек await callback.Invoke((i, visible, uv365, uv254, image)); } // Если ошибок не было, то мигаем светодиодами зелёным _ = Task.Run(async () => { await Task.Delay(1000); _lights.Flash(1, 1, Color.Green); await Task.Delay(3000); _lights.Disconnect(); }); } catch (OperationCanceledException) { } catch { // Если была ошибка, то мигаем светодиодами красным _ = Task.Run(async () => { await Task.Delay(1000); _lights.Flash(1, 1, Color.Red); await Task.Delay(3000); _lights.Disconnect(); }); throw; } finally { // В любом случае отключаем осветитель _illuminator.TurnOff(); // Запускаем обратно ViewFinder, если он был запущен и ещё не запущен обратно if (needRestartViewFinder && !_camera.ViewFinderStarted) _camera.StartViewFinder(); } } }