Files
GSS2Rework/GSS2/Commands/Capture.cs
T
amkovkov 8cf1c89863 feat: starting to build a application itself
add "capture" and "camera-tuning" commands for cli
2026-04-07 13:28:20 +03:00

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();
}
}