forked from amkovkov/GranuSightSoftware2
213 lines
8.6 KiB
C#
213 lines
8.6 KiB
C#
using System.CommandLine;
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
using OpenCvSharp;
|
|
|
|
using GSS2.Core;
|
|
using GSS2.Core.Logging;
|
|
using GSS2.Core.Hardware;
|
|
using GSS2.Core.Extensions;
|
|
|
|
namespace GSS2.Commands;
|
|
|
|
public static class Capture
|
|
{
|
|
private class CaptureWorker : BackgroundService
|
|
{
|
|
private readonly ILogger<CaptureWorker> _logger;
|
|
private readonly IHostApplicationLifetime _applicationLifetime;
|
|
private readonly CameraService _cameraService;
|
|
private readonly IlluminatorService _illuminatorService;
|
|
|
|
private readonly FileInfo _output;
|
|
private readonly double _intensityWhite;
|
|
private readonly double _intensityUv365;
|
|
private readonly double _intensityUv254;
|
|
|
|
public CaptureWorker(
|
|
ILogger<CaptureWorker> logger,
|
|
IHostApplicationLifetime applicationLifetime,
|
|
CameraService cameraService,
|
|
IlluminatorService illuminatorService,
|
|
FileInfo output,
|
|
double intensityWhite,
|
|
double intensityUv365,
|
|
double intensityUv254)
|
|
{
|
|
_applicationLifetime = applicationLifetime;
|
|
_logger = logger;
|
|
_cameraService = cameraService;
|
|
_illuminatorService = illuminatorService;
|
|
_output = output;
|
|
_intensityWhite = intensityWhite;
|
|
_intensityUv365 = intensityUv365;
|
|
_intensityUv254 = intensityUv254;
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
// Логгируем информацию
|
|
_logger.LogInformation("Захват изображения с камеры...");
|
|
_logger.LogInformation("Файл выходного изображения: {}", _output);
|
|
_logger.LogInformation("Интенсивность белого канала осветителя: {}", _intensityWhite);
|
|
_logger.LogInformation("Интенсивность УФ канала осветителя 365 нм: {}", _intensityUv365);
|
|
_logger.LogInformation("Интенсивность УФ канала осветителя 254 нм: {}", _intensityUv254);
|
|
|
|
// Инициализируем камеру
|
|
await _cameraService.InitializeAsync(stoppingToken);
|
|
stoppingToken.ThrowIfCancellationRequested();
|
|
|
|
// Включаем осветитель
|
|
_illuminatorService.SetIntensity(_intensityWhite, _intensityUv365, _intensityUv254);
|
|
_illuminatorService.TurnOn();
|
|
|
|
// Захватываем изображение
|
|
Mat? image;
|
|
try
|
|
{
|
|
image = await _cameraService.CaptureImage(stoppingToken, 5);
|
|
|
|
if (image is null)
|
|
throw new Exception("Не удаётся захватить изображение с камеры.");
|
|
|
|
_illuminatorService.TurnOff();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_illuminatorService.TurnOff();
|
|
_logger.LogCritical(ex, "Ошибка при захвате изображения");
|
|
_applicationLifetime.StopApplication();
|
|
return;
|
|
}
|
|
|
|
// Сохраняем изображение в файл
|
|
try
|
|
{
|
|
image.ImWrite(path: _output.FullName);
|
|
_logger.LogInformation("Изображение сохранено: {}", _output.FullName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogCritical(ex, "Ошибка при сохранении изображения");
|
|
_applicationLifetime.StopApplication();
|
|
return;
|
|
}
|
|
|
|
_applicationLifetime.StopApplication();
|
|
}
|
|
}
|
|
|
|
public static readonly RootCommand RootCommand;
|
|
private static readonly Command Command;
|
|
private static readonly Option<FileInfo> Output;
|
|
private static readonly Option<double> IntensityWhite;
|
|
private static readonly Option<double> IntensityUv365;
|
|
private static readonly Option<double> IntensityUv254;
|
|
|
|
static Capture()
|
|
{
|
|
// Создаём команды, опции, аргументы и пр.
|
|
RootCommand = new("Захватить изображение с камеры");
|
|
Command = new("capture")
|
|
{
|
|
Description = "Захватить изображение с камеры"
|
|
};
|
|
Output = new("--output", ["-o"])
|
|
{
|
|
Description = "Файл выходного изображения",
|
|
DefaultValueFactory = (_) => new FileInfo("image.png")
|
|
};
|
|
IntensityWhite = new("--intensity-white", ["-iw"])
|
|
{
|
|
Description = "Интенсивность белого канала осветителя (от 0 до 1)",
|
|
DefaultValueFactory = (_) => 1
|
|
};
|
|
IntensityUv365 = new("--intensity-uv365", ["-i365"])
|
|
{
|
|
Description = "Интенсивность УФ канала осветителя 365 нм (от 0 до 1)",
|
|
DefaultValueFactory = (_) => 0
|
|
};
|
|
IntensityUv254 = new("--intensity-uv254", ["-i254"])
|
|
{
|
|
Description = "Интенсивность УФ канала осветителя 254 нм (from 0 to 1)",
|
|
DefaultValueFactory = (_) => 0
|
|
};
|
|
|
|
// Изменяем описания стандартных опций
|
|
Helper.TranslateDefaultOptionDescriptions(RootCommand);
|
|
|
|
// Наполняем команды
|
|
RootCommand.Add(Output);
|
|
RootCommand.Add(IntensityWhite);
|
|
RootCommand.Add(IntensityUv365);
|
|
RootCommand.Add(IntensityUv254);
|
|
RootCommand.SetAction(CommandAction);
|
|
|
|
Command.Add(Output);
|
|
Command.Add(IntensityWhite);
|
|
Command.Add(IntensityUv365);
|
|
Command.Add(IntensityUv254);
|
|
Command.SetAction(CommandAction);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Получить команду как корневую
|
|
/// </summary>
|
|
public static RootCommand GetCommand() => RootCommand;
|
|
|
|
/// <summary>
|
|
/// Зарегистрировать команду как подкоманду
|
|
/// </summary>
|
|
/// <param name="command">Команда в которой необходимо зарегистрировать подкоманду</param>
|
|
public static void RegisterCommand(Command command) => command.Add(Command);
|
|
|
|
private static void CommandAction(ParseResult result)
|
|
{
|
|
/// Получаем значения аргументов командной строки
|
|
var outputFile = result.GetRequiredValue(Output);
|
|
var intensityWhite = result.GetRequiredValue(IntensityWhite);
|
|
var intensityUv365 = result.GetRequiredValue(IntensityUv365);
|
|
var intensityUv254 = result.GetRequiredValue(IntensityUv254);
|
|
|
|
// Создаём хост
|
|
var builder = Host.CreateApplicationBuilder();
|
|
|
|
// Добавляем конфигурацию из appsettings.json
|
|
builder.Configuration.AddAppSettingsJson();
|
|
|
|
// Конфигурируем логгер
|
|
builder.Logging.ConfigureLogging();
|
|
builder.Services.AddSingleton<LibCameraLogSink>();
|
|
|
|
// Добавляем сервисы аппаратной части
|
|
builder.Services.AddIlluminatorService("Hardware:Illuminator");
|
|
builder.Services.AddCameraService("Hardware:Camera");
|
|
|
|
// Добавляем рабочий сервис
|
|
builder.Services.AddHostedService<CaptureWorker>(services =>
|
|
new CaptureWorker(
|
|
services.GetRequiredService<ILogger<CaptureWorker>>(),
|
|
services.GetRequiredService<IHostApplicationLifetime>(),
|
|
services.GetRequiredService<CameraService>(),
|
|
services.GetRequiredService<IlluminatorService>(),
|
|
outputFile,
|
|
intensityWhite, intensityUv365, intensityUv254
|
|
)
|
|
);
|
|
|
|
// Собираем хост
|
|
var host = builder.Build();
|
|
|
|
// Поскольку LibCameraLogSink, который перенаправляет логи из libcamera в хост,
|
|
// не будет создан ни одним из других сервисов, его необходимо создать превентивно
|
|
host.Services.GetRequiredService<LibCameraLogSink>();
|
|
|
|
// Запускаем хост
|
|
host.Run();
|
|
}
|
|
}
|