diff --git a/Azaion.Annotator/DTO/AnnotationClass.cs b/Azaion.Annotator/DTO/AnnotationClass.cs index df1fa19..e2bb115 100644 --- a/Azaion.Annotator/DTO/AnnotationClass.cs +++ b/Azaion.Annotator/DTO/AnnotationClass.cs @@ -4,12 +4,15 @@ using Azaion.Annotator.Extensions; namespace Azaion.Annotator.DTO; -public class AnnotationClass(int id, string name = "") +public class AnnotationClass { - public int Id { get; set; } = id; + public int Id { get; set; } - public string Name { get; set; } = name; - public Color Color { get; set; } = id.ToColor(); + public string Name { get; set; } + public string ShortName { get; set; } + + [JsonIgnore] + public Color Color => Id.ToColor(); [JsonIgnore] public int ClassNumber => Id + 1; diff --git a/Azaion.Annotator/DTO/AnnotationResult.cs b/Azaion.Annotator/DTO/AnnotationResult.cs index aec26d8..c64e851 100644 --- a/Azaion.Annotator/DTO/AnnotationResult.cs +++ b/Azaion.Annotator/DTO/AnnotationResult.cs @@ -1,4 +1,5 @@ using System.Windows.Media; +using Azaion.Annotator.Extensions; using Newtonsoft.Json; namespace Azaion.Annotator.DTO; @@ -23,38 +24,44 @@ public class AnnotationResult //For XAML Form public string TimeStr => $"{Time:h\\:mm\\:ss}"; + private List? _detectionClasses = null!; + + //For Form [JsonIgnore] - //For XAML Form public string ClassName { get { if (Detections.Count == 0) return ""; + _detectionClasses ??= Detections.Select(x => x.ClassNumber).Distinct().ToList(); - var groups = Detections.Select(x => x.ClassNumber).GroupBy(x => x).ToList(); - return groups.Count > 1 - ? string.Join(",", groups.Select(x => x.Key + 1)) - : _config.AnnotationClassesDict[groups.FirstOrDefault().Key].Name; + return _detectionClasses.Count > 1 + ? string.Join(", ", _detectionClasses.Select(x => _config.AnnotationClassesDict[x].ShortName)) + : _config.AnnotationClassesDict[_detectionClasses.FirstOrDefault()].Name; } } + [JsonIgnore] - //For XAML Form - public Color ClassColor + public Color ClassColor1 => GetAnnotationClass(0); + [JsonIgnore] + public Color ClassColor2 => GetAnnotationClass(1); + [JsonIgnore] + public Color ClassColor3 => GetAnnotationClass(2); + [JsonIgnore] + public Color ClassColor4 => GetAnnotationClass(3); + + private Color GetAnnotationClass(int colorNumber) { - get - { - var defaultColor = (Color)ColorConverter.ConvertFromString("#404040"); - if (Detections.Count == 0) - return defaultColor; + if (Detections.Count == 0) + return (-1).ToColor(); - var groups = Detections.Select(x => x.ClassNumber).GroupBy(x => x).ToList(); + _detectionClasses ??= Detections.Select(x => x.ClassNumber).Distinct().ToList(); - return groups.Count > 1 - ? defaultColor - : _config.AnnotationClassesDict[groups.FirstOrDefault().Key].Color; - } + return colorNumber >= _detectionClasses.Count + ? _config.AnnotationClassesDict[_detectionClasses.LastOrDefault()].Color + : _config.AnnotationClassesDict[_detectionClasses[colorNumber]].Color; } diff --git a/Azaion.Annotator/DTO/Config.cs b/Azaion.Annotator/DTO/Config.cs index 752fca5..206b8ef 100644 --- a/Azaion.Annotator/DTO/Config.cs +++ b/Azaion.Annotator/DTO/Config.cs @@ -22,6 +22,8 @@ public class Config public List AnnotationClasses { get; set; } = []; private Dictionary? _annotationClassesDict; + + [JsonIgnore] public Dictionary AnnotationClassesDict => _annotationClassesDict ??= AnnotationClasses.ToDictionary(x => x.Id); public WindowConfig MainWindowConfig { get; set; } = null!; diff --git a/Azaion.Annotator/DTO/FormState.cs b/Azaion.Annotator/DTO/FormState.cs index 765b0fa..bad09b5 100644 --- a/Azaion.Annotator/DTO/FormState.cs +++ b/Azaion.Annotator/DTO/FormState.cs @@ -15,7 +15,7 @@ public class FormState public Size CurrentVideoSize { get; set; } public TimeSpan CurrentVideoLength { get; set; } - public bool BackgroundShown { get; set; } + public TimeSpan? BackgroundTime { get; set; } public int CurrentVolume { get; set; } = 100; public ObservableCollection AnnotationResults { get; set; } = []; public WindowsEnum ActiveWindow { get; set; } diff --git a/Azaion.Annotator/DatasetExplorer.xaml.cs b/Azaion.Annotator/DatasetExplorer.xaml.cs index bff4812..c49cdd3 100644 --- a/Azaion.Annotator/DatasetExplorer.xaml.cs +++ b/Azaion.Annotator/DatasetExplorer.xaml.cs @@ -47,7 +47,7 @@ public partial class DatasetExplorer Loaded += async (_, _) => { AllAnnotationClasses = new ObservableCollection( - new List { new(-1, "All") } + new List { new() {Id = -1, Name = "All", ShortName = "All"}} .Concat(_config.AnnotationClasses)); LvClasses.ItemsSource = AllAnnotationClasses; diff --git a/Azaion.Annotator/MainWindow.xaml b/Azaion.Annotator/MainWindow.xaml index 7bb400f..a056f6c 100644 --- a/Azaion.Annotator/MainWindow.xaml +++ b/Azaion.Annotator/MainWindow.xaml @@ -260,7 +260,12 @@ diff --git a/Azaion.Annotator/MainWindow.xaml.cs b/Azaion.Annotator/MainWindow.xaml.cs index 8b06d80..113e092 100644 --- a/Azaion.Annotator/MainWindow.xaml.cs +++ b/Azaion.Annotator/MainWindow.xaml.cs @@ -123,7 +123,7 @@ public partial class MainWindow ReloadFiles(); if (_config.AnnotationClasses.Count == 0) - _config.AnnotationClasses.Add(new AnnotationClass(0)); + _config.AnnotationClasses.Add(new AnnotationClass{Id = 0}); AnnotationClasses = new ObservableCollection(_config.AnnotationClasses); LvClasses.ItemsSource = AnnotationClasses; @@ -299,7 +299,7 @@ public partial class MainWindow if (File.Exists(imgPath)) { Editor.Background = new ImageBrush { ImageSource = await imgPath.OpenImage() }; - _formState.BackgroundShown = true; + _formState.BackgroundTime = time; videoSize = Editor.RenderSize; } } diff --git a/Azaion.Annotator/MainWindowEventHandler.cs b/Azaion.Annotator/MainWindowEventHandler.cs index e4f1ab8..dd206f2 100644 --- a/Azaion.Annotator/MainWindowEventHandler.cs +++ b/Azaion.Annotator/MainWindowEventHandler.cs @@ -150,10 +150,10 @@ public class MainWindowEventHandler : _mediaPlayer.Pause(); if (!_mediaPlayer.IsPlaying) _mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.AnnotationHelp]); - if (_formState.BackgroundShown) + if (_formState.BackgroundTime.HasValue) { _mainWindow.Editor.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)); - _formState.BackgroundShown = false; + _formState.BackgroundTime = null; } break; case PlaybackControlEnum.Stop: @@ -248,11 +248,11 @@ public class MainWindowEventHandler : if (_formState.CurrentMedia == null) return; - var time = TimeSpan.FromMilliseconds(_mediaPlayer.Time); + var time = _formState.BackgroundTime ?? TimeSpan.FromMilliseconds(_mediaPlayer.Time); var fName = _formState.GetTimeName(time); var currentAnns = _mainWindow.Editor.CurrentAnns - .Select(x => new YoloLabel(x.Info, _mainWindow.Editor.RenderSize, _formState.BackgroundShown ? _mainWindow.Editor.RenderSize : _formState.CurrentVideoSize)) + .Select(x => new YoloLabel(x.Info, _mainWindow.Editor.RenderSize, _formState.BackgroundTime.HasValue ? _mainWindow.Editor.RenderSize : _formState.CurrentVideoSize)) .ToList(); await YoloLabel.WriteToFile(currentAnns, Path.Combine(_config.LabelsDirectory, $"{fName}.txt")); @@ -267,12 +267,13 @@ public class MainWindowEventHandler : _mainWindow.Editor.RemoveAllAnns(); if (isVideo) { - if (_formState.BackgroundShown) + if (_formState.BackgroundTime.HasValue) { //no need to save image, it's already there, just remove background _mainWindow.Editor.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)); - _formState.BackgroundShown = false; + _formState.BackgroundTime = null; + //next item var annGrid = _mainWindow.DgAnnotations; annGrid.SelectedIndex = Math.Min(annGrid.Items.Count, annGridSelectedIndex + 1); _mainWindow.OpenAnnotationResult((AnnotationResult)annGrid.SelectedItem); diff --git a/Azaion.Annotator/config.json b/Azaion.Annotator/config.json index 8e83711..5dd0ea1 100644 --- a/Azaion.Annotator/config.json +++ b/Azaion.Annotator/config.json @@ -6,16 +6,17 @@ "ResultsDirectory": "E:\\results", "UnknownImages": "E:\\unknown", "AnnotationClasses": [ - { "Id": 0, "Name": "Броньована техніка", "Color": "#40FF0000" }, - { "Id": 1, "Name": "Вантажівка", "Color": "#4000FF00" }, - { "Id": 2, "Name": "Машина легкова", "Color": "#400000FF" }, - { "Id": 3, "Name": "Артилерія", "Color": "#40FFFF00" }, - { "Id": 4, "Name": "Тінь від техніки", "Color": "#40FF00FF" }, - { "Id": 5, "Name": "Окопи", "Color": "#4000FFFF" }, - { "Id": 6, "Name": "Військовий", "Color": "#40000000" }, - { "Id": 7, "Name": "Накати", "Color": "#40800000" }, - { "Id": 8, "Name": "Танк з захистом", "Color": "#40008000" }, - { "Id": 9, "Name": "Дим", "Color": "#40000080" } + { "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",