mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 11:16:30 +00:00
rework to Azaion.Suite, show tabs with annotator and dataset explorer
This commit is contained in:
@@ -102,9 +102,6 @@ public partial class Annotator
|
|||||||
|
|
||||||
if (LvFiles.Items.IsEmpty)
|
if (LvFiles.Items.IsEmpty)
|
||||||
BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.Initial]);
|
BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.Initial]);
|
||||||
|
|
||||||
if (_appConfig.WindowConfig.ShowHelpOnStart)
|
|
||||||
_helpWindow.Show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BlinkHelp(string helpText, int times = 2)
|
public void BlinkHelp(string helpText, int times = 2)
|
||||||
@@ -541,7 +538,6 @@ public partial class Annotator
|
|||||||
|
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
using var detector = new YOLODetector(_appConfig.AIRecognitionConfig);
|
|
||||||
Dispatcher.Invoke(() => _autoDetectDialog.Log("Ініціалізація AI..."));
|
Dispatcher.Invoke(() => _autoDetectDialog.Log("Ініціалізація AI..."));
|
||||||
var prevSeekTime = 0.0;
|
var prevSeekTime = 0.0;
|
||||||
|
|
||||||
@@ -549,7 +545,7 @@ public partial class Annotator
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var detections = _aiDetector.Detect(timeframe.Stream);
|
var detections = await _aiDetector.Detect(timeframe.Stream, token);
|
||||||
if (timeframe.Time.TotalSeconds > prevSeekTime + 1)
|
if (timeframe.Time.TotalSeconds > prevSeekTime + 1)
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(() => SeekTo(timeframe.Time));
|
Dispatcher.Invoke(() => SeekTo(timeframe.Time));
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Azaion.Annotator.DTO;
|
using Azaion.Annotator.DTO;
|
||||||
using Azaion.Common.DTO;
|
using Azaion.Common.DTO;
|
||||||
|
using Azaion.Common.DTO.Config;
|
||||||
using LibVLCSharp.Shared;
|
using LibVLCSharp.Shared;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="libc.translation" Version="7.1.1" />
|
<PackageReference Include="libc.translation" Version="7.1.1" />
|
||||||
<PackageReference Include="LibVLCSharp" Version="3.8.2" />
|
<PackageReference Include="LibVLCSharp" Version="3.9.1" />
|
||||||
<PackageReference Include="LibVLCSharp.WPF" Version="3.8.2" />
|
<PackageReference Include="LibVLCSharp.WPF" Version="3.9.1" />
|
||||||
<PackageReference Include="MediatR" Version="12.4.1" />
|
<PackageReference Include="MediatR" Version="12.4.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
|
||||||
@@ -26,16 +26,13 @@
|
|||||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
<PackageReference Include="SkiaSharp" Version="2.88.9" />
|
<PackageReference Include="SkiaSharp" Version="2.88.9" />
|
||||||
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.20" />
|
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.21" />
|
||||||
<PackageReference Include="WindowsAPICodePack" Version="7.0.4" />
|
<PackageReference Include="WindowsAPICodePack" Version="7.0.4" />
|
||||||
<PackageReference Include="YoloV8.Gpu" Version="5.0.4" />
|
<PackageReference Include="YoloV8.Gpu" Version="5.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="logo.ico" />
|
<None Remove="logo.ico" />
|
||||||
<None Update="config.json">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Azaion.Annotator.Extensions;
|
|
||||||
using Azaion.Common.DTO;
|
using Azaion.Common.DTO;
|
||||||
using Azaion.Common.DTO.Config;
|
|
||||||
using Azaion.Common.Extensions;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Azaion.Annotator.DTO;
|
namespace Azaion.Annotator.DTO;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using Azaion.Common.DTO.Config;
|
using Azaion.Common.DTO.Config;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Azaion.Annotator;
|
namespace Azaion.Annotator;
|
||||||
|
|
||||||
@@ -7,14 +8,19 @@ public partial class HelpWindow : Window
|
|||||||
{
|
{
|
||||||
private readonly WindowConfig _windowConfig;
|
private readonly WindowConfig _windowConfig;
|
||||||
|
|
||||||
public HelpWindow(WindowConfig windowConfig)
|
public HelpWindow(IOptions<WindowConfig> windowConfig)
|
||||||
{
|
{
|
||||||
_windowConfig = windowConfig;
|
_windowConfig = windowConfig.Value;
|
||||||
Loaded += (_, _) => CbShowHelp.IsChecked = windowConfig.ShowHelpOnStart;
|
Loaded += (_, _) => CbShowHelp.IsChecked = _windowConfig.ShowHelpOnStart;
|
||||||
|
Closing += (sender, args) =>
|
||||||
|
{
|
||||||
|
args.Cancel = true;
|
||||||
|
Visibility = Visibility.Hidden;
|
||||||
|
};
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
private void Close(object sender, RoutedEventArgs e) => Close();
|
|
||||||
|
|
||||||
private void CbShowHelp_OnChecked(object sender, RoutedEventArgs e) => _windowConfig.ShowHelpOnStart = true;
|
private void CbShowHelp_OnChecked(object sender, RoutedEventArgs e) => _windowConfig.ShowHelpOnStart = true;
|
||||||
private void CbShowHelp_OnUnchecked(object sender, RoutedEventArgs e) => _windowConfig.ShowHelpOnStart = false;
|
private void CbShowHelp_OnUnchecked(object sender, RoutedEventArgs e) => _windowConfig.ShowHelpOnStart = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
using Azaion.Annotator.DTO;
|
using Azaion.Annotator.DTO;
|
||||||
using Azaion.Annotator.Extensions;
|
using Azaion.Annotator.Extensions;
|
||||||
using Azaion.Common.DTO;
|
using Azaion.Common.DTO;
|
||||||
|
using Azaion.Common.DTO.Config;
|
||||||
|
using Azaion.Common.Services;
|
||||||
using Compunet.YoloV8;
|
using Compunet.YoloV8;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
@@ -12,18 +14,27 @@ namespace Azaion.Annotator;
|
|||||||
|
|
||||||
public interface IAIDetector
|
public interface IAIDetector
|
||||||
{
|
{
|
||||||
List<Detection> Detect(Stream stream);
|
Task<List<Detection>> Detect(Stream imageStream, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class YOLODetector(AIRecognitionConfig recognitionConfig) : IAIDetector, IDisposable
|
public class YOLODetector(IOptions<AIRecognitionConfig> recognitionConfig, IResourceLoader resourceLoader) : IAIDetector, IDisposable
|
||||||
{
|
{
|
||||||
private readonly YoloPredictor _predictor = new(recognitionConfig.AIModelPath);
|
private readonly AIRecognitionConfig _recognitionConfig = recognitionConfig.Value;
|
||||||
|
private YoloPredictor? _predictor;
|
||||||
|
private const string YOLO_MODEL = "azaion.onnx";
|
||||||
|
|
||||||
public List<Detection> Detect(Stream stream)
|
|
||||||
|
public async Task<List<Detection>> Detect(Stream imageStream, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
stream.Seek(0, SeekOrigin.Begin);
|
if (_predictor == null)
|
||||||
var image = Image.Load<Rgb24>(stream);
|
{
|
||||||
var result = _predictor.Detect(image);
|
await using var stream = await resourceLoader.Load(YOLO_MODEL, cancellationToken);
|
||||||
|
_predictor = new YoloPredictor(stream.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
imageStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
var image = Image.Load<Rgb24>(imageStream);
|
||||||
|
var result = await _predictor.DetectAsync(image);
|
||||||
|
|
||||||
var imageSize = new System.Windows.Size(image.Width, image.Height);
|
var imageSize = new System.Windows.Size(image.Width, image.Height);
|
||||||
|
|
||||||
@@ -38,7 +49,7 @@ public class YOLODetector(AIRecognitionConfig recognitionConfig) : IAIDetector,
|
|||||||
|
|
||||||
private List<Detection> FilterOverlapping(List<Detection> detections)
|
private List<Detection> FilterOverlapping(List<Detection> detections)
|
||||||
{
|
{
|
||||||
var k = recognitionConfig.TrackingIntersectionThreshold;
|
var k = _recognitionConfig.TrackingIntersectionThreshold;
|
||||||
var filteredDetections = new List<Detection>();
|
var filteredDetections = new List<Detection>();
|
||||||
for (var i = 0; i < detections.Count; i++)
|
for (var i = 0; i < detections.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -73,5 +84,5 @@ public class YOLODetector(AIRecognitionConfig recognitionConfig) : IAIDetector,
|
|||||||
return filteredDetections;
|
return filteredDetections;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() => _predictor.Dispose();
|
public void Dispose() => _predictor?.Dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
{
|
|
||||||
"VideosDirectory": "E:\\Azaion1\\Videos",
|
|
||||||
"LabelsDirectory": "E:\\labels",
|
|
||||||
"ImagesDirectory": "E:\\images",
|
|
||||||
"ThumbnailsDirectory": "E:\\thumbnails",
|
|
||||||
"ResultsDirectory": "E:\\results",
|
|
||||||
"UnknownImages": "E:\\unknown",
|
|
||||||
"AnnotationClasses": [
|
|
||||||
{ "Id": 0, "Name": "Броньована техніка", "ShortName": "Бронь" },
|
|
||||||
{ "Id": 1, "Name": "Вантажівка", "ShortName": "Вантаж" },
|
|
||||||
{ "Id": 2, "Name": "Машина легкова", "ShortName": "Машина" },
|
|
||||||
{ "Id": 3, "Name": "Артилерія", "ShortName": "Арта" },
|
|
||||||
{ "Id": 4, "Name": "Тінь від техніки", "ShortName": "Тінь" },
|
|
||||||
{ "Id": 5, "Name": "Окопи", "ShortName": "Окопи" },
|
|
||||||
{ "Id": 6, "Name": "Військовий", "ShortName": "Військов" },
|
|
||||||
{ "Id": 7, "Name": "Накати", "ShortName": "Накати" },
|
|
||||||
{ "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк захист" },
|
|
||||||
{ "Id": 9, "Name": "Дим", "ShortName": "Дим" },
|
|
||||||
{ "Id": 10, "Name": "Літак", "ShortName": "Літак" }
|
|
||||||
],
|
|
||||||
"MainWindowConfig": {
|
|
||||||
"WindowSize": "1920,1080",
|
|
||||||
"WindowLocation": "50,50",
|
|
||||||
"FullScreen": true
|
|
||||||
},
|
|
||||||
"DatasetExplorerConfig": {
|
|
||||||
"WindowSize": "1920,1080",
|
|
||||||
"WindowLocation": "50,50",
|
|
||||||
"FullScreen": true
|
|
||||||
},
|
|
||||||
"ThumbnailConfig": {
|
|
||||||
"Size": "480,270",
|
|
||||||
"Border": 10
|
|
||||||
},
|
|
||||||
"LeftPanelWidth": 300,
|
|
||||||
"RightPanelWidth": 300,
|
|
||||||
"ShowHelpOnStart": false,
|
|
||||||
"VideoFormats": ["mov", "mp4"],
|
|
||||||
"ImageFormats": ["jpg", "jpeg", "png", "bmp", "gif"],
|
|
||||||
"AIRecognitionConfig": {
|
|
||||||
"AIModelPath": "azaion.onnx",
|
|
||||||
"FrameRecognitionSeconds": 2,
|
|
||||||
"TrackingDistanceConfidence": 0.15,
|
|
||||||
"TrackingProbabilityIncrease": 15,
|
|
||||||
"TrackingIntersectionThreshold": 0.8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
<PackageReference Include="MediatR" Version="12.4.1" />
|
<PackageReference Include="MediatR" Version="12.4.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
+39
-18
@@ -5,9 +5,17 @@ namespace Azaion.Common;
|
|||||||
|
|
||||||
public class Constants
|
public class Constants
|
||||||
{
|
{
|
||||||
#region DefaultConfig
|
|
||||||
|
|
||||||
public const string CONFIG_PATH = "config.json";
|
public const string CONFIG_PATH = "config.json";
|
||||||
|
public const string DEFAULT_DLL_CACHE_DIR = "DllCache";
|
||||||
|
|
||||||
|
#region ApiConfig
|
||||||
|
|
||||||
|
public const string DEFAULT_API_URL = "https://api.azaion.com/";
|
||||||
|
public const int DEFAULT_API_RETRY_COUNT = 3;
|
||||||
|
public const int DEFAULT_API_TIMEOUT_SECONDS = 40;
|
||||||
|
#endregion ApiConfig
|
||||||
|
|
||||||
|
#region DirectoriesConfig
|
||||||
|
|
||||||
public const string DEFAULT_VIDEO_DIR = "video";
|
public const string DEFAULT_VIDEO_DIR = "video";
|
||||||
public const string DEFAULT_LABELS_DIR = "labels";
|
public const string DEFAULT_LABELS_DIR = "labels";
|
||||||
@@ -15,24 +23,9 @@ public class Constants
|
|||||||
public const string DEFAULT_RESULTS_DIR = "results";
|
public const string DEFAULT_RESULTS_DIR = "results";
|
||||||
public const string DEFAULT_THUMBNAILS_DIR = "thumbnails";
|
public const string DEFAULT_THUMBNAILS_DIR = "thumbnails";
|
||||||
|
|
||||||
public const int DEFAULT_THUMBNAIL_BORDER = 10;
|
|
||||||
public const double DEFAULT_FRAME_RECOGNITION_SECONDS = 2;
|
|
||||||
public const double TRACKING_DISTANCE_CONFIDENCE = 0.15;
|
|
||||||
public const double TRACKING_PROBABILITY_INCREASE = 15;
|
|
||||||
public const double TRACKING_INTERSECTION_THRESHOLD = 0.8;
|
|
||||||
|
|
||||||
public static readonly Size DefaultWindowSize = new(1280, 720);
|
|
||||||
public static readonly Point DefaultWindowLocation = new(100, 100);
|
|
||||||
public static readonly Size DefaultThumbnailSize = new(240, 135);
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Thumbnails
|
#region AnnotatorConfig
|
||||||
|
|
||||||
public const string THUMBNAIL_PREFIX = "_thumb";
|
|
||||||
public const string THUMBNAILS_CACHE_FILE = "thumbnails.cache";
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public static readonly List<AnnotationClass> DefaultAnnotationClasses =
|
public static readonly List<AnnotationClass> DefaultAnnotationClasses =
|
||||||
[
|
[
|
||||||
@@ -52,6 +45,34 @@ public class Constants
|
|||||||
public static readonly List<string> DefaultVideoFormats = ["mp4", "mov", "avi"];
|
public static readonly List<string> DefaultVideoFormats = ["mp4", "mov", "avi"];
|
||||||
public static readonly List<string> DefaultImageFormats = ["jpg", "jpeg", "png", "bmp"];
|
public static readonly List<string> DefaultImageFormats = ["jpg", "jpeg", "png", "bmp"];
|
||||||
|
|
||||||
|
# endregion AnnotatorConfig
|
||||||
|
|
||||||
|
# region AIRecognitionConfig
|
||||||
|
|
||||||
|
public const double DEFAULT_FRAME_RECOGNITION_SECONDS = 2;
|
||||||
|
public const double TRACKING_DISTANCE_CONFIDENCE = 0.15;
|
||||||
|
public const double TRACKING_PROBABILITY_INCREASE = 15;
|
||||||
|
public const double TRACKING_INTERSECTION_THRESHOLD = 0.8;
|
||||||
|
|
||||||
|
# endregion AIRecognitionConfig
|
||||||
|
|
||||||
|
# region WindowConfig
|
||||||
|
|
||||||
|
public static readonly Size DefaultWindowSize = new(1280, 720);
|
||||||
|
public static readonly Point DefaultWindowLocation = new(100, 100);
|
||||||
|
public static readonly Size DefaultThumbnailSize = new(240, 135);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Thumbnails
|
||||||
|
|
||||||
|
public const int DEFAULT_THUMBNAIL_BORDER = 10;
|
||||||
|
|
||||||
|
public const string THUMBNAIL_PREFIX = "_thumb";
|
||||||
|
public const string THUMBNAILS_CACHE_FILE = "thumbnails.cache";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public static TimeSpan? GetTime(string imagePath)
|
public static TimeSpan? GetTime(string imagePath)
|
||||||
{
|
{
|
||||||
var timeStr = imagePath.Split("_").LastOrDefault();
|
var timeStr = imagePath.Split("_").LastOrDefault();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media;
|
|
||||||
using Azaion.Common.Extensions;
|
using Azaion.Common.Extensions;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Azaion.Common.DTO;
|
namespace Azaion.Common.DTO;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
namespace Azaion.Annotator.DTO;
|
namespace Azaion.Common.DTO.Config;
|
||||||
|
|
||||||
public class AIRecognitionConfig
|
public class AIRecognitionConfig
|
||||||
{
|
{
|
||||||
public string AIModelPath { get; set; } = null!;
|
|
||||||
public double FrameRecognitionSeconds { get; set; }
|
public double FrameRecognitionSeconds { get; set; }
|
||||||
public double TrackingDistanceConfidence { get; set; }
|
public double TrackingDistanceConfidence { get; set; }
|
||||||
public double TrackingProbabilityIncrease { get; set; }
|
public double TrackingProbabilityIncrease { get; set; }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Azaion.Suite.Services.DTO;
|
namespace Azaion.Common.DTO.Config;
|
||||||
|
|
||||||
public class ApiConfig
|
public class ApiConfig
|
||||||
{
|
{
|
||||||
@@ -6,8 +6,3 @@ public class ApiConfig
|
|||||||
public int RetryCount {get;set;}
|
public int RetryCount {get;set;}
|
||||||
public double TimeoutSeconds { get; set; }
|
public double TimeoutSeconds { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LocalFilesConfig
|
|
||||||
{
|
|
||||||
public string DllPath { get; set; } = null!;
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Azaion.Annotator.DTO;
|
|
||||||
using Azaion.Suite.Services.DTO;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Azaion.Common.DTO.Config;
|
namespace Azaion.Common.DTO.Config;
|
||||||
@@ -11,14 +8,14 @@ public class AppConfig
|
|||||||
{
|
{
|
||||||
public ApiConfig ApiConfig { get; set; } = null!;
|
public ApiConfig ApiConfig { get; set; } = null!;
|
||||||
|
|
||||||
|
public DirectoriesConfig DirectoriesConfig { get; set; } = null!;
|
||||||
|
|
||||||
public AnnotationConfig AnnotationConfig { get; set; } = null!;
|
public AnnotationConfig AnnotationConfig { get; set; } = null!;
|
||||||
|
|
||||||
public WindowConfig WindowConfig { get; set; } = null!;
|
public WindowConfig WindowConfig { get; set; } = null!;
|
||||||
|
|
||||||
public AIRecognitionConfig AIRecognitionConfig { get; set; } = null!;
|
public AIRecognitionConfig AIRecognitionConfig { get; set; } = null!;
|
||||||
|
|
||||||
public DirectoriesConfig DirectoriesConfig { get; set; } = null!;
|
|
||||||
|
|
||||||
public ThumbnailConfig ThumbnailConfig { get; set; } = null!;
|
public ThumbnailConfig ThumbnailConfig { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +37,13 @@ public class ConfigUpdater : IConfigUpdater
|
|||||||
|
|
||||||
var appConfig = new AppConfig
|
var appConfig = new AppConfig
|
||||||
{
|
{
|
||||||
|
ApiConfig = new ApiConfig
|
||||||
|
{
|
||||||
|
Url = Constants.DEFAULT_API_URL,
|
||||||
|
RetryCount = Constants.DEFAULT_API_RETRY_COUNT,
|
||||||
|
TimeoutSeconds = Constants.DEFAULT_API_TIMEOUT_SECONDS
|
||||||
|
},
|
||||||
|
|
||||||
AnnotationConfig = new AnnotationConfig
|
AnnotationConfig = new AnnotationConfig
|
||||||
{
|
{
|
||||||
AnnotationClasses = Constants.DefaultAnnotationClasses,
|
AnnotationClasses = Constants.DefaultAnnotationClasses,
|
||||||
@@ -51,7 +55,6 @@ public class ConfigUpdater : IConfigUpdater
|
|||||||
{
|
{
|
||||||
WindowSize = Constants.DefaultWindowSize,
|
WindowSize = Constants.DefaultWindowSize,
|
||||||
WindowLocation = Constants.DefaultWindowLocation,
|
WindowLocation = Constants.DefaultWindowLocation,
|
||||||
ShowHelpOnStart = true,
|
|
||||||
FullScreen = true,
|
FullScreen = true,
|
||||||
LeftPanelWidth = 250,
|
LeftPanelWidth = 250,
|
||||||
RightPanelWidth = 250,
|
RightPanelWidth = 250,
|
||||||
@@ -74,7 +77,6 @@ public class ConfigUpdater : IConfigUpdater
|
|||||||
|
|
||||||
AIRecognitionConfig = new AIRecognitionConfig
|
AIRecognitionConfig = new AIRecognitionConfig
|
||||||
{
|
{
|
||||||
AIModelPath = "azaion.onnx",
|
|
||||||
FrameRecognitionSeconds = Constants.DEFAULT_FRAME_RECOGNITION_SECONDS,
|
FrameRecognitionSeconds = Constants.DEFAULT_FRAME_RECOGNITION_SECONDS,
|
||||||
TrackingDistanceConfidence = Constants.TRACKING_DISTANCE_CONFIDENCE,
|
TrackingDistanceConfidence = Constants.TRACKING_DISTANCE_CONFIDENCE,
|
||||||
TrackingProbabilityIncrease = Constants.TRACKING_PROBABILITY_INCREASE,
|
TrackingProbabilityIncrease = Constants.TRACKING_PROBABILITY_INCREASE,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Azaion.Common.DTO;
|
namespace Azaion.Common.DTO.Config;
|
||||||
|
|
||||||
public class DirectoriesConfig
|
public class DirectoriesConfig
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
namespace Azaion.Suite;
|
namespace Azaion.Common.DTO;
|
||||||
|
|
||||||
public class HardwareInfo
|
public class HardwareInfo
|
||||||
{
|
{
|
||||||
public string CPU { get; set; } = null!;
|
public string CPU { get; set; } = null!;
|
||||||
public string GPU { get; set; } = null!;
|
public string GPU { get; set; } = null!;
|
||||||
|
public string MacAddress { get; set; } = null!;
|
||||||
public string Memory { get; set; } = null!;
|
public string Memory { get; set; } = null!;
|
||||||
|
|
||||||
public string Hash { get; set; } = null!;
|
public string Hash { get; set; } = null!;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Azaion.Common.Extensions;
|
||||||
|
|
||||||
|
public static class ServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection ConfigureSection<T>(this IServiceCollection services, IConfiguration config) where T: class =>
|
||||||
|
services.Configure<T>(config.GetSection(typeof(T).Name));
|
||||||
|
}
|
||||||
+11
-5
@@ -4,12 +4,12 @@ using System.Net.Http;
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Azaion.Suite.Services.DTO;
|
using Azaion.Common.DTO;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Azaion.Suite.Services;
|
namespace Azaion.Common.Services;
|
||||||
|
|
||||||
public class AzaionApiClient(HttpClient httpClient)
|
public class AzaionApiClient(HttpClient httpClient) : IDisposable
|
||||||
{
|
{
|
||||||
const string JSON_MEDIA = "application/json";
|
const string JSON_MEDIA = "application/json";
|
||||||
|
|
||||||
@@ -26,11 +26,11 @@ public class AzaionApiClient(HttpClient httpClient)
|
|||||||
Password = password.ToSecureString();
|
Password = password.ToSecureString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Stream> GetResource(string password, HardwareInfo hardware, ResourceEnum resourceEnum)
|
public async Task<Stream> GetResource(string fileName, string password, HardwareInfo hardware)
|
||||||
{
|
{
|
||||||
var response = await Send(httpClient, new HttpRequestMessage(HttpMethod.Post, "/resources/get")
|
var response = await Send(httpClient, new HttpRequestMessage(HttpMethod.Post, "/resources/get")
|
||||||
{
|
{
|
||||||
Content = new StringContent(JsonConvert.SerializeObject(new { password, hardware, resourceEnum }), Encoding.UTF8, JSON_MEDIA)
|
Content = new StringContent(JsonConvert.SerializeObject(new { fileName, password, hardware }), Encoding.UTF8, JSON_MEDIA)
|
||||||
});
|
});
|
||||||
return await response.Content.ReadAsStreamAsync();
|
return await response.Content.ReadAsStreamAsync();
|
||||||
}
|
}
|
||||||
@@ -82,4 +82,10 @@ public class AzaionApiClient(HttpClient httpClient)
|
|||||||
var result = await response.Content.ReadAsStringAsync();
|
var result = await response.Content.ReadAsStringAsync();
|
||||||
throw new Exception($"Failed: {response.StatusCode}! Result: {result}");
|
throw new Exception($"Failed: {response.StatusCode}! Result: {result}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
httpClient.Dispose();
|
||||||
|
Password.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+2
-1
@@ -2,8 +2,9 @@
|
|||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Azaion.Common.DTO;
|
||||||
|
|
||||||
namespace Azaion.Suite.Services;
|
namespace Azaion.Common.Services;
|
||||||
|
|
||||||
public interface IHardwareService
|
public interface IHardwareService
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Azaion.Common.Services;
|
||||||
|
|
||||||
|
public interface IResourceLoader
|
||||||
|
{
|
||||||
|
Task<MemoryStream> Load(string fileName, CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResourceLoader(string email, string password, AzaionApiClient api, IHardwareService hardwareService) : IResourceLoader
|
||||||
|
{
|
||||||
|
public async Task<MemoryStream> Load(string fileName, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var hardwareInfo = await hardwareService.GetHardware();
|
||||||
|
var encryptedStream = await api.GetResource(fileName, password, hardwareInfo);
|
||||||
|
|
||||||
|
var key = Security.MakeEncryptionKey(email, password, hardwareInfo.Hash);
|
||||||
|
var stream = new MemoryStream();
|
||||||
|
await encryptedStream.DecryptTo(stream, key, cancellationToken);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ using System.Security;
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Azaion.Suite.Services;
|
namespace Azaion.Common.Services;
|
||||||
|
|
||||||
public static class Security
|
public static class Security
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Azaion.Common.DTO;
|
using Azaion.Common.DTO;
|
||||||
|
using Azaion.Common.DTO.Config;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<Application x:Class="Azaion.Launcher.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
StartupUri="Loader.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Azaion.Launcher;
|
||||||
|
|
||||||
|
public partial class App;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="Loader.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<XamlRuntime>Wpf</XamlRuntime>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Window x:Class="Azaion.Suite.Loader"
|
<Window x:Class="Azaion.Launcher.Loader"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Azaion.Launcher;
|
||||||
|
|
||||||
|
public partial class Loader : Window
|
||||||
|
{
|
||||||
|
public Loader()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Process.Start("Azaion.Suite.exe", $"-e {TbEmail.Text} -p {TbPassword.Password}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseClick(object sender, RoutedEventArgs e) => Close();
|
||||||
|
|
||||||
|
private void MainMouseMove(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.OriginalSource is Button || e.OriginalSource is TextBox)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (e.LeftButton == MouseButtonState.Pressed)
|
||||||
|
DragMove();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azaion.Common", "Azaion.Com
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azaion.Dataset", "Azaion.Dataset\Azaion.Dataset.csproj", "{01A5CA37-A62E-4EF3-8678-D72CD9525677}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azaion.Dataset", "Azaion.Dataset\Azaion.Dataset.csproj", "{01A5CA37-A62E-4EF3-8678-D72CD9525677}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azaion.Launcher", "Azaion.Launcher\Azaion.Launcher.csproj", "{00CC9AFE-2952-4943-BCBA-976AE03DE841}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -36,5 +38,9 @@ Global
|
|||||||
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Release|Any CPU.Build.0 = Release|Any CPU
|
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{00CC9AFE-2952-4943-BCBA-976AE03DE841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{00CC9AFE-2952-4943-BCBA-976AE03DE841}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{00CC9AFE-2952-4943-BCBA-976AE03DE841}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{00CC9AFE-2952-4943-BCBA-976AE03DE841}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
@@ -1,16 +1,21 @@
|
|||||||
using System.Reflection;
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Reflection;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using Azaion.Annotator;
|
using Azaion.Annotator;
|
||||||
using Azaion.Annotator.DTO;
|
using Azaion.Annotator.DTO;
|
||||||
using Azaion.Annotator.Extensions;
|
using Azaion.Annotator.Extensions;
|
||||||
|
using Azaion.Common;
|
||||||
using Azaion.Common.DTO;
|
using Azaion.Common.DTO;
|
||||||
using Azaion.Common.DTO.Config;
|
using Azaion.Common.DTO.Config;
|
||||||
using Azaion.Common.Extensions;
|
using Azaion.Common.Extensions;
|
||||||
|
using Azaion.Common.Services;
|
||||||
using Azaion.Suite.Services;
|
using Azaion.Suite.Services;
|
||||||
using Azaion.Suite.Services.DTO;
|
|
||||||
using Azaion.Dataset;
|
using Azaion.Dataset;
|
||||||
|
using Azaion.Suite.Services.DTO;
|
||||||
|
using CommandLine;
|
||||||
using LibVLCSharp.Shared;
|
using LibVLCSharp.Shared;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@@ -18,16 +23,53 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace Azaion.Suite;
|
namespace Azaion.Suite;
|
||||||
|
|
||||||
public partial class App : Application
|
public partial class App
|
||||||
{
|
{
|
||||||
private readonly IHost _host;
|
private readonly IHost _host;
|
||||||
private readonly ILogger<App> _logger;
|
private readonly ILogger<App> _logger;
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
private static readonly List<string> EncryptedResources =
|
||||||
|
[
|
||||||
|
"Azaion.Annotator.dll",
|
||||||
|
"Azaion.Dataset.dll"
|
||||||
|
];
|
||||||
|
|
||||||
|
private static readonly IResourceLoader? ResourceLoader;
|
||||||
|
|
||||||
|
static App()
|
||||||
|
{
|
||||||
|
var result = Parser.Default.ParseArguments<SuiteCommandLineOptions>(Environment.GetCommandLineArgs());
|
||||||
|
if (result.Errors.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var configStr = File.ReadAllText(Constants.CONFIG_PATH);
|
||||||
|
var apiConfig = JsonConvert.DeserializeObject<AppConfig>(configStr)!.ApiConfig;
|
||||||
|
var api = new AzaionApiClient(new HttpClient
|
||||||
|
{
|
||||||
|
BaseAddress = new Uri(apiConfig.Url),
|
||||||
|
Timeout = TimeSpan.FromSeconds(apiConfig.TimeoutSeconds)
|
||||||
|
});
|
||||||
|
var email = result.Value.Email;
|
||||||
|
var password = result.Value.Password;
|
||||||
|
|
||||||
|
api.Login(email, password);
|
||||||
|
|
||||||
|
ResourceLoader = new ResourceLoader(email, password, api, new HardwareService());
|
||||||
|
foreach (var resource in EncryptedResources)
|
||||||
|
{
|
||||||
|
var stream = ResourceLoader.Load(resource).GetAwaiter().GetResult();
|
||||||
|
Assembly.Load(stream.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
new ConfigUpdater().CheckConfig();
|
||||||
|
}
|
||||||
|
|
||||||
public App()
|
public App()
|
||||||
{
|
{
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
@@ -42,21 +84,30 @@ public partial class App : Application
|
|||||||
_host = Host.CreateDefaultBuilder()
|
_host = Host.CreateDefaultBuilder()
|
||||||
.ConfigureAppConfiguration((context, config) => config
|
.ConfigureAppConfiguration((context, config) => config
|
||||||
.AddCommandLine(Environment.GetCommandLineArgs())
|
.AddCommandLine(Environment.GetCommandLineArgs())
|
||||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true))
|
.AddJsonFile(Constants.CONFIG_PATH, optional: true, reloadOnChange: true))
|
||||||
.ConfigureServices((context, services) =>
|
.ConfigureServices((context, services) =>
|
||||||
{
|
{
|
||||||
services.AddSingleton<Loader>();
|
services.AddSingleton<MainSuite>();
|
||||||
services.AddSingleton<IHardwareService, HardwareService>();
|
services.AddSingleton<IHardwareService, HardwareService>();
|
||||||
services.AddSingleton<IResourceLoader, ResourceLoader>();
|
services.AddSingleton<IResourceLoader>(ResourceLoader!);
|
||||||
|
|
||||||
|
services.Configure<AppConfig>(context.Configuration);
|
||||||
|
services.ConfigureSection<ApiConfig>(context.Configuration);
|
||||||
|
services.ConfigureSection<DirectoriesConfig>(context.Configuration);
|
||||||
|
services.ConfigureSection<AnnotationConfig>(context.Configuration);
|
||||||
|
services.ConfigureSection<WindowConfig>(context.Configuration);
|
||||||
|
services.ConfigureSection<AIRecognitionConfig>(context.Configuration);
|
||||||
|
services.ConfigureSection<ThumbnailConfig>(context.Configuration);
|
||||||
|
|
||||||
services.Configure<ApiConfig>(context.Configuration.GetSection(nameof(ApiConfig)));
|
|
||||||
services.AddSingleton<IConfigUpdater, ConfigUpdater>();
|
services.AddSingleton<IConfigUpdater, ConfigUpdater>();
|
||||||
|
|
||||||
services.AddSingleton<Annotator.Annotator>();
|
services.AddSingleton<Annotator.Annotator>();
|
||||||
services.AddSingleton<DatasetExplorer>();
|
services.AddSingleton<DatasetExplorer>();
|
||||||
services.AddSingleton<HelpWindow>();
|
services.AddSingleton<HelpWindow>();
|
||||||
services.AddSingleton<IAIDetector, YOLODetector>();
|
services.AddSingleton<IAIDetector, YOLODetector>();
|
||||||
services.AddMediatR(c => c.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
|
services.AddMediatR(c => c.RegisterServicesFromAssemblies(
|
||||||
|
typeof(Annotator.Annotator).Assembly,
|
||||||
|
typeof(DatasetExplorer).Assembly));
|
||||||
services.AddSingleton<LibVLC>(_ => new LibVLC());
|
services.AddSingleton<LibVLC>(_ => new LibVLC());
|
||||||
services.AddSingleton<FormState>();
|
services.AddSingleton<FormState>();
|
||||||
services.AddSingleton<MediaPlayer>(sp =>
|
services.AddSingleton<MediaPlayer>(sp =>
|
||||||
@@ -93,7 +144,7 @@ public partial class App : Application
|
|||||||
{
|
{
|
||||||
EventManager.RegisterClassHandler(typeof(UIElement), UIElement.KeyDownEvent, new RoutedEventHandler(GlobalClick));
|
EventManager.RegisterClassHandler(typeof(UIElement), UIElement.KeyDownEvent, new RoutedEventHandler(GlobalClick));
|
||||||
await _host.StartAsync();
|
await _host.StartAsync();
|
||||||
_host.Services.GetRequiredService<Loader>().Show();
|
_host.Services.GetRequiredService<MainSuite>().Show();
|
||||||
|
|
||||||
base.OnStartup(e);
|
base.OnStartup(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||||
|
<PackageReference Include="LibVLCSharp" Version="3.9.1" />
|
||||||
|
<PackageReference Include="LibVLCSharp.WPF" Version="3.9.1" />
|
||||||
<PackageReference Include="MediatR" Version="12.4.1" />
|
<PackageReference Include="MediatR" Version="12.4.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
|
||||||
@@ -19,13 +22,7 @@
|
|||||||
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
|
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
</ItemGroup>
|
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.21" />
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Remove="appsettings.json" />
|
|
||||||
<Content Include="appsettings.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.Loader;
|
|
||||||
using Azaion.Suite.Services.DTO;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Azaion.Suite;
|
|
||||||
|
|
||||||
public class DynamicAssemblyLoader(IOptions<LocalFilesConfig> localFilesConfig) : AssemblyLoadContext
|
|
||||||
{
|
|
||||||
private static readonly Dictionary<string?, Assembly> LoadedAssemblies = new();
|
|
||||||
|
|
||||||
static DynamicAssemblyLoader()
|
|
||||||
{
|
|
||||||
LoadedAssemblies = Default.Assemblies.ToDictionary(a => a.GetName().Name, a => a);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Assembly Load(AssemblyName assemblyName)
|
|
||||||
{
|
|
||||||
var assembly = LoadedAssemblies.GetValueOrDefault(assemblyName.Name);
|
|
||||||
if (assembly != null)
|
|
||||||
return assembly;
|
|
||||||
|
|
||||||
var currentLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
|
|
||||||
|
|
||||||
var asm = Assembly.LoadFile(Path.Combine(currentLocation, localFilesConfig.Value.DllPath, $"{assemblyName.Name!}.dll"));
|
|
||||||
return asm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.Loader;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Azaion.Suite.Services.DTO;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Azaion.Suite;
|
|
||||||
|
|
||||||
public partial class Loader : Window
|
|
||||||
{
|
|
||||||
private readonly IResourceLoader _resourceLoader;
|
|
||||||
private readonly IOptions<LocalFilesConfig> _localFilesConfig;
|
|
||||||
|
|
||||||
public Loader(IResourceLoader resourceLoader, IOptions<LocalFilesConfig> localFilesConfig)
|
|
||||||
{
|
|
||||||
_resourceLoader = resourceLoader;
|
|
||||||
_localFilesConfig = localFilesConfig;
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void RunClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var stream = new MemoryStream();
|
|
||||||
await _resourceLoader.LoadAnnotator(TbEmail.Text, TbPassword.Password, stream);
|
|
||||||
stream.Seek(0, SeekOrigin.Begin);
|
|
||||||
var loader = new AssemblyLoadContext("DynamicContext", isCollectible: true);
|
|
||||||
var annotatorAssembly = loader.LoadFromStream(stream);
|
|
||||||
|
|
||||||
var appType = annotatorAssembly.GetType("Azaion.Annotator.App");
|
|
||||||
var appInstance = Activator.CreateInstance(appType);
|
|
||||||
var runMethod = appType.GetMethod("Run", BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
if (runMethod != null)
|
|
||||||
{
|
|
||||||
runMethod.Invoke(appInstance, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// var entryPoint = annotatorAssembly.EntryPoint;
|
|
||||||
// if (entryPoint == null)
|
|
||||||
// return;
|
|
||||||
//
|
|
||||||
// var o = annotatorAssembly.CreateInstance(entryPoint.Name);
|
|
||||||
// entryPoint.Invoke(o, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CloseClick(object sender, RoutedEventArgs e) => Close();
|
|
||||||
|
|
||||||
private void MainMouseMove(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.OriginalSource is Button || e.OriginalSource is TextBox)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (e.LeftButton == MouseButtonState.Pressed)
|
|
||||||
DragMove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,10 +3,13 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Azaion.Suite"
|
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="MainSuite" Height="450" Width="800">
|
Title="MainSuite" Height="450" Width="800">
|
||||||
<Grid>
|
<Grid>
|
||||||
|
<TabControl Name="MainTabControl"
|
||||||
|
TabStripPlacement="Left"
|
||||||
|
Margin="0, 0, 0, 10"
|
||||||
|
Background="Black">
|
||||||
|
</TabControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
using Azaion.Annotator.Extensions;
|
using Azaion.Annotator.Extensions;
|
||||||
using Azaion.Common.DTO.Config;
|
using Azaion.Common.DTO.Config;
|
||||||
|
using Azaion.Dataset;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Azaion.Suite;
|
namespace Azaion.Suite;
|
||||||
|
|
||||||
public partial class MainSuite : Window
|
public partial class MainSuite
|
||||||
{
|
{
|
||||||
private readonly AppConfig _appConfig;
|
private readonly AppConfig _appConfig;
|
||||||
private readonly IConfigUpdater _configUpdater;
|
private readonly IConfigUpdater _configUpdater;
|
||||||
|
private readonly Annotator.Annotator _annotator;
|
||||||
|
private readonly DatasetExplorer _datasetExplorer;
|
||||||
|
|
||||||
public MainSuite(IOptions<AppConfig> appConfig, IConfigUpdater configUpdater)
|
public MainSuite(IOptions<AppConfig> appConfig, IConfigUpdater configUpdater, Annotator.Annotator annotator, DatasetExplorer datasetExplorer)
|
||||||
{
|
{
|
||||||
_configUpdater = configUpdater;
|
_configUpdater = configUpdater;
|
||||||
|
_annotator = annotator;
|
||||||
|
_datasetExplorer = datasetExplorer;
|
||||||
_appConfig = appConfig.Value;
|
_appConfig = appConfig.Value;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Loaded += OnLoaded;
|
Loaded += OnLoaded;
|
||||||
@@ -41,6 +47,17 @@ public partial class MainSuite : Window
|
|||||||
|
|
||||||
if (_appConfig.WindowConfig.FullScreen)
|
if (_appConfig.WindowConfig.FullScreen)
|
||||||
WindowState = WindowState.Maximized;
|
WindowState = WindowState.Maximized;
|
||||||
|
|
||||||
|
MainTabControl.Items.Add(new TabItem
|
||||||
|
{
|
||||||
|
Header = "Annotator",
|
||||||
|
Content = _annotator.Content
|
||||||
|
});
|
||||||
|
MainTabControl.Items.Add(new TabItem
|
||||||
|
{
|
||||||
|
Header = "Dataset Explorer",
|
||||||
|
Content = _datasetExplorer.Content
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveUserSettings()
|
private async Task SaveUserSettings()
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using Azaion.Suite.Services;
|
|
||||||
using Azaion.Suite.Services.DTO;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Azaion.Suite;
|
|
||||||
|
|
||||||
public interface IResourceLoader
|
|
||||||
{
|
|
||||||
Task LoadAnnotator(string email, string password, Stream outStream, CancellationToken cancellationToken = default);
|
|
||||||
Assembly LoadAssembly(string name, CancellationToken cancellationToken = default);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ResourceLoader(AzaionApiClient azaionApi, IHardwareService hardwareService, IOptions<LocalFilesConfig> localFilesConfig) : IResourceLoader
|
|
||||||
{
|
|
||||||
public async Task LoadAnnotator(string email, string password, Stream outStream, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var hardwareInfo = await hardwareService.GetHardware();
|
|
||||||
azaionApi.Login(email, password);
|
|
||||||
var key = Security.MakeEncryptionKey(email, password, hardwareInfo.Hash);
|
|
||||||
|
|
||||||
var encryptedStream = await azaionApi.GetResource(password, hardwareInfo, ResourceEnum.AnnotatorDll);
|
|
||||||
|
|
||||||
await encryptedStream.DecryptTo(outStream, key, cancellationToken);
|
|
||||||
//return Assembly.Load(stream.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Assembly LoadAssembly(string name, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var dllValues = name.Split(",");
|
|
||||||
var dllName = $"{dllValues[0]}.dll";
|
|
||||||
var currentLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
|
|
||||||
|
|
||||||
var asm = Assembly.LoadFile(Path.Combine(currentLocation, localFilesConfig.Value.DllPath, dllName));
|
|
||||||
return asm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Azaion.Suite.Services.DTO;
|
|
||||||
|
|
||||||
public enum ResourceEnum
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
AnnotatorDll = 10,
|
|
||||||
AIModelRKNN = 20,
|
|
||||||
AIModelONNX = 30,
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using CommandLine;
|
||||||
|
|
||||||
|
namespace Azaion.Suite.Services.DTO;
|
||||||
|
|
||||||
|
public class SuiteCommandLineOptions
|
||||||
|
{
|
||||||
|
[Option('e', "email", Required = true, HelpText = "The email for authorization.")]
|
||||||
|
public string Email { get; set; } = null!;
|
||||||
|
|
||||||
|
[Option('p', "password", Required = true, HelpText = "The password for authorization.")]
|
||||||
|
public string Password { get; set; } = null!;
|
||||||
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"ApiConfig": {
|
|
||||||
"Url": "https://api.azaion.com",
|
|
||||||
"TimeoutSeconds": 20,
|
|
||||||
"RetryCount": 3
|
|
||||||
},
|
|
||||||
"LocalFilesConfig": {
|
|
||||||
"DllPath": "AzaionSuite"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"ApiConfig": {
|
||||||
|
"Url": "https://api.azaion.com",
|
||||||
|
"TimeoutSeconds": 20,
|
||||||
|
"RetryCount": 3
|
||||||
|
},
|
||||||
|
|
||||||
|
"DirectoriesConfig": {
|
||||||
|
"VideosDirectory" : "E:\\Azaion1\\Videos",
|
||||||
|
"LabelsDirectory" : "E:\\labels",
|
||||||
|
"ImagesDirectory" : "E:\\images",
|
||||||
|
"ResultsDirectory" : "E:\\results",
|
||||||
|
"ThumbnailsDirectory" : "E:\\thumbnails",
|
||||||
|
|
||||||
|
"DllCacheDirectory" : "Cache"
|
||||||
|
},
|
||||||
|
|
||||||
|
"AnnotationConfig" : {
|
||||||
|
"AnnotationClasses": [
|
||||||
|
{ "Id": 0, "Name": "Броньована техніка", "ShortName": "Бронь" },
|
||||||
|
{ "Id": 1, "Name": "Вантажівка", "ShortName": "Вантаж" },
|
||||||
|
{ "Id": 2, "Name": "Машина легкова", "ShortName": "Машина" },
|
||||||
|
{ "Id": 3, "Name": "Артилерія", "ShortName": "Арта" },
|
||||||
|
{ "Id": 4, "Name": "Тінь від техніки", "ShortName": "Тінь" },
|
||||||
|
{ "Id": 5, "Name": "Окопи", "ShortName": "Окопи" },
|
||||||
|
{ "Id": 6, "Name": "Військовий", "ShortName": "Військов" },
|
||||||
|
{ "Id": 7, "Name": "Накати", "ShortName": "Накати" },
|
||||||
|
{ "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк захист" },
|
||||||
|
{ "Id": 9, "Name": "Дим", "ShortName": "Дим" },
|
||||||
|
{ "Id": 10, "Name": "Літак", "ShortName": "Літак" }
|
||||||
|
],
|
||||||
|
"LastSelectedExplorerClass": 1,
|
||||||
|
"VideoFormats": ["mov", "mp4"],
|
||||||
|
"ImageFormats": ["jpg", "jpeg", "png", "bmp", "gif"]
|
||||||
|
},
|
||||||
|
|
||||||
|
"WindowConfig": {
|
||||||
|
"WindowSize": "1920,1080",
|
||||||
|
"WindowLocation": "50,50",
|
||||||
|
"FullScreen": true,
|
||||||
|
"LeftPanelWidth": 220,
|
||||||
|
"RightPanelWidth": 220,
|
||||||
|
"ShowHelpOnStart": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"AIRecognitionConfig": {
|
||||||
|
"FrameRecognitionSeconds" : 2,
|
||||||
|
"TrackingDistanceConfidence" : 0.15,
|
||||||
|
"TrackingProbabilityIncrease" : 15,
|
||||||
|
"TrackingIntersectionThreshold" : 0.8
|
||||||
|
},
|
||||||
|
|
||||||
|
"ThumbnailConfig": {
|
||||||
|
"Size" : "240,135",
|
||||||
|
"Border" : 10
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Azaion.Suite;
|
using Azaion.Common.Services;
|
||||||
|
using Azaion.Suite;
|
||||||
using Azaion.Suite.Services;
|
using Azaion.Suite.Services;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user