forked from amkovkov/GranuSightSoftware2
chore: remove GSS2.Test project
This commit is contained in:
@@ -1,16 +0,0 @@
|
||||
<Application
|
||||
x:Class="GSS2.Test.App"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:GSS2.Test"
|
||||
RequestedThemeVariant="Dark">
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
</Application.Styles>
|
||||
|
||||
<Application.DataTemplates>
|
||||
<local:DependencyInjectionViewLocator />
|
||||
</Application.DataTemplates>
|
||||
|
||||
</Application>
|
||||
@@ -1,72 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Threading;
|
||||
|
||||
using GSS2.Test.ViewModels;
|
||||
using GSS2.Test.Views;
|
||||
using GSS2.UI.Core;
|
||||
using GSS2.UI.Core.Services;
|
||||
using GSS2.UI.Core.ViewModels;
|
||||
|
||||
namespace GSS2.Test;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is null)
|
||||
throw new InvalidOperationException("Application framework initialization cannot be fulfilled, ApplicationLifetime is null");
|
||||
|
||||
var loggerFactory = Program.ApplicationHost.Services.GetRequiredService<ILoggerFactory>();
|
||||
var navigationService = Program.ApplicationHost.Services.GetRequiredService<NavigationService>();
|
||||
|
||||
switch (ApplicationLifetime)
|
||||
{
|
||||
case IClassicDesktopStyleApplicationLifetime desktop:
|
||||
Console.WriteLine("Application running in classic style");
|
||||
Console.WriteLine($"Application running in {(Program.IsFullscreen ? "fullscreen" : "window")} mode");
|
||||
|
||||
desktop.Startup += (_, _) => Program.ApplicationHost.RunAsync();
|
||||
desktop.Exit += (_, _) => Program.ApplicationHost.StopAsync();
|
||||
|
||||
var mainWindowViewModelLogger = loggerFactory.CreateLogger<MainWindowViewModel>();
|
||||
var mainWindow = new MainWindow()
|
||||
{
|
||||
DataContext = new MainWindowViewModel(mainWindowViewModelLogger)
|
||||
{
|
||||
SystemDecorations = Program.IsFullscreen ? Avalonia.Controls.SystemDecorations.None : Avalonia.Controls.SystemDecorations.Full,
|
||||
Topmost = Program.IsFullscreen,
|
||||
WindowState = Program.IsFullscreen ? Avalonia.Controls.WindowState.FullScreen : Avalonia.Controls.WindowState.Normal
|
||||
},
|
||||
};
|
||||
desktop.MainWindow = mainWindow;
|
||||
|
||||
Program.ShutdownRequested += (_, _) => Dispatcher.UIThread.Invoke(() => desktop.MainWindow?.Close());
|
||||
break;
|
||||
|
||||
case ISingleViewApplicationLifetime singleView:
|
||||
Console.WriteLine("Application running in single view style");
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException($"Application framework initialization cannot be fulfilled, ApplicationLifetime has unknown type inherited from: {string.Join(", ", ApplicationLifetime.GetType().GetInterfaces().Select(i => i.FullName))}");
|
||||
|
||||
}
|
||||
|
||||
var mainViewLogger = loggerFactory.CreateLogger<MainView>();
|
||||
var mainView = new MainView(mainViewLogger)
|
||||
{
|
||||
DataContext = Program.ApplicationHost.Services.GetRequiredService<MainViewModel>()
|
||||
};
|
||||
navigationService.NavigateTo(mainView);
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using GSS2.UI.Core.Views;
|
||||
using GSS2.UI.Core.ViewModels;
|
||||
using GSS2.Test.Views;
|
||||
using GSS2.Test.ViewModels;
|
||||
using GSS2.UI.Core.Services;
|
||||
|
||||
using Avalonia;
|
||||
|
||||
namespace GSS2.Test;
|
||||
|
||||
public static class DependencyInjectionHelper
|
||||
{
|
||||
public static IServiceCollection AddViewsAndModels(this IServiceCollection services) =>
|
||||
services
|
||||
.AddSingleton<NavigationService>((_) => new NavigationService(Application.Current?.ApplicationLifetime))
|
||||
.AddSingleton<MainWindowViewModel>()
|
||||
.AddSingleton<MainView>()
|
||||
.AddSingleton<MainViewModel>()
|
||||
.AddSingleton<ResourcesView>()
|
||||
.AddSingleton<ResourcesViewModel>()
|
||||
.AddSingleton<CameraView>()
|
||||
.AddSingleton<CameraViewModel>()
|
||||
.AddSingleton<IlluminatorControllerView>()
|
||||
.AddSingleton<IlluminatorControllerViewModel>();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
|
||||
using GSS2.UI.Core.ViewModels;
|
||||
|
||||
namespace GSS2.Test;
|
||||
|
||||
public class DependencyInjectionViewLocator : IDataTemplate
|
||||
{
|
||||
public Control? Build(object? data)
|
||||
{
|
||||
if (data is null)
|
||||
return null;
|
||||
|
||||
var name = data.GetType().AssemblyQualifiedName?
|
||||
.Replace("ViewModels", "Views")
|
||||
.Replace("ViewModel", "View");
|
||||
if (name is null)
|
||||
return new TextBlock { Text = $"Not found: {data}" };
|
||||
var type = Type.GetType(name);
|
||||
if (type is null)
|
||||
return new TextBlock { Text = $"Not found type: {name} for {data}" };
|
||||
|
||||
var control = Program.ApplicationHost.Services.GetRequiredService(type) as Control;
|
||||
if (control is null)
|
||||
return new TextBlock { Text = $"Not found in DI: {type} for {data}" };
|
||||
|
||||
control.DataContext = data;
|
||||
return control;
|
||||
}
|
||||
|
||||
public bool Match(object? data) => data is ViewModelBase;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Worker">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>dotnet-GSS2.Test-191ece0a-855d-46ec-9ecb-44378fc3db83</UserSecretsId>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia.LinuxFramebuffer" Version="12.0.0" />
|
||||
<PackageReference Include="LiveChartsCore.SkiaSharpView.Avalonia" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
|
||||
<PackageReference Include="Avalonia" Version="12.0.0" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="12.0.0" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="12.0.0" />
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="12.0.0" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.3" />
|
||||
<!-- Avalonia.X11 зависит от Avalonia.FreeDesktop который зависит от Tmds.DBus.Protocol==0.90.3 -->
|
||||
<!-- Tmds.DBus.Protocol==0.90.3 имеет критическую уязвмость, поэтому превентивно установлена версия с исправлением -->
|
||||
<PackageReference Include="Tmds.DBus.Protocol" Version="0.92.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GSS2.Core\GSS2.Core.csproj" />
|
||||
<ProjectReference Include="..\GSS2.UI.Core\GSS2.UI.Core.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,189 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.OpenGL.Egl;
|
||||
|
||||
using System.CommandLine;
|
||||
|
||||
namespace GSS2.Test;
|
||||
|
||||
public partial class Program
|
||||
{
|
||||
private enum RenderingMode
|
||||
{
|
||||
X11,
|
||||
DRM
|
||||
}
|
||||
|
||||
private static List<string>? _args = null;
|
||||
private static readonly RootCommand _rootCommand = new("Run UI application");
|
||||
private static readonly Option<bool> _fullscreen = new("--fullscreen")
|
||||
{
|
||||
Description = "Run in fullscreen mode"
|
||||
};
|
||||
private static readonly Option<RenderingMode> _renderingMode = new("--rendering-mode")
|
||||
{
|
||||
Description = "Rendering mode to use",
|
||||
DefaultValueFactory = (_) => RenderingMode.X11
|
||||
};
|
||||
private static readonly Option<bool> _hideConsole = new("--hide-console")
|
||||
{
|
||||
Description = "Suppress console output",
|
||||
DefaultValueFactory = (result) => result.GetRequiredValue(_renderingMode) == RenderingMode.DRM
|
||||
};
|
||||
|
||||
private static readonly Command _cameraTuningCommand = new("camera-tuning")
|
||||
{
|
||||
Description = "Tune camera parameters"
|
||||
};
|
||||
private static readonly Option<FileInfo> _cameraTuningOutputFile = new("--output")
|
||||
{
|
||||
Description = "Output image file",
|
||||
Required = false
|
||||
};
|
||||
private static readonly Option<double> _cameraTuningGainR = new("--gain-r")
|
||||
{
|
||||
Description = "Color gain (red channel) to start from",
|
||||
DefaultValueFactory = (_) => 1
|
||||
};
|
||||
private static readonly Option<double> _cameraTuningGainG = new("--gain-g")
|
||||
{
|
||||
Description = "Color gain (green channel) to start from",
|
||||
DefaultValueFactory = (_) => 1
|
||||
};
|
||||
private static readonly Option<double> _cameraTuningGainB = new("--gain-b")
|
||||
{
|
||||
Description = "Color gain (blue channel) to start from",
|
||||
DefaultValueFactory = (_) => 1
|
||||
};
|
||||
private static readonly Option<double> _cameraTuningThreshold = new("--threshold")
|
||||
{
|
||||
Description = "Threshold to stop on",
|
||||
DefaultValueFactory = (_) => 0.1
|
||||
};
|
||||
private static readonly Option<uint> _cameraTuningSteps = new("--steps")
|
||||
{
|
||||
Description = "Maximum steps count",
|
||||
DefaultValueFactory = (_) => 10
|
||||
};
|
||||
|
||||
private static readonly Command _captureCommand = new("capture")
|
||||
{
|
||||
Description = "Capture image from camera"
|
||||
};
|
||||
private static readonly Option<FileInfo> _captureOutputFile = new("--output")
|
||||
{
|
||||
Description = "Output image file",
|
||||
DefaultValueFactory = (_) => new FileInfo("image.png")
|
||||
};
|
||||
private static readonly Option<double> _captureIntensityWhite = new("--intensity-white")
|
||||
{
|
||||
Description = "Illuminator intensity for white (from 0 to 1)",
|
||||
DefaultValueFactory = (_) => 1
|
||||
};
|
||||
private static readonly Option<double> _captureIntensityUv365nm = new("--intensity-uv365nm")
|
||||
{
|
||||
Description = "Illuminator intensity for UV 365 nm (from 0 to 1)",
|
||||
DefaultValueFactory = (_) => 0
|
||||
};
|
||||
private static readonly Option<double> _captureIntensityUv254nm = new("--intensity-uv254nm")
|
||||
{
|
||||
Description = "Illuminator intensity for UV 254 nm (from 0 to 1)",
|
||||
DefaultValueFactory = (_) => 0
|
||||
};
|
||||
|
||||
private static readonly Command _imageStorageClear = new("image-storage-clear")
|
||||
{
|
||||
Description = "Clear image storage from unused images"
|
||||
};
|
||||
|
||||
|
||||
public static event ConsoleCancelEventHandler? ShutdownRequested;
|
||||
|
||||
[STAThread]
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
_args = args.ToList();
|
||||
|
||||
#if DEBUG
|
||||
WaitDebuggerIfNeeded();
|
||||
#endif
|
||||
|
||||
_rootCommand.SetAction(Ui);
|
||||
_rootCommand.Add(_fullscreen);
|
||||
_rootCommand.Add(_renderingMode);
|
||||
_rootCommand.Add(_hideConsole);
|
||||
|
||||
_rootCommand.Add(_cameraTuningCommand);
|
||||
_cameraTuningCommand.SetAction(CameraTuning);
|
||||
_cameraTuningCommand.Add(_cameraTuningOutputFile);
|
||||
_cameraTuningCommand.Add(_cameraTuningGainR);
|
||||
_cameraTuningCommand.Add(_cameraTuningGainG);
|
||||
_cameraTuningCommand.Add(_cameraTuningGainB);
|
||||
_cameraTuningCommand.Add(_cameraTuningThreshold);
|
||||
_cameraTuningCommand.Add(_cameraTuningSteps);
|
||||
|
||||
_rootCommand.Add(_captureCommand);
|
||||
_captureCommand.SetAction(Capture);
|
||||
_captureCommand.Add(_captureOutputFile);
|
||||
_captureCommand.Add(_captureIntensityWhite);
|
||||
_captureCommand.Add(_captureIntensityUv365nm);
|
||||
_captureCommand.Add(_captureIntensityUv254nm);
|
||||
|
||||
_rootCommand.Add(_imageStorageClear);
|
||||
_imageStorageClear.SetAction(ImageStorageClear);
|
||||
|
||||
Console.CancelKeyPress += new ConsoleCancelEventHandler(OnProgramShutdown);
|
||||
Console.WriteLine("Press Ctrl+C to shut down.");
|
||||
|
||||
var parseResult = _rootCommand.Parse(_args);
|
||||
if (parseResult.Errors.Count() != 0)
|
||||
{
|
||||
foreach (var parseError in parseResult.Errors)
|
||||
Console.Error.WriteLine(parseError.Message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return parseResult.Invoke();
|
||||
}
|
||||
|
||||
private static void OnProgramShutdown(object? sender, ConsoleCancelEventArgs ea)
|
||||
{
|
||||
ShutdownRequested?.Invoke(sender, ea);
|
||||
ea.Cancel = true;
|
||||
}
|
||||
|
||||
private static void WaitDebuggerIfNeeded()
|
||||
{
|
||||
if (System.Diagnostics.Debugger.IsAttached)
|
||||
return;
|
||||
|
||||
if (_args is null || !_args.Contains("--debug"))
|
||||
return;
|
||||
|
||||
_args.Remove("--debug");
|
||||
|
||||
bool keepWaiting = true;
|
||||
|
||||
void CancelHandle(object? sender, ConsoleCancelEventArgs e)
|
||||
{
|
||||
e.Cancel = true;
|
||||
keepWaiting = false;
|
||||
Console.WriteLine("\nWait cancelled by user.");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
Console.CancelKeyPress += CancelHandle;
|
||||
|
||||
Console.WriteLine("Waiting debugger attach (Press Ctrl+C to cancel)");
|
||||
Console.WriteLine($"Process Id: {Environment.ProcessId}");
|
||||
Console.WriteLine($"Process Name: {Environment.ProcessPath}");
|
||||
Console.WriteLine($"Thread Id: {Thread.CurrentThread.ManagedThreadId}");
|
||||
Console.WriteLine($"Thread Name: {Thread.CurrentThread.Name}");
|
||||
|
||||
while (!System.Diagnostics.Debugger.IsAttached && keepWaiting)
|
||||
Thread.Sleep(100);
|
||||
|
||||
if (System.Diagnostics.Debugger.IsAttached)
|
||||
System.Diagnostics.Debugger.Break();
|
||||
|
||||
Console.CancelKeyPress -= CancelHandle;
|
||||
}
|
||||
}
|
||||
@@ -1,330 +0,0 @@
|
||||
using System.CommandLine;
|
||||
|
||||
using GSS2.Core;
|
||||
using GSS2.Core.Hardware;
|
||||
using GSS2.Core.Logging;
|
||||
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
|
||||
using OpenCvSharp;
|
||||
|
||||
using ConsoleFormatter = GSS2.Core.Logging.ConsoleFormatter;
|
||||
|
||||
namespace GSS2.Test;
|
||||
|
||||
public partial class Program
|
||||
{
|
||||
private class CameraTuningWorker : BackgroundService
|
||||
{
|
||||
private readonly ILogger<CameraTuningWorker> _logger;
|
||||
private readonly IHostApplicationLifetime _applicationLifetime;
|
||||
private readonly CameraService _cameraService;
|
||||
private readonly IlluminatorService _illuminatorService;
|
||||
private readonly FileInfo? _outputFile;
|
||||
private double _gainR;
|
||||
private double _gainG;
|
||||
private double _gainB;
|
||||
private readonly double _threshold;
|
||||
private readonly uint _steps;
|
||||
private static readonly Scalar[] KnownSegments =
|
||||
{
|
||||
new Scalar(0,255,255), // Cyan
|
||||
new Scalar(0,0,255), // Blue
|
||||
new Scalar(255,0,255), // Magenta
|
||||
new Scalar(128,128,128), // Gray (skip)
|
||||
new Scalar(255,0,0), // Red
|
||||
new Scalar(255,128,0), // Orange
|
||||
new Scalar(255,255,0), // Yellow
|
||||
new Scalar(0,255,0) // Green
|
||||
};
|
||||
private const double PatternOuterRadius = 180.0;
|
||||
private const double PatternCenterRadius = 60.0;
|
||||
|
||||
public CameraTuningWorker(ILogger<CameraTuningWorker> logger, IHostApplicationLifetime applicationLifetime, CameraService cameraService, IlluminatorService illuminatorService, FileInfo? outputFile, double gainR, double gainG, double gainB, double threshold, uint steps)
|
||||
{
|
||||
_applicationLifetime = applicationLifetime;
|
||||
_logger = logger;
|
||||
_cameraService = cameraService;
|
||||
_illuminatorService = illuminatorService;
|
||||
_outputFile = outputFile;
|
||||
_gainR = gainR;
|
||||
_gainG = gainG;
|
||||
_gainB = gainB;
|
||||
_threshold = threshold;
|
||||
_steps = steps;
|
||||
_logger.LogInformation("Initialized");
|
||||
_logger.LogInformation("Output File: {}", _outputFile);
|
||||
_logger.LogInformation("Gain R: {}", _gainR);
|
||||
_logger.LogInformation("Gain G: {}", _gainG);
|
||||
_logger.LogInformation("Gain B: {}", _gainB);
|
||||
_logger.LogInformation("Threshold: {}", _threshold);
|
||||
_logger.LogInformation("Steps: {}", _steps);
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("Running camera fine tuning");
|
||||
|
||||
Mat? image;
|
||||
|
||||
int i = 0;
|
||||
bool optimalGainsFound = false;
|
||||
|
||||
_illuminatorService.SetIntensity(1, 0, 0);
|
||||
_illuminatorService.TurnOn();
|
||||
|
||||
while (i < _steps)
|
||||
{
|
||||
_cameraService.Configuration.DecodeGainR = _gainR;
|
||||
_cameraService.Configuration.DecodeGainG = _gainG;
|
||||
_cameraService.Configuration.DecodeGainB = _gainB;
|
||||
|
||||
try
|
||||
{
|
||||
image = await _cameraService.CaptureImage(stoppingToken, 2);
|
||||
|
||||
if (image is null)
|
||||
{
|
||||
_logger.LogError("Cannot get image");
|
||||
break;
|
||||
}
|
||||
|
||||
if (image.Type() != MatType.CV_8UC3 &&
|
||||
image.Type() != MatType.CV_8UC4 &&
|
||||
image.Type() != MatType.CV_16UC3 &&
|
||||
image.Type() != MatType.CV_16UC4)
|
||||
{
|
||||
_logger.LogCritical("Unsupported image type: {}", image.Type().ToString());
|
||||
break;
|
||||
}
|
||||
|
||||
if (image.Type() == MatType.CV_16UC3)
|
||||
image.ConvertTo(image, MatType.CV_8UC3, 1 / 256.0);
|
||||
if (image.Type() == MatType.CV_16UC4)
|
||||
image.ConvertTo(image, MatType.CV_8UC4, 1 / 256.0);
|
||||
|
||||
var channels = image.Split();
|
||||
Cv2.Merge([channels[0], channels[1], channels[2]], image);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception occurred while image capturing");
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_outputFile is not null)
|
||||
image.ImWrite(_outputFile.FullName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception occurred while image saving");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var gains = ComputeWhiteBalanceGains(image);
|
||||
if (gains is null)
|
||||
{
|
||||
_logger.LogError("Cannot compute gains");
|
||||
break;
|
||||
}
|
||||
|
||||
var (r, g, b) = gains.Value;
|
||||
if (Math.Abs(_gainR - r) < _threshold &&
|
||||
Math.Abs(_gainG - g) < _threshold &&
|
||||
Math.Abs(_gainB - b) < _threshold)
|
||||
{
|
||||
_logger.LogInformation("Optimal color gains: r={}, g={}, b:={}", r, g, b);
|
||||
optimalGainsFound = true;
|
||||
break;
|
||||
}
|
||||
_gainR = (_gainR + r) / 2;
|
||||
_gainG = (_gainG + g) / 2;
|
||||
_gainB = (_gainB + b) / 2;
|
||||
_logger.LogInformation("Step {}/{} color gains: r={}, g={}, b:={}", i + 1, _steps, _gainR, _gainG, _gainB);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Exception occurred while gains computing");
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
_illuminatorService.TurnOff();
|
||||
|
||||
if (!optimalGainsFound)
|
||||
_logger.LogWarning("Optimal gains not found");
|
||||
|
||||
_applicationLifetime.StopApplication();
|
||||
}
|
||||
|
||||
private (double rGain, double gGain, double bGain)? ComputeWhiteBalanceGains(Mat image)
|
||||
{
|
||||
var circle = FindCircle(image);
|
||||
if (circle == null)
|
||||
return null;
|
||||
|
||||
var (rx, ry, rr) = circle.Value;
|
||||
|
||||
double scale = rr / PatternOuterRadius;
|
||||
double innerPx = PatternCenterRadius * scale;
|
||||
int midR = (int)((innerPx + rr) / 2.0);
|
||||
|
||||
double phi0 = DetectOrientation(image, rx, ry, rr);
|
||||
if (double.IsNaN(phi0))
|
||||
phi0 = Math.PI / 2.0;
|
||||
|
||||
var samples = new List<Vec3d>();
|
||||
var refs = new List<Vec3d>();
|
||||
|
||||
int N = KnownSegments.Length;
|
||||
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
if (i == 3) continue; // skip gray
|
||||
|
||||
double theta = phi0 - (2 * Math.PI / N) * i;
|
||||
|
||||
int cx = (int)(rx + midR * Math.Cos(theta));
|
||||
int cy = (int)(ry - midR * Math.Sin(theta));
|
||||
|
||||
var roi = new Rect(
|
||||
Math.Max(cx - 8, 0),
|
||||
Math.Max(cy - 8, 0),
|
||||
Math.Min(16, image.Width - Math.Max(cx - 8, 0)),
|
||||
Math.Min(16, image.Height - Math.Max(cy - 8, 0)));
|
||||
|
||||
if (roi.Width < 8 || roi.Height < 8)
|
||||
continue;
|
||||
|
||||
using var patch = new Mat(image, roi);
|
||||
var mean = Cv2.Mean(patch);
|
||||
|
||||
// BGR → RGB
|
||||
samples.Add(new Vec3d(mean.Val2, mean.Val1, mean.Val0));
|
||||
|
||||
var refColor = KnownSegments[i];
|
||||
refs.Add(new Vec3d(refColor.Val2, refColor.Val1, refColor.Val0));
|
||||
}
|
||||
|
||||
if (samples.Count < 3)
|
||||
return null;
|
||||
|
||||
// Формируем матрицы для least squares
|
||||
var S = new Mat(samples.Count, 3, MatType.CV_64F);
|
||||
var R = new Mat(samples.Count, 3, MatType.CV_64F);
|
||||
|
||||
for (int i = 0; i < samples.Count; i++)
|
||||
{
|
||||
S.Set(i, 0, samples[i][0]);
|
||||
S.Set(i, 1, samples[i][1]);
|
||||
S.Set(i, 2, samples[i][2]);
|
||||
|
||||
R.Set(i, 0, refs[i][0]);
|
||||
R.Set(i, 1, refs[i][1]);
|
||||
R.Set(i, 2, refs[i][2]);
|
||||
}
|
||||
|
||||
var M = new Mat();
|
||||
Cv2.Solve(S, R, M, DecompTypes.Normal);
|
||||
|
||||
double rGain = Math.Max(M.At<double>(0, 0), 1.0);
|
||||
double gGain = 1.0;
|
||||
double bGain = Math.Max(M.At<double>(2, 2), 1.0);
|
||||
|
||||
return (rGain, gGain, bGain);
|
||||
}
|
||||
private (int x, int y, int r)? FindCircle(Mat image)
|
||||
{
|
||||
using var gray = new Mat();
|
||||
Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY);
|
||||
Cv2.GaussianBlur(gray, gray, new Size(9, 9), 2);
|
||||
|
||||
var circles = Cv2.HoughCircles(
|
||||
gray,
|
||||
HoughModes.Gradient,
|
||||
dp: 1.2,
|
||||
minDist: gray.Rows / 3,
|
||||
param1: 100,
|
||||
param2: 30,
|
||||
minRadius: (int)(gray.Rows * 0.3),
|
||||
maxRadius: (int)(gray.Rows * 0.6));
|
||||
|
||||
if (circles.Length == 0)
|
||||
return null;
|
||||
|
||||
var c = circles[0];
|
||||
return ((int)c.Center.X, (int)c.Center.Y, (int)c.Radius);
|
||||
}
|
||||
private double DetectOrientation(Mat image, int rx, int ry, int rr)
|
||||
{
|
||||
double scale = rr / PatternOuterRadius;
|
||||
int innerR = (int)(PatternCenterRadius * scale);
|
||||
|
||||
using var gray = new Mat();
|
||||
Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY);
|
||||
|
||||
using var mask = Mat.Zeros(image.Size(), MatType.CV_8U).ToMat();
|
||||
Cv2.Circle(mask, new Point(rx, ry), innerR, Scalar.White, -1);
|
||||
|
||||
var whitePoints = new List<Point>();
|
||||
|
||||
for (int y = 0; y < gray.Rows; y++)
|
||||
{
|
||||
for (int x = 0; x < gray.Cols; x++)
|
||||
{
|
||||
if (mask.At<byte>(y, x) == 255 &&
|
||||
gray.At<byte>(y, x) > 128)
|
||||
{
|
||||
whitePoints.Add(new Point(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (whitePoints.Count < 20)
|
||||
return double.NaN;
|
||||
|
||||
double cx = whitePoints.Average(p => p.X);
|
||||
double cy = whitePoints.Average(p => p.Y);
|
||||
|
||||
return Math.Atan2(ry - cy, cx - rx);
|
||||
}
|
||||
}
|
||||
private static void CameraTuning(ParseResult parseResult)
|
||||
{
|
||||
var outputFile = parseResult.GetValue(_cameraTuningOutputFile);
|
||||
var gainR = parseResult.GetRequiredValue(_cameraTuningGainR);
|
||||
var gainG = parseResult.GetRequiredValue(_cameraTuningGainG);
|
||||
var gainB = parseResult.GetRequiredValue(_cameraTuningGainB);
|
||||
var threshold = parseResult.GetRequiredValue(_cameraTuningThreshold);
|
||||
var steps = parseResult.GetRequiredValue(_cameraTuningSteps);
|
||||
|
||||
var builder = Host.CreateApplicationBuilder();
|
||||
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Logging.AddConsole(options => options.FormatterName = nameof(ConsoleFormatter));
|
||||
builder.Logging.AddConsoleFormatter<ConsoleFormatter, ConsoleFormatterOptions>();
|
||||
builder.Logging.AddProvider(new FileLoggerProvider("full.log", true));
|
||||
builder.Logging.AddProvider(new FileLoggerProvider("last_run.log", false));
|
||||
builder.Services.AddSingleton<LibCameraLogSink>();
|
||||
|
||||
builder.Services.AddIlluminatorService("Hardware:Illuminator");
|
||||
builder.Services.AddCameraService("Hardware:Camera", true);
|
||||
|
||||
builder.Services.AddHostedService<CameraTuningWorker>(services =>
|
||||
{
|
||||
var logger = services.GetRequiredService<ILogger<CameraTuningWorker>>();
|
||||
var applicationLifetime = services.GetRequiredService<IHostApplicationLifetime>();
|
||||
var cameraService = services.GetRequiredService<CameraService>();
|
||||
var illuminatorService = services.GetRequiredService<IlluminatorService>();
|
||||
return new CameraTuningWorker(logger, applicationLifetime, cameraService, illuminatorService, outputFile, gainB, gainG, gainR, threshold, steps);
|
||||
});
|
||||
|
||||
var host = builder.Build();
|
||||
host.Services.GetRequiredService<LibCameraLogSink>();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
using System.CommandLine;
|
||||
|
||||
using GSS2.Core;
|
||||
using GSS2.Core.Hardware;
|
||||
using GSS2.Core.Logging;
|
||||
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
|
||||
using OpenCvSharp;
|
||||
|
||||
using ConsoleFormatter = GSS2.Core.Logging.ConsoleFormatter;
|
||||
|
||||
namespace GSS2.Test;
|
||||
|
||||
public partial class Program
|
||||
{
|
||||
private class CaptureWorker : BackgroundService
|
||||
{
|
||||
private readonly ILogger<CaptureWorker> _logger;
|
||||
private readonly IHostApplicationLifetime _applicationLifetime;
|
||||
private readonly CameraService _cameraService;
|
||||
private readonly IlluminatorService _illuminatorService;
|
||||
private readonly FileInfo _outputFile;
|
||||
private readonly double _intensityWhite;
|
||||
private readonly double _intensityUv365nm;
|
||||
private readonly double _intensityUv254nm;
|
||||
|
||||
public CaptureWorker(ILogger<CaptureWorker> logger, IHostApplicationLifetime applicationLifetime, CameraService cameraService, IlluminatorService illuminatorService, FileInfo outputFile, double intensityWhite, double intensityUv365nm, double intensityUv254nm)
|
||||
{
|
||||
_applicationLifetime = applicationLifetime;
|
||||
_logger = logger;
|
||||
_cameraService = cameraService;
|
||||
_illuminatorService = illuminatorService;
|
||||
_outputFile = outputFile;
|
||||
_intensityWhite = intensityWhite;
|
||||
_intensityUv365nm = intensityUv365nm;
|
||||
_intensityUv254nm = intensityUv254nm;
|
||||
|
||||
_logger.LogInformation("Initialized");
|
||||
_logger.LogInformation("Output File: {}", _outputFile);
|
||||
_logger.LogInformation("Intensity White: {}", _intensityWhite);
|
||||
_logger.LogInformation("Intensity UV 365 nm: {}", _intensityUv365nm);
|
||||
_logger.LogInformation("Intensity UV 254 nm: {}", _intensityUv254nm);
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("Running camera fine tuning");
|
||||
_illuminatorService.SetIntensity(_intensityWhite, _intensityUv365nm, _intensityUv254nm);
|
||||
_illuminatorService.TurnOn();
|
||||
|
||||
Mat? image;
|
||||
try
|
||||
{
|
||||
image = await _cameraService.CaptureImage(stoppingToken, 5);
|
||||
|
||||
if (image is null)
|
||||
{
|
||||
_logger.LogCritical("Cannot get image");
|
||||
_applicationLifetime.StopApplication();
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogCritical(ex, "Exception occurred while image capturing");
|
||||
_applicationLifetime.StopApplication();
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_illuminatorService.TurnOff();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
image.ImWrite(_outputFile.FullName);
|
||||
_logger.LogInformation("Image saved: {}", _outputFile.FullName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogCritical(ex, "Exception occurred while image saving");
|
||||
}
|
||||
|
||||
_applicationLifetime.StopApplication();
|
||||
}
|
||||
|
||||
}
|
||||
private static void Capture(ParseResult parseResult)
|
||||
{
|
||||
var outputFile = parseResult.GetRequiredValue(_captureOutputFile);
|
||||
var intensityWhite = parseResult.GetRequiredValue(_captureIntensityWhite);
|
||||
var intensityUv365nm = parseResult.GetRequiredValue(_captureIntensityUv365nm);
|
||||
var intensityUv254nm = parseResult.GetRequiredValue(_captureIntensityUv254nm);
|
||||
|
||||
var builder = Host.CreateApplicationBuilder();
|
||||
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Logging.AddConsole(options => options.FormatterName = nameof(ConsoleFormatter));
|
||||
builder.Logging.AddConsoleFormatter<ConsoleFormatter, ConsoleFormatterOptions>();
|
||||
builder.Logging.AddProvider(new FileLoggerProvider("full.log", true));
|
||||
builder.Logging.AddProvider(new FileLoggerProvider("last_run.log", false));
|
||||
builder.Services.AddSingleton<LibCameraLogSink>();
|
||||
|
||||
builder.Services.AddIlluminatorService("Hardware:Illuminator");
|
||||
builder.Services.AddCameraService("Hardware:Camera", true);
|
||||
|
||||
builder.Services.AddHostedService<CaptureWorker>(services =>
|
||||
{
|
||||
var logger = services.GetRequiredService<ILogger<CaptureWorker>>();
|
||||
var applicationLifetime = services.GetRequiredService<IHostApplicationLifetime>();
|
||||
var cameraService = services.GetRequiredService<CameraService>();
|
||||
var illuminatorService = services.GetRequiredService<IlluminatorService>();
|
||||
return new CaptureWorker(logger, applicationLifetime, cameraService, illuminatorService, outputFile, intensityWhite, intensityUv365nm, intensityUv254nm);
|
||||
});
|
||||
|
||||
var host = builder.Build();
|
||||
host.Services.GetRequiredService<LibCameraLogSink>();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
using System.CommandLine;
|
||||
|
||||
using GSS2.Core;
|
||||
using GSS2.Core.Analysis.AmineContent.Database.Calibration;
|
||||
using GSS2.Core.Hardware;
|
||||
using GSS2.Core.Logging;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
|
||||
using OpenCvSharp;
|
||||
|
||||
using ConsoleFormatter = GSS2.Core.Logging.ConsoleFormatter;
|
||||
|
||||
namespace GSS2.Test;
|
||||
|
||||
public partial class Program
|
||||
{
|
||||
private class ImagesStorageClearWorker : BackgroundService
|
||||
{
|
||||
private readonly ILogger<ImagesStorageClearWorker> _logger;
|
||||
private readonly IHostApplicationLifetime _applicationLifetime;
|
||||
private readonly AmineContentCalibrationContext _context;
|
||||
private readonly ImageStorageService _imageStorageService;
|
||||
|
||||
public ImagesStorageClearWorker(ILogger<ImagesStorageClearWorker> logger, IHostApplicationLifetime applicationLifetime, AmineContentCalibrationContext context, ImageStorageService imageStorageService)
|
||||
{
|
||||
_logger = logger;
|
||||
_applicationLifetime = applicationLifetime;
|
||||
_context = context;
|
||||
_imageStorageService = imageStorageService;
|
||||
|
||||
_logger.LogInformation("Initialized");
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("Running images storage clear");
|
||||
|
||||
var recordsFiles = _context.ImageRecords.Select(r => r.ImagePath);
|
||||
var storedFiles = _imageStorageService.ListFiles()
|
||||
.Select(Path.GetFileName)
|
||||
.OfType<string>();
|
||||
|
||||
var unusedFiles = storedFiles.Except(recordsFiles)
|
||||
.ToList()
|
||||
.Order();
|
||||
|
||||
if (unusedFiles is null || unusedFiles.Count() == 0)
|
||||
{
|
||||
_logger.LogInformation("Unused images not found");
|
||||
_applicationLifetime.StopApplication();
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Found {} unused image(s):\n\t{}", unusedFiles.Count(), string.Join("\n\t", unusedFiles));
|
||||
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogInformation("Delete this files? (y/n) ");
|
||||
var input = Console.ReadLine()?.Trim();
|
||||
if (input == "y")
|
||||
{
|
||||
foreach (var file in unusedFiles)
|
||||
_imageStorageService.Delete(file);
|
||||
break;
|
||||
}
|
||||
if (input == "n")
|
||||
break;
|
||||
}
|
||||
|
||||
_applicationLifetime.StopApplication();
|
||||
}
|
||||
|
||||
}
|
||||
private static void ImageStorageClear(ParseResult parseResult)
|
||||
{
|
||||
var builder = Host.CreateApplicationBuilder();
|
||||
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Logging.AddConsole(options => options.FormatterName = nameof(ConsoleFormatter));
|
||||
builder.Logging.AddConsoleFormatter<ConsoleFormatter, ConsoleFormatterOptions>();
|
||||
builder.Logging.AddProvider(new FileLoggerProvider("full.log", true));
|
||||
builder.Logging.AddProvider(new FileLoggerProvider("last_run.log", false));
|
||||
builder.Services.AddSingleton<LibCameraLogSink>();
|
||||
|
||||
builder.Services.AddAmineContentCalibrationContext(builder.Configuration);
|
||||
builder.Services.AddImageStorageService(new DirectoryInfo("images"));
|
||||
|
||||
builder.Services.AddHostedService<ImagesStorageClearWorker>();
|
||||
|
||||
var host = builder.Build();
|
||||
|
||||
using (var scope = host.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AmineContentCalibrationContext>();
|
||||
context.Database.Migrate();
|
||||
}
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
using System.CommandLine;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.OpenGL.Egl;
|
||||
|
||||
using GSS2.Core;
|
||||
using GSS2.Core.Logging;
|
||||
using GSS2.Core.Analysis.AmineContent.Database.Calibration;
|
||||
using GSS2.Core.Analysis.AmineContent.Database.Results;
|
||||
|
||||
using ConsoleFormatter = GSS2.Core.Logging.ConsoleFormatter;
|
||||
|
||||
namespace GSS2.Test;
|
||||
|
||||
public partial class Program
|
||||
{
|
||||
public static IHost ApplicationHost { get; } = BuildHostApp();
|
||||
public static bool IsFullscreen = false;
|
||||
|
||||
private static void Ui(ParseResult parseResult)
|
||||
{
|
||||
var builder = BuildAvaloniaApp();
|
||||
var fullscreen = parseResult.GetValue(_fullscreen);
|
||||
var renderingMode = parseResult.GetValue(_renderingMode);
|
||||
var hideConsole = parseResult.GetValue(_hideConsole);
|
||||
|
||||
IsFullscreen = fullscreen;
|
||||
|
||||
if (hideConsole)
|
||||
SilenceConsole();
|
||||
|
||||
switch (renderingMode)
|
||||
{
|
||||
case RenderingMode.X11:
|
||||
builder.StartWithClassicDesktopLifetime(_args?.ToArray() ?? []);
|
||||
break;
|
||||
case RenderingMode.DRM:
|
||||
builder.StartLinuxDrm(_args?.ToArray() ?? [], "/dev/dri/card1", 1.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SilenceConsole()
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
Console.CursorVisible = false;
|
||||
while (true)
|
||||
Console.ReadKey(true);
|
||||
})
|
||||
{ IsBackground = true }.Start();
|
||||
}
|
||||
|
||||
private static IHost BuildHostApp()
|
||||
{
|
||||
var builder = Host.CreateApplicationBuilder();
|
||||
|
||||
builder.Logging.ClearProviders();
|
||||
builder.Logging.AddConsole(options => options.FormatterName = nameof(ConsoleFormatter));
|
||||
builder.Logging.AddConsoleFormatter<ConsoleFormatter, ConsoleFormatterOptions>();
|
||||
builder.Logging.AddProvider(new FileLoggerProvider("full.log", true));
|
||||
builder.Logging.AddProvider(new FileLoggerProvider("last_run.log", false));
|
||||
builder.Services.AddSingleton<LibCameraLogSink>();
|
||||
|
||||
builder.Services.AddAmineContentCalibrationContext(builder.Configuration);
|
||||
builder.Services.AddAmineContentResultsContext(builder.Configuration);
|
||||
|
||||
builder.Services.AddLightsService("Hardware:Lights");
|
||||
builder.Services.AddTemperatureHumidityService("Hardware:TemperatureHumidity");
|
||||
builder.Services.AddIlluminatorService("Hardware:Illuminator");
|
||||
builder.Services.AddCameraService("Hardware:Camera", true);
|
||||
builder.Services.AddComputeResourcesService();
|
||||
builder.Services.AddImageStorageService(new DirectoryInfo("images"));
|
||||
|
||||
builder.Services.AddViewsAndModels();
|
||||
|
||||
var host = builder.Build();
|
||||
host.Services.GetRequiredService<LibCameraLogSink>();
|
||||
|
||||
using (var scope = host.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AmineContentCalibrationContext>();
|
||||
context.Database.Migrate();
|
||||
}
|
||||
using (var scope = host.Services.CreateScope())
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<AmineContentResultsContext>();
|
||||
context.Database.Migrate();
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
private static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.UseSkia()
|
||||
.LogToTrace()
|
||||
.With(new X11PlatformOptions
|
||||
{
|
||||
RenderingMode = [X11RenderingMode.Egl]
|
||||
})
|
||||
.With(new EglDisplayOptions
|
||||
{
|
||||
SupportsContextSharing = true
|
||||
});
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using GSS2.Core.Hardware;
|
||||
using GSS2.UI.Core.ViewModels;
|
||||
|
||||
namespace GSS2.Test.ViewModels;
|
||||
|
||||
public partial class MainViewModel : ViewModelBase
|
||||
{
|
||||
private readonly ILogger<MainViewModel> _logger;
|
||||
private readonly CameraService _cameraService;
|
||||
private readonly IlluminatorService _illuminatorService;
|
||||
|
||||
[ObservableProperty] private CameraViewModel _cameraViewModel;
|
||||
[ObservableProperty] private ResourcesViewModel _resourcesViewModel;
|
||||
[ObservableProperty] private IlluminatorControllerViewModel _illuminatorControllerViewModel;
|
||||
[ObservableProperty] private OpenCvSharp.Mat? _image1;
|
||||
[ObservableProperty] private OpenCvSharp.Mat? _image2;
|
||||
[ObservableProperty] private OpenCvSharp.Mat? _image3;
|
||||
[ObservableProperty] private OpenCvSharp.Mat? _image4;
|
||||
[ObservableProperty] private IRelayCommand _buttonCaptureClick;
|
||||
[ObservableProperty] private IRelayCommand _buttonUpClick;
|
||||
[ObservableProperty] private IRelayCommand _buttonDownClick;
|
||||
[ObservableProperty] private int _currentIndex;
|
||||
[ObservableProperty] private bool _canScrollForward;
|
||||
[ObservableProperty] private bool _canScrollBackward;
|
||||
|
||||
public MainViewModel(ILogger<MainViewModel> logger, CameraViewModel cameraViewModel, ResourcesViewModel resourcesViewModel, IlluminatorControllerViewModel illuminatorControllerViewModel, CameraService cameraService, IlluminatorService illuminatorService)
|
||||
{
|
||||
_logger = logger;
|
||||
_logger.LogInformation("Initialization");
|
||||
|
||||
_cameraService = cameraService;
|
||||
_illuminatorService = illuminatorService;
|
||||
CameraViewModel = cameraViewModel;
|
||||
ResourcesViewModel = resourcesViewModel;
|
||||
IlluminatorControllerViewModel = illuminatorControllerViewModel;
|
||||
ButtonCaptureClick = new RelayCommand(() =>
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
_illuminatorService.TurnOn();
|
||||
_illuminatorService.SetIntensity(1, 0, 0);
|
||||
await _cameraService.CaptureImage(CancellationToken.None, 3).ContinueWith(image => Image1 = image.Result);
|
||||
_illuminatorService.SetIntensity(0, 1, 1);
|
||||
await _cameraService.CaptureImage(CancellationToken.None, 3).ContinueWith(image => Image2 = image.Result);
|
||||
_illuminatorService.SetIntensity(0, 1, 0);
|
||||
await _cameraService.CaptureImage(CancellationToken.None, 3).ContinueWith(image => Image3 = image.Result);
|
||||
_illuminatorService.SetIntensity(0, 0, 1);
|
||||
await _cameraService.CaptureImage(CancellationToken.None, 3).ContinueWith(image => Image4 = image.Result);
|
||||
_illuminatorService.SetIntensity(0, 0, 0);
|
||||
_illuminatorService.TurnOff();
|
||||
});
|
||||
});
|
||||
ButtonUpClick = new RelayCommand(() => CurrentIndex--);
|
||||
ButtonDownClick = new RelayCommand(() => CurrentIndex++);
|
||||
|
||||
_logger.LogInformation("Initialized");
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="GSS2.Test.Views.MainView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:core="using:GSS2.UI.Core"
|
||||
xmlns:core_vm="using:GSS2.UI.Core.ViewModels"
|
||||
xmlns:local_vm="using:GSS2.Test.ViewModels"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
x:DataType="local_vm:MainViewModel">
|
||||
|
||||
<Grid ColumnDefinitions="*,100" RowDefinitions="*,*">
|
||||
|
||||
<core:SectionPanel
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="0"
|
||||
CanScrollBackward="{Binding CanScrollBackward}"
|
||||
CanScrollForward="{Binding CanScrollForward}"
|
||||
ClipToBounds="True"
|
||||
CurrentIndex="{Binding CurrentIndex}">
|
||||
|
||||
<Grid ColumnDefinitions="300,*">
|
||||
|
||||
<ContentControl
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="{Binding IlluminatorControllerViewModel}" />
|
||||
|
||||
<ContentControl
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="{Binding CameraViewModel}" />
|
||||
|
||||
</Grid>
|
||||
|
||||
<Grid ColumnDefinitions="100,*">
|
||||
|
||||
<Button
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Command="{Binding ButtonCaptureClick}" />
|
||||
|
||||
<Grid
|
||||
Grid.Column="1"
|
||||
ColumnDefinitions="*,*"
|
||||
RowDefinitions="*,*">
|
||||
|
||||
<core:OpenCvImage
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Image="{Binding Image1}" />
|
||||
|
||||
<core:OpenCvImage
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Image="{Binding Image2}" />
|
||||
|
||||
<core:OpenCvImage
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Image="{Binding Image3}" />
|
||||
|
||||
<core:OpenCvImage
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Image="{Binding Image4}" />
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
<ContentControl
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="{Binding ResourcesViewModel}" />
|
||||
|
||||
</core:SectionPanel>
|
||||
|
||||
<Button
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Command="{Binding ButtonUpClick}"
|
||||
IsEnabled="{Binding CanScrollBackward}" />
|
||||
|
||||
<Button
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Command="{Binding ButtonDownClick}"
|
||||
IsEnabled="{Binding CanScrollForward}" />
|
||||
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -1,15 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace GSS2.Test.Views;
|
||||
|
||||
public partial class MainView : UserControl
|
||||
{
|
||||
private readonly ILogger<MainView> _logger;
|
||||
|
||||
public MainView(ILogger<MainView> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
InitializeComponent();
|
||||
_logger.LogInformation("{} initialized", nameof(MainView));
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<!-- This manifest is used on Windows only.
|
||||
Don't remove it as it might cause problems with window transparency and embedded controls.
|
||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||
<assemblyIdentity version="1.0.0.0" name="GSS2.Test.Desktop"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
@@ -1,82 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.Hosting.Lifetime": "Information",
|
||||
"Microsoft.EntityFrameworkCore.Migrations": "Warning",
|
||||
"Microsoft.EntityFrameworkCore.Database.Command": "Warning",
|
||||
"GSS2.Core.Hardware.LightsService": "Information",
|
||||
"GSS2.Core.Hardware.IlluminatorService": "Information",
|
||||
"GSS2.Core.Hardware.CameraService": "Information",
|
||||
"LibCamera": "Information",
|
||||
"LibCamera-Camera": "Information",
|
||||
"LibCamera-RPI": "Information",
|
||||
"LibCamera-DeviceEnumerator": "Information",
|
||||
"LibCamera-IPAProxy": "Information",
|
||||
"LibCamera-V4L2": "Information",
|
||||
"LibCamera-RPISTREAM": "Information",
|
||||
"LibCamera-WRAPPER": "Information",
|
||||
"Avalonia.*": "Warning"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"AmineContentCalibrationDatabasePath": "AmineContentCalibration.db",
|
||||
"AmineContentResultsDatabasePath": "AmineContentResults.db"
|
||||
},
|
||||
"Hardware": {
|
||||
"Illuminator": {
|
||||
"WhitePwmPin": 13,
|
||||
"Uv254PwmPin": 18,
|
||||
"Uv365PwmPin": 12,
|
||||
"WhiteRelayPin": 16,
|
||||
"Uv254RelayPin": 15,
|
||||
"Uv365RelayPin": 20,
|
||||
"FanPin": 21,
|
||||
"PwmFrequency": 200,
|
||||
"MaxWhitePwmDuty": 1.0,
|
||||
"MaxUv254PwmDuty": 1.0,
|
||||
"MaxUv365PwmDuty": 1.0
|
||||
},
|
||||
"Camera": {
|
||||
"CameraId": "/base/axi/pcie@1000120000/rp1/i2c@70000/imx477@1a",
|
||||
"ViewFinderFrameBufferCount": 5,
|
||||
"ViewFinderWidth": 4056,
|
||||
"ViewFinderHeight": 3040,
|
||||
"ViewFinderFps": 30,
|
||||
"ImageCaptureFrameBufferCount": 5,
|
||||
"ImageCaptureWidth": 4056,
|
||||
"ImageCaptureHeight": 3040,
|
||||
"CameraHardSettings": {
|
||||
"AeEnable": false,
|
||||
"ExposureValue": 8.0,
|
||||
"ExposureTime": 30000,
|
||||
"ExposureTimeMode": "ExposureTimeModeManual",
|
||||
"AnalogueGain": 23.0,
|
||||
"AnalogueGainMode": "AnalogueGainModeManual",
|
||||
"Brightness": 0.0,
|
||||
"Contrast": 1.0,
|
||||
"AwbEnable": false,
|
||||
"ColourGains": [
|
||||
3.2,
|
||||
1.0
|
||||
],
|
||||
"HdrMode": "HdrModeOff",
|
||||
"NoiseReductionMode": "NoiseReductionModeOff",
|
||||
"StatsOutputEnable": true,
|
||||
"SyncMode": "SyncModeOff",
|
||||
"CnnEnableInputTensor": false
|
||||
},
|
||||
"DecodeGainR": 3.2,
|
||||
"DecodeGainG": 1.0,
|
||||
"DecodeGainB": 1.0,
|
||||
"DecodeBlackLevel": 4096
|
||||
},
|
||||
"TemperatureHumidity": {
|
||||
"Bus": 6,
|
||||
"Address": 69
|
||||
},
|
||||
"Lights": {
|
||||
"ServerAddress": "http://127.0.0.1:50051"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user