Files
GSS2Rework/GSS2.Core/Analysis/AmineContent/ImageCapturerService.cs
T

126 lines
4.7 KiB
C#

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 ImageCapturerService
{
// Список интенсивностей освещения для каждого кадра
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<ImageCapturerService> _logger;
private readonly CameraService _camera;
private readonly IlluminatorService _illuminator;
private readonly LightsService _lights;
public ImageCapturerService(
ILogger<ImageCapturerService> 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);
// Ждём разогрева светодиодов
await Task.Delay(200);
// Получаем изображение
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();
}
}
}