diff --git a/Azaion.Annotator/Annotator.xaml.cs b/Azaion.Annotator/Annotator.xaml.cs index 80a1cd0..ad99090 100644 --- a/Azaion.Annotator/Annotator.xaml.cs +++ b/Azaion.Annotator/Annotator.xaml.cs @@ -116,8 +116,8 @@ public partial class Annotator _suspendLayout = true; - MainGrid.ColumnDefinitions.FirstOrDefault()!.Width = new GridLength(_appConfig.AnnotationConfig.LeftPanelWidth); - MainGrid.ColumnDefinitions.LastOrDefault()!.Width = new GridLength(_appConfig.AnnotationConfig.RightPanelWidth); + MainGrid.ColumnDefinitions.FirstOrDefault()!.Width = new GridLength(_appConfig.UIConfig.LeftPanelWidth); + MainGrid.ColumnDefinitions.LastOrDefault()!.Width = new GridLength(_appConfig.UIConfig.RightPanelWidth); _suspendLayout = false; TbFolder.Text = _appConfig.DirectoriesConfig.VideosDirectory; @@ -255,8 +255,8 @@ public partial class Annotator if (_suspendLayout) return; - _appConfig.AnnotationConfig.LeftPanelWidth = MainGrid.ColumnDefinitions.FirstOrDefault()!.Width.Value; - _appConfig.AnnotationConfig.RightPanelWidth = MainGrid.ColumnDefinitions.LastOrDefault()!.Width.Value; + _appConfig.UIConfig.LeftPanelWidth = MainGrid.ColumnDefinitions.FirstOrDefault()!.Width.Value; + _appConfig.UIConfig.RightPanelWidth = MainGrid.ColumnDefinitions.LastOrDefault()!.Width.Value; await ThrottleExt.ThrottleRunFirst(() => { @@ -329,8 +329,19 @@ public partial class Annotator var existingResult = _formState.AnnotationResults.FirstOrDefault(x => x.Annotation.Time == time); if (existingResult != null) { - _logger.LogInformation($"remove annotation {existingResult.TimeStr} {existingResult.ClassName}!"); - _formState.AnnotationResults.Remove(existingResult); + try + { + _logger.LogInformation($"remove annotation {existingResult.TimeStr} {existingResult.ClassName}!"); + _formState.AnnotationResults.Remove(existingResult); + _logger.LogInformation($"removed {existingResult.TimeStr} {existingResult.ClassName} sucessfully!"); + } + catch (Exception e) + { + _logger.LogError(e, e.Message); + //Console.WriteLine(e); + throw; + } + } @@ -640,7 +651,7 @@ public class GradientStyleSelector : StyleSelector }; var gradients = new List(); - if (result.Colors.Count != 0) + if (result.Colors.Count == 0) { var color = (Color)ColorConverter.ConvertFromString("#40DDDDDD"); gradients = [new GradientStop(color, 0.99)]; diff --git a/Azaion.Annotator/AnnotatorEventHandler.cs b/Azaion.Annotator/AnnotatorEventHandler.cs index 9578a45..28deefa 100644 --- a/Azaion.Annotator/AnnotatorEventHandler.cs +++ b/Azaion.Annotator/AnnotatorEventHandler.cs @@ -275,7 +275,7 @@ public class AnnotatorEventHandler( await NextMedia(ct: cancellationToken); } - var annotation = await annotationService.SaveAnnotation(originalMediaName, time, currentDetections, SourceEnum.Manual, token: cancellationToken); + var annotation = await annotationService.SaveAnnotation(originalMediaName, time, currentDetections, token: cancellationToken); if (isVideo) mainWindow.AddAnnotation(annotation); } diff --git a/Azaion.Common/Controls/CanvasEditor.cs b/Azaion.Common/Controls/CanvasEditor.cs index 3056b8f..f4062f9 100644 --- a/Azaion.Common/Controls/CanvasEditor.cs +++ b/Azaion.Common/Controls/CanvasEditor.cs @@ -169,7 +169,8 @@ public class CanvasEditor : Canvas Width = width, Height = height, X = Math.Min(endPos.X, _newAnnotationStartPos.X), - Y = Math.Min(endPos.Y, _newAnnotationStartPos.Y) + Y = Math.Min(endPos.Y, _newAnnotationStartPos.Y), + Confidence = 1 }); } @@ -312,25 +313,21 @@ public class CanvasEditor : Canvas { foreach (var detection in detections) { - var annClass = DetectionClass.FromYoloId(detection.ClassNumber, detectionClasses); + var detectionClass = DetectionClass.FromYoloId(detection.ClassNumber, detectionClasses); var canvasLabel = new CanvasLabel(detection, RenderSize, videoSize, detection.Confidence); - CreateDetectionControl(annClass, time, canvasLabel); + CreateDetectionControl(detectionClass, time, canvasLabel); } } - private void CreateDetectionControl(DetectionClass annClass, TimeSpan time, CanvasLabel canvasLabel) + private void CreateDetectionControl(DetectionClass detectionClass, TimeSpan time, CanvasLabel canvasLabel) { - var detectionControl = new DetectionControl(annClass, time, AnnotationResizeStart, canvasLabel.Confidence) - { - Width = canvasLabel.Width, - Height = canvasLabel.Height - }; + var detectionControl = new DetectionControl(detectionClass, time, AnnotationResizeStart, canvasLabel); detectionControl.MouseDown += AnnotationPositionStart; SetLeft(detectionControl, canvasLabel.X ); SetTop(detectionControl, canvasLabel.Y); Children.Add(detectionControl); CurrentDetections.Add(detectionControl); - _newAnnotationRect.Fill = new SolidColorBrush(annClass.Color); + _newAnnotationRect.Fill = new SolidColorBrush(detectionClass.Color); } #endregion diff --git a/Azaion.Common/Controls/DetectionClasses.xaml.cs b/Azaion.Common/Controls/DetectionClasses.xaml.cs index 5558144..d704fa5 100644 --- a/Azaion.Common/Controls/DetectionClasses.xaml.cs +++ b/Azaion.Common/Controls/DetectionClasses.xaml.cs @@ -1,6 +1,8 @@ -using System.Windows; +using System.Collections.ObjectModel; +using System.Windows; using System.Windows.Controls; using Azaion.Common.DTO; +using Azaion.Common.Extensions; namespace Azaion.Common.Controls; @@ -14,6 +16,7 @@ public partial class DetectionClasses { public event EventHandler? DetectionClassChanged; private const int CaptionedMinWidth = 230; + ObservableCollection _detectionClasses = new(); public DetectionClasses() { @@ -37,7 +40,14 @@ public partial class DetectionClasses public void Init(List detectionClasses) { - DetectionDataGrid.ItemsSource = detectionClasses; + foreach (var dClass in detectionClasses) + { + var cl = (DetectionClass)dClass.Clone(); + cl.Color = cl.Color.ToConfidenceColor(); + _detectionClasses.Add(cl); + } + + DetectionDataGrid.ItemsSource = _detectionClasses; DetectionDataGrid.SelectedIndex = 0; } diff --git a/Azaion.Common/Controls/DetectionControl.cs b/Azaion.Common/Controls/DetectionControl.cs index a579df7..d613c6b 100644 --- a/Azaion.Common/Controls/DetectionControl.cs +++ b/Azaion.Common/Controls/DetectionControl.cs @@ -4,6 +4,7 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; using Azaion.Common.DTO; +using Azaion.Common.Extensions; using Label = System.Windows.Controls.Label; namespace Azaion.Common.Controls; @@ -11,22 +12,28 @@ namespace Azaion.Common.Controls; public class DetectionControl : Border { private readonly Action _resizeStart; - private const double RESIZE_RECT_SIZE = 9; + private const double RESIZE_RECT_SIZE = 12; private readonly Grid _grid; - private readonly TextBlock _classNameLabel; - private readonly Label _probabilityLabel; + private readonly Label _detectionLabel; public TimeSpan Time { get; set; } - + private readonly double _confidence; + private List _resizedRectangles = new(); + private DetectionClass _detectionClass = null!; public DetectionClass DetectionClass { get => _detectionClass; set { - _grid.Background = value.ColorBrush; - _probabilityLabel.Background = value.ColorBrush; - _classNameLabel.Text = value.UIName; + var brush = new SolidColorBrush(value.Color.ToConfidenceColor()); + BorderBrush = brush; + BorderThickness = new Thickness(3); + foreach (var rect in _resizedRectangles) + rect.Stroke = brush; + + _detectionLabel.Background = new SolidColorBrush(value.Color.ToConfidenceColor(_confidence)); + _detectionLabel.Content = _detectionLabelText(value.UIName); _detectionClass = value; } } @@ -43,29 +50,36 @@ public class DetectionControl : Border _isSelected = value; } } - - public DetectionControl(DetectionClass detectionClass, TimeSpan time, Action resizeStart, double? probability = null) + + private string _detectionLabelText(string detectionClassName) => + _confidence >= 0.995 ? detectionClassName : $"{detectionClassName}: {_confidence * 100:F0}%"; //double + + public DetectionControl(DetectionClass detectionClass, TimeSpan time, Action resizeStart, CanvasLabel canvasLabel) { + Width = canvasLabel.Width; + Height = canvasLabel.Height; Time = time; _resizeStart = resizeStart; - _classNameLabel = new TextBlock + _confidence = canvasLabel.Confidence; + + var labelContainer = new Canvas { - Text = detectionClass.UIName, - HorizontalAlignment = HorizontalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top, - Margin = new Thickness(0, 15, 0, 0), - FontSize = 14, - Cursor = Cursors.SizeAll + ClipToBounds = false, + Margin = new Thickness(0, 0, 32, 0) }; - _probabilityLabel = new Label + _detectionLabel = new Label { - Content = probability.HasValue ? $"{probability.Value*100:F0}%" : string.Empty, + Content = _detectionLabelText(detectionClass.Name), HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top, Margin = new Thickness(0, -32, 0, 0), FontSize = 16, Visibility = Visibility.Visible }; + labelContainer.Children.Add(_detectionLabel); + _selectionFrame = new Rectangle { HorizontalAlignment = HorizontalAlignment.Stretch, @@ -74,43 +88,46 @@ public class DetectionControl : Border StrokeThickness = 2, Visibility = Visibility.Collapsed }; - + _resizedRectangles = + [ + CreateResizeRect("rLT", HorizontalAlignment.Left, VerticalAlignment.Top, Cursors.SizeNWSE), + CreateResizeRect("rCT", HorizontalAlignment.Center, VerticalAlignment.Top, Cursors.SizeNS), + CreateResizeRect("rRT", HorizontalAlignment.Right, VerticalAlignment.Top, Cursors.SizeNESW), + CreateResizeRect("rLC", HorizontalAlignment.Left, VerticalAlignment.Center, Cursors.SizeWE), + CreateResizeRect("rRC", HorizontalAlignment.Right, VerticalAlignment.Center, Cursors.SizeWE), + CreateResizeRect("rLB", HorizontalAlignment.Left, VerticalAlignment.Bottom, Cursors.SizeNESW), + CreateResizeRect("rCB", HorizontalAlignment.Center, VerticalAlignment.Bottom, Cursors.SizeNS), + CreateResizeRect("rRB", HorizontalAlignment.Right, VerticalAlignment.Bottom, Cursors.SizeNWSE) + ]; _grid = new Grid { + Background = Brushes.Transparent, HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, - Children = - { - _selectionFrame, - _classNameLabel, - AddRect("rLT", HorizontalAlignment.Left, VerticalAlignment.Top, Cursors.SizeNWSE), - AddRect("rCT", HorizontalAlignment.Center, VerticalAlignment.Top, Cursors.SizeNS), - AddRect("rRT", HorizontalAlignment.Right, VerticalAlignment.Top, Cursors.SizeNESW), - AddRect("rLC", HorizontalAlignment.Left, VerticalAlignment.Center, Cursors.SizeWE), - AddRect("rRC", HorizontalAlignment.Right, VerticalAlignment.Center, Cursors.SizeWE), - AddRect("rLB", HorizontalAlignment.Left, VerticalAlignment.Bottom, Cursors.SizeNESW), - AddRect("rCB", HorizontalAlignment.Center, VerticalAlignment.Bottom, Cursors.SizeNS), - AddRect("rRB", HorizontalAlignment.Right, VerticalAlignment.Bottom, Cursors.SizeNWSE) - } + Children = { _selectionFrame } }; - if (probability.HasValue) - _grid.Children.Add(_probabilityLabel); + foreach (var rect in _resizedRectangles) + _grid.Children.Add(rect); + _grid.Children.Add(labelContainer); + Child = _grid; Cursor = Cursors.SizeAll; DetectionClass = detectionClass; } //small corners - private Rectangle AddRect(string name, HorizontalAlignment ha, VerticalAlignment va, Cursor crs) + private Rectangle CreateResizeRect(string name, HorizontalAlignment ha, VerticalAlignment va, Cursor crs) { var rect = new Rectangle() // small rectangles at the corners and sides { + ClipToBounds = false, + Margin = new Thickness(-RESIZE_RECT_SIZE), HorizontalAlignment = ha, VerticalAlignment = va, Width = RESIZE_RECT_SIZE, Height = RESIZE_RECT_SIZE, - Stroke = new SolidColorBrush(Color.FromArgb(230, 40, 40, 40)), // small rectangles color - Fill = new SolidColorBrush(Color.FromArgb(1, 255, 255, 255)), + Stroke = new SolidColorBrush(Color.FromArgb(230, 20, 20, 20)), // small rectangles color + Fill = new SolidColorBrush(Color.FromArgb(150, 80, 80, 80)), Cursor = crs, Name = name, }; diff --git a/Azaion.Common/DTO/Config/AnnotationConfig.cs b/Azaion.Common/DTO/Config/AnnotationConfig.cs index 83af334..5e5805e 100644 --- a/Azaion.Common/DTO/Config/AnnotationConfig.cs +++ b/Azaion.Common/DTO/Config/AnnotationConfig.cs @@ -36,7 +36,4 @@ public class AnnotationConfig public List ImageFormats { get; set; } = null!; public string AnnotationsDbFile { get; set; } = null!; - - public double LeftPanelWidth { get; set; } - public double RightPanelWidth { get; set; } } \ No newline at end of file diff --git a/Azaion.Common/DTO/Config/AppConfig.cs b/Azaion.Common/DTO/Config/AppConfig.cs index 049b1af..f4971d3 100644 --- a/Azaion.Common/DTO/Config/AppConfig.cs +++ b/Azaion.Common/DTO/Config/AppConfig.cs @@ -18,6 +18,8 @@ public class AppConfig public AnnotationConfig AnnotationConfig { get; set; } = null!; + public UIConfig UIConfig { get; set; } = null!; + public AIRecognitionConfig AIRecognitionConfig { get; set; } = null!; public ThumbnailConfig ThumbnailConfig { get; set; } = null!; @@ -49,10 +51,13 @@ public class ConfigUpdater : IConfigUpdater VideoFormats = Constants.DefaultVideoFormats, ImageFormats = Constants.DefaultImageFormats, + AnnotationsDbFile = Constants.DEFAULT_ANNOTATIONS_DB_FILE + }, + + UIConfig = new UIConfig + { LeftPanelWidth = Constants.DEFAULT_LEFT_PANEL_WIDTH, RightPanelWidth = Constants.DEFAULT_RIGHT_PANEL_WIDTH, - - AnnotationsDbFile = Constants.DEFAULT_ANNOTATIONS_DB_FILE }, DirectoriesConfig = new DirectoriesConfig @@ -84,15 +89,13 @@ public class ConfigUpdater : IConfigUpdater public void Save(AppConfig config) { - //Save without sensitive info + //Save only user's config var publicConfig = new { - InferenceClientConfig = config.InferenceClientConfig, - GpsDeniedClientConfig = config.GpsDeniedClientConfig, - DirectoriesConfig = config.DirectoriesConfig, - AnnotationConfig = config.AnnotationConfig, - AIRecognitionConfig = config.AIRecognitionConfig, - ThumbnailConfig = config.ThumbnailConfig + config.InferenceClientConfig, + config.GpsDeniedClientConfig, + config.DirectoriesConfig, + config.UIConfig }; File.WriteAllText(SecurityConstants.CONFIG_PATH, JsonConvert.SerializeObject(publicConfig, Formatting.Indented), Encoding.UTF8); diff --git a/Azaion.Common/DTO/Config/UIConfig.cs b/Azaion.Common/DTO/Config/UIConfig.cs new file mode 100644 index 0000000..ca07a01 --- /dev/null +++ b/Azaion.Common/DTO/Config/UIConfig.cs @@ -0,0 +1,7 @@ +namespace Azaion.Common.DTO.Config; + +public class UIConfig +{ + public double LeftPanelWidth { get; set; } + public double RightPanelWidth { get; set; } +} \ No newline at end of file diff --git a/Azaion.Common/DTO/DetectionClass.cs b/Azaion.Common/DTO/DetectionClass.cs index 9c798c5..fa79eb3 100644 --- a/Azaion.Common/DTO/DetectionClass.cs +++ b/Azaion.Common/DTO/DetectionClass.cs @@ -3,7 +3,7 @@ using Newtonsoft.Json; namespace Azaion.Common.DTO; -public class DetectionClass +public class DetectionClass : ICloneable { public int Id { get; set; } @@ -49,6 +49,8 @@ public class DetectionClass detClass.PhotoMode = photoMode; return detClass; } + + public object Clone() => MemberwiseClone(); } public enum PhotoMode diff --git a/Azaion.Common/DTO/Label.cs b/Azaion.Common/DTO/Label.cs index 177225b..fab95f2 100644 --- a/Azaion.Common/DTO/Label.cs +++ b/Azaion.Common/DTO/Label.cs @@ -26,13 +26,13 @@ public class CanvasLabel : Label public double Y { get; set; } public double Width { get; set; } public double Height { get; set; } - public double? Confidence { get; } + public double Confidence { get; set; } public CanvasLabel() { } - public CanvasLabel(int classNumber, double x, double y, double width, double height, double? confidence = null) : base(classNumber) + public CanvasLabel(int classNumber, double x, double y, double width, double height, double confidence = 1) : base(classNumber) { X = x; Y = y; diff --git a/Azaion.Common/Extensions/ColorExtensions.cs b/Azaion.Common/Extensions/ColorExtensions.cs index 0123acb..30839c9 100644 --- a/Azaion.Common/Extensions/ColorExtensions.cs +++ b/Azaion.Common/Extensions/ColorExtensions.cs @@ -4,10 +4,10 @@ namespace Azaion.Common.Extensions; public static class ColorExtensions { - private const int MIN_ALPHA = 20; - private const int MAX_ALPHA = 100; + private const int MIN_ALPHA = 15; + private const int MAX_ALPHA = 150; - public static Color ToConfidenceColor(this Color color, double confidence ) + public static Color ToConfidenceColor(this Color color, double confidence = 1) { color.A = (byte)(MIN_ALPHA + (int)Math.Round(confidence * (MAX_ALPHA - MIN_ALPHA))); return color; diff --git a/Azaion.Common/Services/AnnotationService.cs b/Azaion.Common/Services/AnnotationService.cs index 22de3f6..97f0704 100644 --- a/Azaion.Common/Services/AnnotationService.cs +++ b/Azaion.Common/Services/AnnotationService.cs @@ -55,15 +55,20 @@ public class AnnotationService : INotificationHandler private async Task Init(CancellationToken cancellationToken = default) { + if (!_authProvider.CurrentUser.Role.IsValidator()) + return; + var consumerSystem = await StreamSystem.Create(new StreamSystemConfig { Endpoints = new List{new DnsEndPoint(_queueConfig.Host, _queueConfig.Port)}, UserName = _queueConfig.ConsumerUsername, Password = _queueConfig.ConsumerPassword }); + var offset = (await _dbFactory.Run(db => db.QueueOffsets.FirstOrDefaultAsync( - x => x.QueueName == Constants.MQ_ANNOTATIONS_QUEUE, token: cancellationToken)) + x => x.QueueName == Constants.MQ_ANNOTATIONS_QUEUE, token: cancellationToken)) )?.Offset ?? 0; + _consumer = await Consumer.Create(new ConsumerConfig(consumerSystem, Constants.MQ_ANNOTATIONS_QUEUE) { Reference = _hardwareService.GetHardware().Hash, @@ -71,7 +76,7 @@ public class AnnotationService : INotificationHandler MessageHandler = async (_, _, context, message) => { var msg = MessagePackSerializer.Deserialize(message.Data.Contents); - await _dbFactory.Run(async db => await db.QueueOffsets + await _dbFactory.Run(async db => await db.QueueOffsets .Where(x => x.QueueName == Constants.MQ_ANNOTATIONS_QUEUE) .Set(x => x.Offset, context.Offset) .UpdateAsync(token: cancellationToken)); @@ -95,28 +100,29 @@ public class AnnotationService : INotificationHandler msg.CreatedRole, msg.CreatedEmail, generateThumbnail: true, - cancellationToken); + fromQueue: true, + token: cancellationToken); } }); } //AI - public async Task SaveAnnotation(AnnotationImage a, CancellationToken cancellationToken = default) + public async Task SaveAnnotation(AnnotationImage a, CancellationToken ct = default) { a.Time = TimeSpan.FromMilliseconds(a.Milliseconds); return await SaveAnnotationInner(DateTime.Now, a.OriginalMediaName, a.Time, a.Detections.ToList(), - a.Source, new MemoryStream(a.Image), _authProvider.CurrentUser.Role, _authProvider.CurrentUser.Email, generateThumbnail: true, cancellationToken); + SourceEnum.AI, new MemoryStream(a.Image), _authProvider.CurrentUser.Role, _authProvider.CurrentUser.Email, generateThumbnail: true, token: ct); } //Manual - public async Task SaveAnnotation(string originalMediaName, TimeSpan time, List detections, SourceEnum source, Stream? stream = null, CancellationToken token = default) => - await SaveAnnotationInner(DateTime.UtcNow, originalMediaName, time, detections, source, stream, - _authProvider.CurrentUser.Role, _authProvider.CurrentUser.Email, generateThumbnail: true, token); + public async Task SaveAnnotation(string originalMediaName, TimeSpan time, List detections, Stream? stream = null, CancellationToken token = default) => + await SaveAnnotationInner(DateTime.UtcNow, originalMediaName, time, detections, SourceEnum.Manual, stream, + _authProvider.CurrentUser.Role, _authProvider.CurrentUser.Email, generateThumbnail: true, token: token); //Manual Validate existing public async Task ValidateAnnotation(Annotation annotation, CancellationToken token = default) => await SaveAnnotationInner(DateTime.UtcNow, annotation.OriginalMediaName, annotation.Time, annotation.Detections.ToList(), SourceEnum.Manual, null, - _authProvider.CurrentUser.Role, _authProvider.CurrentUser.Email, generateThumbnail: false, token); + _authProvider.CurrentUser.Role, _authProvider.CurrentUser.Email, token: token); // Manual save from Validators -> Validated -> stream: azaion-annotations-confirm // AI, Manual save from Operators -> Created -> stream: azaion-annotations @@ -124,6 +130,7 @@ public class AnnotationService : INotificationHandler RoleEnum userRole, string createdEmail, bool generateThumbnail = false, + bool fromQueue = false, CancellationToken token = default) { @@ -179,7 +186,8 @@ public class AnnotationService : INotificationHandler if (generateThumbnail) await _galleryService.CreateThumbnail(annotation, token); - await _producer.SendToInnerQueue(annotation, token); + if (!fromQueue) //Send to queue only if we're not getting from queue already + await _producer.SendToInnerQueue(annotation, token); await _mediator.Publish(new AnnotationCreatedEvent(annotation), token); await ThrottleExt.ThrottleRunAfter(() => diff --git a/Azaion.Common/Services/GalleryService.cs b/Azaion.Common/Services/GalleryService.cs index 896a13f..2589397 100644 --- a/Azaion.Common/Services/GalleryService.cs +++ b/Azaion.Common/Services/GalleryService.cs @@ -255,8 +255,7 @@ public class GalleryService( var color = _annotationConfig.DetectionClassesDict[label.ClassNumber].Color; var brush = new SolidBrush(Color.FromArgb(color.A, color.R, color.G, color.B)); - var rectangle = new RectangleF((float)((label.X - frameX) / scale), (float)((label.Y - frameY) / scale), (float)(label.Width / scale), (float)(label.Height / scale)); - g.FillRectangle(brush, rectangle); + g.DrawRectangle(new Pen(brush, width: 3), (float)((label.X - frameX) / scale), (float)((label.Y - frameY) / scale), (float)(label.Width / scale), (float)(label.Height / scale)); } bitmap.Save(annotation.ThumbPath, ImageFormat.Jpeg); diff --git a/Azaion.Dataset/DatasetExplorerEventHandler.cs b/Azaion.Dataset/DatasetExplorerEventHandler.cs index c33707a..03d69b8 100644 --- a/Azaion.Dataset/DatasetExplorerEventHandler.cs +++ b/Azaion.Dataset/DatasetExplorerEventHandler.cs @@ -67,7 +67,7 @@ public class DatasetExplorerEventHandler( .Select(x => new Detection(a.Name, x.GetLabel(datasetExplorer.ExplorerEditor.RenderSize))) .ToList(); var index = datasetExplorer.ThumbnailsView.SelectedIndex; - await annotationService.SaveAnnotation(a.OriginalMediaName, a.Time, detections, SourceEnum.Manual, token: cancellationToken); + await annotationService.SaveAnnotation(a.OriginalMediaName, a.Time, detections, token: cancellationToken); await datasetExplorer.EditAnnotation(index + 1); break; case PlaybackControlEnum.RemoveSelectedAnns: diff --git a/Azaion.Suite/App.xaml.cs b/Azaion.Suite/App.xaml.cs index cb0474f..d77f4a3 100644 --- a/Azaion.Suite/App.xaml.cs +++ b/Azaion.Suite/App.xaml.cs @@ -38,6 +38,7 @@ public partial class App private IAuthProvider _authProvider = null!; private Stream _securedConfig = null!; + private Stream _systemConfig = null!; private static readonly Guid KeyPressTaskId = Guid.NewGuid(); private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) @@ -95,7 +96,8 @@ public partial class App { credentials.Folder = secureAppConfig.InferenceClientConfig.ResourcesFolder; _authProvider.Login(credentials); - _securedConfig = _resourceLoader.LoadFile("secured-config.json"); + _securedConfig = _resourceLoader.LoadFile("config.secured.json"); + _systemConfig = _resourceLoader.LoadFile("config.system.json"); AppDomain.CurrentDomain.AssemblyResolve += (_, a) => { @@ -146,7 +148,8 @@ public partial class App .ConfigureAppConfiguration((context, config) => config .AddCommandLine(Environment.GetCommandLineArgs()) .AddJsonFile(SecurityConstants.CONFIG_PATH, optional: true, reloadOnChange: true) - .AddJsonStream(_securedConfig)) + .AddJsonStream(_securedConfig) + .AddJsonStream(_systemConfig)) .UseSerilog() .ConfigureServices((context, services) => { @@ -159,6 +162,7 @@ public partial class App services.ConfigureSection(context.Configuration); services.ConfigureSection(context.Configuration); services.ConfigureSection(context.Configuration); + services.ConfigureSection(context.Configuration); #region External Services diff --git a/Azaion.Suite/config.json b/Azaion.Suite/config.json index 1260f88..879b5b8 100644 --- a/Azaion.Suite/config.json +++ b/Azaion.Suite/config.json @@ -20,47 +20,8 @@ "ResultsDirectory": "E:\\results", "ThumbnailsDirectory": "E:\\thumbnails" }, - "AnnotationConfig": { - "DetectionClasses": [ - { "Id": 0, "Name": "ArmorVehicle", "ShortName": "Броня", "Color": "#FF0000" }, - { "Id": 1, "Name": "Truck", "ShortName": "Вантаж.", "Color": "#00FF00" }, - { "Id": 2, "Name": "Vehicle", "ShortName": "Машина", "Color": "#0000FF" }, - { "Id": 3, "Name": "Atillery", "ShortName": "Арта", "Color": "#FFFF00" }, - { "Id": 4, "Name": "Shadow", "ShortName": "Тінь", "Color": "#FF00FF" }, - { "Id": 5, "Name": "Trenches", "ShortName": "Окопи", "Color": "#00FFFF" }, - { "Id": 6, "Name": "MilitaryMan", "ShortName": "Військов", "Color": "#188021" }, - { "Id": 7, "Name": "TyreTracks", "ShortName": "Накати", "Color": "#800000" }, - { "Id": 8, "Name": "AdditArmoredTank", "ShortName": "Танк.захист", "Color": "#008000" }, - { "Id": 9, "Name": "Smoke", "ShortName": "Дим", "Color": "#000080" }, - { "Id": 10, "Name": "Plane", "ShortName": "Літак", "Color": "#000080" }, - { "Id": 11, "Name": "Moto", "ShortName": "Мото", "Color": "#808000" }, - { "Id": 12, "Name": "CamouflageNnet", "ShortName": "Сітка", "Color": "#800080" }, - { "Id": 13, "Name": "CamouflageBranches", "ShortName": "Гілки", "Color": "#008080" }, - { "Id": 14, "Name": "Roof", "ShortName": "Дах", "Color": "#0050A0" }, - { "Id": 15, "Name": "Building", "ShortName": "Будівля", "Color": "#008080" } - ], - "LastSelectedExplorerClass": null, - "VideoFormats": [ ".mp4", ".mov", ".avi" ], - "ImageFormats": [ ".jpg", ".jpeg", ".png", ".bmp" ], - "AnnotationsDbFile": "annotations.db", + "UIConfig": { "LeftPanelWidth": 220.0, "RightPanelWidth": 230.0 - }, - "AIRecognitionConfig": { - "FramePeriodRecognition": 4, - "FrameRecognitionSeconds": 2.0, - "ProbabilityThreshold": 0.25, - - "TrackingDistanceConfidence": 0.15, - "TrackingProbabilityIncrease": 15.0, - "TrackingIntersectionThreshold": 0.8, - - "ModelBatchSize": 4 - }, - "ThumbnailConfig": { "Size": "240,135", "Border": 10 }, - "MapConfig": - { - "Service": "", - "ApiKey": "" } } \ No newline at end of file diff --git a/Azaion.Suite/config.production.json b/Azaion.Suite/config.production.json index 0c235b1..dd879a7 100644 --- a/Azaion.Suite/config.production.json +++ b/Azaion.Suite/config.production.json @@ -3,11 +3,13 @@ "ZeroMqHost": "127.0.0.1", "ZeroMqPort": 5131, "RetryCount": 25, - "TimeoutSeconds": 5 + "TimeoutSeconds": 5, + "ResourcesFolder": "" }, "GpsDeniedClientConfig": { "ZeroMqHost": "127.0.0.1", - "ZeroMqPort": 5231, + "ZeroMqPort": 5555, + "ZeroMqReceiverPort": 5556, "RetryCount": 25, "TimeoutSeconds": 5 }, @@ -18,42 +20,8 @@ "ResultsDirectory": "results", "ThumbnailsDirectory": "thumbnails" }, - "AnnotationConfig": { - "DetectionClasses": [ - { "Id": 0, "Name": "ArmorVehicle", "ShortName": "Броня", "Color": "#80FF0000" }, - { "Id": 1, "Name": "Truck", "ShortName": "Вантаж.", "Color": "#8000FF00" }, - { "Id": 2, "Name": "Vehicle", "ShortName": "Машина", "Color": "#800000FF" }, - { "Id": 3, "Name": "Atillery", "ShortName": "Арта", "Color": "#80FFFF00" }, - { "Id": 4, "Name": "Shadow", "ShortName": "Тінь", "Color": "#80FF00FF" }, - { "Id": 5, "Name": "Trenches", "ShortName": "Окопи", "Color": "#8000FFFF" }, - { "Id": 6, "Name": "MilitaryMan", "ShortName": "Військов", "Color": "#80188021" }, - { "Id": 7, "Name": "TyreTracks", "ShortName": "Накати", "Color": "#80800000" }, - { "Id": 8, "Name": "AdditArmoredTank", "ShortName": "Танк.захист", "Color": "#80008000" }, - { "Id": 9, "Name": "Smoke", "ShortName": "Дим", "Color": "#8080000080" }, - { "Id": 10, "Name": "Plane", "ShortName": "Літак", "Color": "#80000080" }, - { "Id": 11, "Name": "Moto", "ShortName": "Мото", "Color": "#80808000" }, - { "Id": 12, "Name": "CamouflageNnet", "ShortName": "Сітка", "Color": "#80800080" }, - { "Id": 13, "Name": "CamouflageBranches", "ShortName": "Гілки", "Color": "#80008080" }, - { "Id": 14, "Name": "Roof", "ShortName": "Дах", "Color": "#800050A0" }, - { "Id": 15, "Name": "Building", "ShortName": "Будівля", "Color": "#80008080" } - ], - "LastSelectedExplorerClass": null, - "VideoFormats": [ ".mp4", ".mov", ".avi" ], - "ImageFormats": [ ".jpg", ".jpeg", ".png", ".bmp" ], - "AnnotationsDbFile": "annotations.db", - "LeftPanelWidth": 240.0, - "RightPanelWidth": 240.0 - }, - "AIRecognitionConfig": { - "FramePeriodRecognition": 6, - "FrameRecognitionSeconds": 2.0, - "ProbabilityThreshold": 0.25, - - "TrackingDistanceConfidence": 0.15, - "TrackingProbabilityIncrease": 15.0, - "TrackingIntersectionThreshold": 0.8, - - "ModelBatchSize": 2 - }, - "ThumbnailConfig": { "Size": "240,135", "Border": 10 } + "UIConfig": { + "LeftPanelWidth": 170.0, + "RightPanelWidth": 120.0 + } } \ No newline at end of file diff --git a/Azaion.Suite/config.secured.json b/Azaion.Suite/config.secured.json new file mode 100644 index 0000000..2ba2e1f --- /dev/null +++ b/Azaion.Suite/config.secured.json @@ -0,0 +1,19 @@ +{ + "QueueConfig": + { + "Host": "188.245.120.247", + "Port": 5552, + "CommandsPort": 5672, + + "ProducerUsername" : "azaion_producer", + "ProducerPassword" : "Az12onPr00duccewr", + + "ConsumerUsername" : "azaion_receiver", + "ConsumerPassword" : "Az1onRecce777ve2r" + }, + "MapConfig": + { + "Service": "GoogleMaps", + "ApiKey": "AIzaSyAXRBDBOskC5QOHG6VJWzmVJwYKcu6WH8k" + } +} \ No newline at end of file diff --git a/Azaion.Suite/config.system.json b/Azaion.Suite/config.system.json new file mode 100644 index 0000000..bc78f06 --- /dev/null +++ b/Azaion.Suite/config.system.json @@ -0,0 +1,37 @@ +{ + "AnnotationConfig": { + "DetectionClasses": [ + { "Id": 0, "Name": "ArmorVehicle", "ShortName": "Броня", "Color": "#FF0000" }, + { "Id": 1, "Name": "Truck", "ShortName": "Вантаж.", "Color": "#00FF00" }, + { "Id": 2, "Name": "Vehicle", "ShortName": "Машина", "Color": "#0000FF" }, + { "Id": 3, "Name": "Atillery", "ShortName": "Арта", "Color": "#FFFF00" }, + { "Id": 4, "Name": "Shadow", "ShortName": "Тінь", "Color": "#FF00FF" }, + { "Id": 5, "Name": "Trenches", "ShortName": "Окопи", "Color": "#00FFFF" }, + { "Id": 6, "Name": "MilitaryMan", "ShortName": "Військов", "Color": "#188021" }, + { "Id": 7, "Name": "TyreTracks", "ShortName": "Накати", "Color": "#800000" }, + { "Id": 8, "Name": "AdditArmoredTank", "ShortName": "Танк.захист", "Color": "#008000" }, + { "Id": 9, "Name": "Smoke", "ShortName": "Дим", "Color": "#000080" }, + { "Id": 10, "Name": "Plane", "ShortName": "Літак", "Color": "#000080" }, + { "Id": 11, "Name": "Moto", "ShortName": "Мото", "Color": "#808000" }, + { "Id": 12, "Name": "CamouflageNnet", "ShortName": "Сітка", "Color": "#800080" }, + { "Id": 13, "Name": "CamouflageBranches", "ShortName": "Гілки", "Color": "#2f4f4f" }, + { "Id": 14, "Name": "Roof", "ShortName": "Дах", "Color": "#1e90ff" }, + { "Id": 15, "Name": "Building", "ShortName": "Будівля", "Color": "#ffb6c1" } + ], + "VideoFormats": [ ".mp4", ".mov", ".avi" ], + "ImageFormats": [ ".jpg", ".jpeg", ".png", ".bmp" ], + "AnnotationsDbFile": "annotations.db" + }, + "AIRecognitionConfig": { + "FramePeriodRecognition": 4, + "FrameRecognitionSeconds": 2.0, + "ProbabilityThreshold": 0.25, + + "TrackingDistanceConfidence": 0.15, + "TrackingProbabilityIncrease": 15.0, + "TrackingIntersectionThreshold": 0.8, + + "ModelBatchSize": 4 + }, + "ThumbnailConfig": { "Size": "240,135", "Border": 10 } +} \ No newline at end of file