From 83ae6a0ae98ce2f4ac781861a0b56cd1ad37e785 Mon Sep 17 00:00:00 2001 From: Alex Bezdieniezhnykh Date: Wed, 2 Apr 2025 19:53:03 +0300 Subject: [PATCH] move detection classes and other system values from local config to remote forbid non validators to read from queue create better visualization in detector control make colors for detection classes more distinguishable fix bug with removing detection (probably completely) --- Azaion.Annotator/Annotator.xaml.cs | 25 ++++-- Azaion.Annotator/AnnotatorEventHandler.cs | 2 +- Azaion.Common/Controls/CanvasEditor.cs | 17 ++-- .../Controls/DetectionClasses.xaml.cs | 14 ++- Azaion.Common/Controls/DetectionControl.cs | 89 +++++++++++-------- Azaion.Common/DTO/Config/AnnotationConfig.cs | 3 - Azaion.Common/DTO/Config/AppConfig.cs | 21 +++-- Azaion.Common/DTO/Config/UIConfig.cs | 7 ++ Azaion.Common/DTO/DetectionClass.cs | 4 +- Azaion.Common/DTO/Label.cs | 4 +- Azaion.Common/Extensions/ColorExtensions.cs | 6 +- Azaion.Common/Services/AnnotationService.cs | 28 +++--- Azaion.Common/Services/GalleryService.cs | 3 +- Azaion.Dataset/DatasetExplorerEventHandler.cs | 2 +- Azaion.Suite/App.xaml.cs | 8 +- Azaion.Suite/config.json | 41 +-------- Azaion.Suite/config.production.json | 48 ++-------- Azaion.Suite/config.secured.json | 19 ++++ Azaion.Suite/config.system.json | 37 ++++++++ 19 files changed, 209 insertions(+), 169 deletions(-) create mode 100644 Azaion.Common/DTO/Config/UIConfig.cs create mode 100644 Azaion.Suite/config.secured.json create mode 100644 Azaion.Suite/config.system.json 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