fix initialization, throttle operations

day/winter/night switcher fixes
This commit is contained in:
Alex Bezdieniezhnykh
2025-02-19 23:07:16 +02:00
parent c314268d1e
commit d1af7958f8
17 changed files with 170 additions and 88 deletions
+7 -13
View File
@@ -51,7 +51,7 @@ public partial class Annotator
private readonly TimeSpan _thresholdBefore = TimeSpan.FromMilliseconds(100); private readonly TimeSpan _thresholdBefore = TimeSpan.FromMilliseconds(100);
private readonly TimeSpan _thresholdAfter = TimeSpan.FromMilliseconds(300); private readonly TimeSpan _thresholdAfter = TimeSpan.FromMilliseconds(300);
private static readonly Guid SaveConfigTaskId = Guid.NewGuid();
public ObservableCollection<MediaFileInfo> AllMediaFiles { get; set; } = new(); public ObservableCollection<MediaFileInfo> AllMediaFiles { get; set; } = new();
public ObservableCollection<MediaFileInfo> FilteredMediaFiles { get; set; } = new(); public ObservableCollection<MediaFileInfo> FilteredMediaFiles { get; set; } = new();
@@ -72,6 +72,7 @@ public partial class Annotator
IInferenceService inferenceService) IInferenceService inferenceService)
{ {
InitializeComponent(); InitializeComponent();
_appConfig = appConfig.Value; _appConfig = appConfig.Value;
_configUpdater = configUpdater; _configUpdater = configUpdater;
_libVLC = libVLC; _libVLC = libVLC;
@@ -119,9 +120,7 @@ public partial class Annotator
_suspendLayout = false; _suspendLayout = false;
TbFolder.Text = _appConfig.DirectoriesConfig.VideosDirectory; TbFolder.Text = _appConfig.DirectoriesConfig.VideosDirectory;
AnnotationClasses = new ObservableCollection<DetectionClass>(_appConfig.AnnotationConfig.AnnotationClasses); LvClasses.Init(_appConfig.AnnotationConfig.DetectionClasses);
LvClasses.DetectionDataGrid.ItemsSource = AnnotationClasses;
LvClasses.SelectNum(0);
if (LvFiles.Items.IsEmpty) if (LvFiles.Items.IsEmpty)
BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.Initial]); BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.Initial]);
@@ -261,7 +260,7 @@ public partial class Annotator
{ {
_configUpdater.Save(_appConfig); _configUpdater.Save(_appConfig);
return Task.CompletedTask; return Task.CompletedTask;
}, TimeSpan.FromSeconds(5)); }, SaveConfigTaskId, TimeSpan.FromSeconds(5));
} }
private void ShowTimeAnnotations(TimeSpan time) private void ShowTimeAnnotations(TimeSpan time)
@@ -295,7 +294,7 @@ public partial class Annotator
} }
foreach (var detection in annotation.Detections) foreach (var detection in annotation.Detections)
{ {
var annClass = _appConfig.AnnotationConfig.AnnotationClasses[detection.ClassNumber]; var annClass = _appConfig.AnnotationConfig.DetectionClasses[detection.ClassNumber];
var canvasLabel = new CanvasLabel(detection, canvasSize, videoSize, detection.Probability); var canvasLabel = new CanvasLabel(detection, canvasSize, videoSize, detection.Probability);
Editor.CreateDetectionControl(annClass, annotation.Time, canvasLabel); Editor.CreateDetectionControl(annClass, annotation.Time, canvasLabel);
} }
@@ -312,6 +311,7 @@ public partial class Annotator
var annotations = await _dbFactory.Run(async db => var annotations = await _dbFactory.Run(async db =>
await db.Annotations.LoadWith(x => x.Detections) await db.Annotations.LoadWith(x => x.Detections)
.Where(x => x.OriginalMediaName == _formState.VideoName) .Where(x => x.OriginalMediaName == _formState.VideoName)
.OrderBy(x => x.Time)
.ToListAsync(token: MainCancellationSource.Token)); .ToListAsync(token: MainCancellationSource.Token));
TimedAnnotations.Clear(); TimedAnnotations.Clear();
@@ -425,12 +425,6 @@ public partial class Annotator
private void SeekTo(TimeSpan time) => private void SeekTo(TimeSpan time) =>
SeekTo((long)time.TotalMilliseconds); SeekTo((long)time.TotalMilliseconds);
// private void AddClassBtnClick(object sender, RoutedEventArgs e)
// {
// LvClasses.IsReadOnly = false;
// DetectionClasses.Add(new DetectionClass(DetectionClasses.Count));
// LvClasses.SelectedIndex = DetectionClasses.Count - 1;
// }
private async void OpenFolderItemClick(object sender, RoutedEventArgs e) => await OpenFolder(); private async void OpenFolderItemClick(object sender, RoutedEventArgs e) => await OpenFolder();
private async void OpenFolderButtonClick(object sender, RoutedEventArgs e) => await OpenFolder(); private async void OpenFolderButtonClick(object sender, RoutedEventArgs e) => await OpenFolder();
@@ -521,8 +515,8 @@ public partial class Annotator
{ {
//Take not annotataed medias //Take not annotataed medias
files = (LvFiles.ItemsSource as IEnumerable<MediaFileInfo>)?.Skip(LvFiles.SelectedIndex) files = (LvFiles.ItemsSource as IEnumerable<MediaFileInfo>)?.Skip(LvFiles.SelectedIndex)
.Take(Constants.DETECTION_BATCH_SIZE)
.Where(x => !x.HasAnnotations) .Where(x => !x.HasAnnotations)
.Take(Constants.DETECTION_BATCH_SIZE)
.Select(x => x.Path) .Select(x => x.Path)
.ToList() ?? []; .ToList() ?? [];
if (files.Count != 0) if (files.Count != 0)
+4 -3
View File
@@ -51,7 +51,8 @@
CanUserResizeRows="False" CanUserResizeRows="False"
CanUserResizeColumns="False" CanUserResizeColumns="False"
SelectionChanged="DetectionDataGrid_SelectionChanged" SelectionChanged="DetectionDataGrid_SelectionChanged"
x:FieldModifier="public"> x:FieldModifier="public"
>
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTemplateColumn Width="50" Header="Клавіша" CanUserSort="False"> <DataGridTemplateColumn Width="50" Header="Клавіша" CanUserSort="False">
<DataGridTemplateColumn.HeaderStyle> <DataGridTemplateColumn.HeaderStyle>
@@ -90,13 +91,13 @@
IsChecked="True" IsChecked="True"
Style="{StaticResource ButtonRadioButtonStyle}"/> Style="{StaticResource ButtonRadioButtonStyle}"/>
<RadioButton x:Name="EveningModeRadioButton" <RadioButton x:Name="EveningModeRadioButton"
Tag="1" Tag="20"
Content="Зима" Content="Зима"
GroupName="Mode" GroupName="Mode"
Checked="ModeRadioButton_Checked" Margin="10,0,0,0" Checked="ModeRadioButton_Checked" Margin="10,0,0,0"
Style="{StaticResource ButtonRadioButtonStyle}"/> Style="{StaticResource ButtonRadioButtonStyle}"/>
<RadioButton x:Name="NightModeRadioButton" <RadioButton x:Name="NightModeRadioButton"
Tag="2" Tag="40"
Content="Ніч" Content="Ніч"
GroupName="Mode" GroupName="Mode"
Checked="ModeRadioButton_Checked" Margin="10,0,0,0" Checked="ModeRadioButton_Checked" Margin="10,0,0,0"
@@ -4,16 +4,26 @@ using Azaion.Common.DTO;
namespace Azaion.Common.Controls; namespace Azaion.Common.Controls;
public class DetectionClassChangedEventArgs(DetectionClass? detectionClass, int classNumber) : EventArgs public class DetectionClassChangedEventArgs(DetectionClass detectionClass, int classNumber) : EventArgs
{ {
public DetectionClass? DetectionClass { get; } = detectionClass; public DetectionClass DetectionClass { get; } = detectionClass;
public int ClassNumber { get; } = classNumber; public int ClassNumber { get; } = classNumber;
} }
public partial class DetectionClasses public partial class DetectionClasses
{ {
public event EventHandler<DetectionClassChangedEventArgs>? DetectionClassChanged; public event EventHandler<DetectionClassChangedEventArgs>? DetectionClassChanged;
public DetectionClasses() => InitializeComponent();
public DetectionClasses()
{
InitializeComponent();
}
public void Init(List<DetectionClass> detectionClasses)
{
DetectionDataGrid.ItemsSource = detectionClasses;
DetectionDataGrid.SelectedIndex = 0;
}
public int CurrentClassNumber { get; private set; } = 0; public int CurrentClassNumber { get; private set; } = 0;
public DetectionClass? CurrentDetectionClass { get; set; } public DetectionClass? CurrentDetectionClass { get; set; }
@@ -27,26 +37,25 @@ public partial class DetectionClasses
private void RaiseDetectionClassChanged() private void RaiseDetectionClassChanged()
{ {
var detClass = (DetectionClass)DetectionDataGrid.SelectedItem; var detClass = (DetectionClass)DetectionDataGrid.SelectedItem;
var baseClassNumber = detClass?.Id ?? 0; if (detClass == null)
return;
var modeAmplifier = 0; var modeAmplifier = 0;
foreach (var child in ModeSwitcherPanel.Children) foreach (var child in ModeSwitcherPanel.Children)
if (child is RadioButton { IsChecked: true } rb) if (child is RadioButton { IsChecked: true } rb)
if (int.TryParse(rb.Tag?.ToString(), out int modeIndex)) if (int.TryParse(rb.Tag?.ToString(), out int modeIndex))
{ {
if (detClass != null)
detClass.PhotoMode = (PhotoMode)modeIndex; detClass.PhotoMode = (PhotoMode)modeIndex;
modeAmplifier += modeIndex * 20; modeAmplifier += modeIndex;
} }
CurrentDetectionClass = detClass; CurrentDetectionClass = detClass;
CurrentClassNumber = baseClassNumber + modeAmplifier; CurrentClassNumber = detClass.Id + modeAmplifier;
DetectionClassChanged?.Invoke(this, new DetectionClassChangedEventArgs(detClass, CurrentClassNumber)); DetectionClassChanged?.Invoke(this, new DetectionClassChangedEventArgs(detClass, CurrentClassNumber));
} }
public void SelectNum(int keyNumber) public void SelectNum(int keyNumber)
{ {
DetectionDataGrid.SelectedIndex = keyNumber; DetectionDataGrid.SelectedIndex = keyNumber;
+2 -2
View File
@@ -50,7 +50,7 @@ public class DetectionControl : Border
_resizeStart = resizeStart; _resizeStart = resizeStart;
_classNameLabel = new TextBlock _classNameLabel = new TextBlock
{ {
Text = detectionClass.Name, Text = detectionClass.UIName,
HorizontalAlignment = HorizontalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Top, VerticalAlignment = VerticalAlignment.Top,
Margin = new Thickness(0, 15, 0, 0), Margin = new Thickness(0, 15, 0, 0),
@@ -120,7 +120,7 @@ public class DetectionControl : Border
public YoloLabel GetLabel(Size canvasSize, Size? videoSize = null) public YoloLabel GetLabel(Size canvasSize, Size? videoSize = null)
{ {
var label = new CanvasLabel(DetectionClass.Id, Canvas.GetLeft(this), Canvas.GetTop(this), Width, Height); var label = new CanvasLabel(DetectionClass.YoloId, Canvas.GetLeft(this), Canvas.GetTop(this), Width, Height);
return new YoloLabel(label, canvasSize, videoSize); return new YoloLabel(label, canvasSize, videoSize);
} }
} }
+2 -2
View File
@@ -41,8 +41,8 @@ public class AnnotationResult
var detectionClasses = detections.Select(x => x.ClassNumber).Distinct().ToList(); var detectionClasses = detections.Select(x => x.ClassNumber).Distinct().ToList();
ClassName = detectionClasses.Count > 1 ClassName = detectionClasses.Count > 1
? string.Join(", ", detectionClasses.Select(x => allDetectionClasses[x].ShortName)) ? string.Join(", ", detectionClasses.Select(x => allDetectionClasses[x].UIName))
: allDetectionClasses[detectionClasses.FirstOrDefault()].Name; : allDetectionClasses[detectionClasses.FirstOrDefault()].UIName;
ClassColor0 = GetAnnotationClass(detectionClasses, 0); ClassColor0 = GetAnnotationClass(detectionClasses, 0);
ClassColor1 = GetAnnotationClass(detectionClasses, 1); ClassColor1 = GetAnnotationClass(detectionClasses, 1);
+22 -2
View File
@@ -4,12 +4,32 @@ namespace Azaion.Common.DTO.Config;
public class AnnotationConfig public class AnnotationConfig
{ {
public List<DetectionClass> AnnotationClasses { get; set; } = null!; public List<DetectionClass> DetectionClasses { get; set; } = null!;
[JsonIgnore] [JsonIgnore]
private Dictionary<int, DetectionClass>? _detectionClassesDict; private Dictionary<int, DetectionClass>? _detectionClassesDict;
[JsonIgnore] [JsonIgnore]
public Dictionary<int, DetectionClass> DetectionClassesDict => _detectionClassesDict ??= AnnotationClasses.ToDictionary(x => x.Id); public Dictionary<int, DetectionClass> DetectionClassesDict
{
get
{
if (_detectionClassesDict != null)
return _detectionClassesDict;
var photoModes = Enum.GetValues(typeof(PhotoMode)).Cast<PhotoMode>().ToList();
_detectionClassesDict = DetectionClasses.SelectMany(cls => photoModes.Select(mode => new DetectionClass
{
Id = cls.Id,
Name = cls.Name,
ShortName = cls.ShortName,
PhotoMode = mode
}))
.ToDictionary(x => x.YoloId, x => x);
return _detectionClassesDict;
}
}
public List<string> VideoFormats { get; set; } = null!; public List<string> VideoFormats { get; set; } = null!;
public List<string> ImageFormats { get; set; } = null!; public List<string> ImageFormats { get; set; } = null!;
+1 -1
View File
@@ -41,7 +41,7 @@ public class ConfigUpdater : IConfigUpdater
{ {
AnnotationConfig = new AnnotationConfig AnnotationConfig = new AnnotationConfig
{ {
AnnotationClasses = Constants.DefaultAnnotationClasses, DetectionClasses = Constants.DefaultAnnotationClasses,
VideoFormats = Constants.DefaultVideoFormats, VideoFormats = Constants.DefaultVideoFormats,
ImageFormats = Constants.DefaultImageFormats, ImageFormats = Constants.DefaultImageFormats,
+20
View File
@@ -11,6 +11,23 @@ public class DetectionClass
public string Name { get; set; } = null!; public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!; public string ShortName { get; set; } = null!;
public string UIName
{
get
{
var mode = PhotoMode switch
{
PhotoMode.Night => "(ніч)",
PhotoMode.Winter => "(зим)",
PhotoMode.Regular => "",
_ => ""
};
return ShortName + mode;
}
}
[JsonIgnore]
public PhotoMode PhotoMode { get; set; } public PhotoMode PhotoMode { get; set; }
[JsonIgnore] [JsonIgnore]
@@ -19,6 +36,9 @@ public class DetectionClass
[JsonIgnore] //For UI [JsonIgnore] //For UI
public int ClassNumber => Id + 1; public int ClassNumber => Id + 1;
[JsonIgnore]
public int YoloId => (int)PhotoMode + Id;
[JsonIgnore] [JsonIgnore]
public SolidColorBrush ColorBrush => new(Color); public SolidColorBrush ColorBrush => new(Color);
} }
+32 -11
View File
@@ -1,34 +1,55 @@
namespace Azaion.Common.Extensions; using System.Collections.Concurrent;
namespace Azaion.Common.Extensions;
public static class ThrottleExt public static class ThrottleExt
{ {
private static bool _throttleRunFirstOn; private static ConcurrentDictionary<Guid, bool> _taskStates = new();
public static async Task ThrottleRunFirst(this Func<Task> func, TimeSpan? throttleTime = null, CancellationToken cancellationToken = default)
public static async Task ThrottleRunFirst(Func<Task> func, Guid actionId, TimeSpan? throttleTime = null, CancellationToken cancellationToken = default)
{ {
if (_throttleRunFirstOn) if (_taskStates.ContainsKey(actionId) && _taskStates[actionId])
return; return;
_throttleRunFirstOn = true; _taskStates[actionId] = true;
try
{
await func(); await func();
}
catch (Exception e)
{
Console.WriteLine(e);
}
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
await Task.Delay(throttleTime ?? TimeSpan.FromMilliseconds(500), cancellationToken); await Task.Delay(throttleTime ?? TimeSpan.FromMilliseconds(500), cancellationToken);
_throttleRunFirstOn = false; _taskStates[actionId] = false;
}, cancellationToken); }, cancellationToken);
} }
private static bool _throttleRunAfter; public static async Task ThrottleRunAfter(Func<Task> func, Guid actionId, TimeSpan? throttleTime = null, CancellationToken cancellationToken = default)
public static async Task ThrottleRunAfter(this Func<Task> func, TimeSpan? throttleTime = null, CancellationToken cancellationToken = default)
{ {
if (_throttleRunAfter) if (_taskStates.ContainsKey(actionId) && _taskStates[actionId])
return; return;
_throttleRunAfter = true; _taskStates[actionId] = true;
_ = Task.Run(async () => _ = Task.Run(async () =>
{
try
{ {
await Task.Delay(throttleTime ?? TimeSpan.FromMilliseconds(500), cancellationToken); await Task.Delay(throttleTime ?? TimeSpan.FromMilliseconds(500), cancellationToken);
await func(); await func();
_throttleRunAfter = false; }
catch (Exception ex)
{
_taskStates[actionId] = false;
}
finally
{
_taskStates[actionId] = false;
}
}, cancellationToken); }, cancellationToken);
await Task.CompletedTask; await Task.CompletedTask;
} }
+3 -2
View File
@@ -30,6 +30,7 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
private readonly IAuthProvider _authProvider; private readonly IAuthProvider _authProvider;
private readonly QueueConfig _queueConfig; private readonly QueueConfig _queueConfig;
private Consumer _consumer = null!; private Consumer _consumer = null!;
private static readonly Guid SaveTaskId = Guid.NewGuid();
public AnnotationService( public AnnotationService(
IResourceLoader resourceLoader, IResourceLoader resourceLoader,
@@ -95,7 +96,7 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
{ {
_dbFactory.SaveToDisk(); _dbFactory.SaveToDisk();
return Task.CompletedTask; return Task.CompletedTask;
}, TimeSpan.FromSeconds(3), cancellationToken); }, SaveTaskId, TimeSpan.FromSeconds(3), cancellationToken);
} }
}); });
@@ -184,7 +185,7 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
{ {
_dbFactory.SaveToDisk(); _dbFactory.SaveToDisk();
return Task.CompletedTask; return Task.CompletedTask;
}, TimeSpan.FromSeconds(5), token); }, SaveTaskId, TimeSpan.FromSeconds(5), token);
return annotation; return annotation;
} }
@@ -28,7 +28,7 @@ public class PythonResourceLoader : IResourceLoader, IAuthProvider
public PythonResourceLoader(PythonConfig config) public PythonResourceLoader(PythonConfig config)
{ {
//StartPython(); StartPython();
_dealer.Options.Identity = Encoding.UTF8.GetBytes(_clientId.ToString("N")); _dealer.Options.Identity = Encoding.UTF8.GetBytes(_clientId.ToString("N"));
_dealer.Connect($"tcp://{config.ZeroMqHost}:{config.ZeroMqPort}"); _dealer.Connect($"tcp://{config.ZeroMqHost}:{config.ZeroMqPort}");
} }
+3 -6
View File
@@ -57,16 +57,13 @@
<RowDefinition Height="32"></RowDefinition> <RowDefinition Height="32"></RowDefinition>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="150" /> <ColumnDefinition Width="200" />
<ColumnDefinition Width="4"/> <ColumnDefinition Width="4"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<controls:DetectionClasses <controls:DetectionClasses x:Name="LvClasses"
x:Name="LvClasses"
Grid.Column="0" Grid.Column="0"
Grid.Row="0"> Grid.Row="0" />
</controls:DetectionClasses>
<TabControl <TabControl
Name="Switcher" Name="Switcher"
Grid.Column="2" Grid.Column="2"
+34 -22
View File
@@ -22,10 +22,10 @@ public partial class DatasetExplorer
private readonly AnnotationConfig _annotationConfig; private readonly AnnotationConfig _annotationConfig;
private readonly DirectoriesConfig _directoriesConfig; private readonly DirectoriesConfig _directoriesConfig;
private Dictionary<int, List<Annotation>> _annotationsDict = new(); private readonly Dictionary<int, List<Annotation>> _annotationsDict;
private readonly CancellationTokenSource _cts = new(); private readonly CancellationTokenSource _cts = new();
public ObservableCollection<DetectionClass> AllDetectionClasses { get; set; } = new(); public List<DetectionClass> AllDetectionClasses { get; set; }
public ObservableCollection<AnnotationThumbnail> SelectedAnnotations { get; set; } = new(); public ObservableCollection<AnnotationThumbnail> SelectedAnnotations { get; set; } = new();
public readonly Dictionary<string, AnnotationThumbnail> SelectedAnnotationDict = new(); public readonly Dictionary<string, AnnotationThumbnail> SelectedAnnotationDict = new();
@@ -34,6 +34,8 @@ public partial class DatasetExplorer
private readonly IDbFactory _dbFactory; private readonly IDbFactory _dbFactory;
private readonly IMediator _mediator; private readonly IMediator _mediator;
public readonly List<DetectionClass> AnnotationsClasses;
public bool ThumbnailLoading { get; set; } public bool ThumbnailLoading { get; set; }
@@ -48,6 +50,8 @@ public partial class DatasetExplorer
IDbFactory dbFactory, IDbFactory dbFactory,
IMediator mediator) IMediator mediator)
{ {
InitializeComponent();
_directoriesConfig = directoriesConfig.Value; _directoriesConfig = directoriesConfig.Value;
_annotationConfig = annotationConfig.Value; _annotationConfig = annotationConfig.Value;
_logger = logger; _logger = logger;
@@ -55,7 +59,13 @@ public partial class DatasetExplorer
_dbFactory = dbFactory; _dbFactory = dbFactory;
_mediator = mediator; _mediator = mediator;
InitializeComponent(); var photoModes = Enum.GetValues(typeof(PhotoMode)).Cast<PhotoMode>().ToList();
_annotationsDict = _annotationConfig.DetectionClasses.SelectMany(cls => photoModes.Select(mode => (int)mode + cls.Id))
.ToDictionary(x => x, _ => new List<Annotation>());
_annotationsDict.Add(-1, []);
AnnotationsClasses = annotationConfig.Value.DetectionClasses;
Loaded += OnLoaded; Loaded += OnLoaded;
Activated += (_, _) => formState.ActiveWindow = WindowEnum.DatasetExplorer; Activated += (_, _) => formState.ActiveWindow = WindowEnum.DatasetExplorer;
@@ -86,15 +96,29 @@ public partial class DatasetExplorer
Dispatcher.Invoke(() => RefreshThumbBar.Value = thumbnailsPercentage); Dispatcher.Invoke(() => RefreshThumbBar.Value = thumbnailsPercentage);
}; };
Closing += (_, _) => _cts.Cancel(); Closing += (_, _) => _cts.Cancel();
AllDetectionClasses = new List<DetectionClass>(
new List<DetectionClass> { new() {Id = -1, Name = "All", ShortName = "All"}}
.Concat(_annotationConfig.DetectionClasses));
LvClasses.Init(AllDetectionClasses);
_dbFactory.Run(async db =>
{
var allAnnotations = await db.Annotations
.LoadWith(x => x.Detections)
.OrderBy(x => x.AnnotationStatus)
.ThenByDescending(x => x.CreatedDate)
.ToListAsync();
foreach (var annotation in allAnnotations)
AddAnnotationToDict(annotation);
}).GetAwaiter().GetResult();
DataContext = this;
} }
private async void OnLoaded(object sender, RoutedEventArgs e) private async void OnLoaded(object sender, RoutedEventArgs e)
{ {
AllDetectionClasses = new ObservableCollection<DetectionClass>(
new List<DetectionClass> { new() {Id = -1, Name = "All", ShortName = "All"}}
.Concat(_annotationConfig.AnnotationClasses));
LvClasses.DetectionDataGrid.ItemsSource = AllDetectionClasses;
LvClasses.DetectionClassChanged += async (_, args) => LvClasses.DetectionClassChanged += async (_, args) =>
{ {
ExplorerEditor.CurrentAnnClass = args.DetectionClass; ExplorerEditor.CurrentAnnClass = args.DetectionClass;
@@ -106,20 +130,8 @@ public partial class DatasetExplorer
ann.DetectionClass = args.DetectionClass; ann.DetectionClass = args.DetectionClass;
}; };
ExplorerEditor.CurrentAnnClass = (DetectionClass)LvClasses.CurrentDetectionClass; ExplorerEditor.CurrentAnnClass = LvClasses.CurrentDetectionClass ?? _annotationConfig.DetectionClasses.First();
await _dbFactory.Run(async db =>
{
var allAnnotations = await db.Annotations
.LoadWith(x => x.Detections)
.OrderBy(x => x.AnnotationStatus)
.ThenByDescending(x => x.CreatedDate)
.ToListAsync();
_annotationsDict = AllDetectionClasses.ToDictionary(x => x.Id, _ => new List<Annotation>());
foreach (var annotation in allAnnotations)
AddAnnotationToDict(annotation);
});
await ReloadThumbnails(); await ReloadThumbnails();
await LoadClassDistribution(); await LoadClassDistribution();
@@ -239,7 +251,7 @@ public partial class DatasetExplorer
AnnotationsTab.Visibility = Visibility.Collapsed; AnnotationsTab.Visibility = Visibility.Collapsed;
EditorTab.Visibility = Visibility.Visible; EditorTab.Visibility = Visibility.Visible;
_tempSelectedClassIdx = LvClasses.CurrentClassNumber; _tempSelectedClassIdx = LvClasses.CurrentClassNumber;
LvClasses.DetectionDataGrid.ItemsSource = _annotationConfig.AnnotationClasses; LvClasses.DetectionDataGrid.ItemsSource = _annotationConfig.DetectionClasses;
Switcher.SelectedIndex = 1; Switcher.SelectedIndex = 1;
LvClasses.SelectNum(Math.Max(0, _tempSelectedClassIdx - 1)); LvClasses.SelectNum(Math.Max(0, _tempSelectedClassIdx - 1));
+2 -1
View File
@@ -35,6 +35,7 @@ public partial class App
private PythonResourceLoader _resourceLoader = null!; private PythonResourceLoader _resourceLoader = null!;
private Stream _securedConfig = null!; private Stream _securedConfig = null!;
private static readonly Guid KeyPressTaskId = Guid.NewGuid();
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{ {
@@ -199,7 +200,7 @@ public partial class App
{ {
var args = (KeyEventArgs)e; var args = (KeyEventArgs)e;
var keyEvent = new KeyEvent(sender, args, _formState.ActiveWindow); var keyEvent = new KeyEvent(sender, args, _formState.ActiveWindow);
_ = ThrottleExt.ThrottleRunFirst(() => _mediator.Publish(keyEvent), TimeSpan.FromMilliseconds(50)); _ = ThrottleExt.ThrottleRunFirst(() => _mediator.Publish(keyEvent), KeyPressTaskId, TimeSpan.FromMilliseconds(50));
} }
protected override async void OnExit(ExitEventArgs e) protected override async void OnExit(ExitEventArgs e)
+3 -2
View File
@@ -9,7 +9,6 @@ using Azaion.Common.DTO.Config;
using Azaion.Common.Extensions; using Azaion.Common.Extensions;
using Azaion.Common.Services; using Azaion.Common.Services;
using Azaion.CommonSecurity.Services; using Azaion.CommonSecurity.Services;
using Azaion.Dataset;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using SharpVectors.Converters; using SharpVectors.Converters;
@@ -26,6 +25,7 @@ public partial class MainSuite
private readonly IDbFactory _dbFactory; private readonly IDbFactory _dbFactory;
private readonly Dictionary<WindowEnum, Window> _openedWindows = new(); private readonly Dictionary<WindowEnum, Window> _openedWindows = new();
private readonly IResourceLoader _resourceLoader; private readonly IResourceLoader _resourceLoader;
private static readonly Guid SaveConfigTaskId = Guid.NewGuid();
public MainSuite(IOptions<AppConfig> appConfig, public MainSuite(IOptions<AppConfig> appConfig,
IConfigUpdater configUpdater, IConfigUpdater configUpdater,
@@ -89,6 +89,7 @@ public partial class MainSuite
}; };
lvItem.MouseUp += (lv, _) => OpenWindow((lv as ListViewItem)!); lvItem.MouseUp += (lv, _) => OpenWindow((lv as ListViewItem)!);
ListView.Items.Add(lvItem); ListView.Items.Add(lvItem);
_ = _sp.GetRequiredService(azaionModule.MainWindowType) as Window;
} }
_ = Task.Run(async () => await _galleryService.RefreshThumbnails()); _ = Task.Run(async () => await _galleryService.RefreshThumbnails());
@@ -126,7 +127,7 @@ public partial class MainSuite
{ {
_configUpdater.Save(_appConfig); _configUpdater.Save(_appConfig);
return Task.CompletedTask; return Task.CompletedTask;
}, TimeSpan.FromSeconds(2)); }, SaveConfigTaskId, TimeSpan.FromSeconds(2));
} }
private void OnFormClosed(object? sender, EventArgs e) private void OnFormClosed(object? sender, EventArgs e)
+6 -5
View File
@@ -3,7 +3,8 @@
"ZeroMqHost": "127.0.0.1", "ZeroMqHost": "127.0.0.1",
"ZeroMqPort": 5128, "ZeroMqPort": 5128,
"RetryCount": 25, "RetryCount": 25,
"TimeoutSeconds": 5 "TimeoutSeconds": 5,
"ResourcesFolder": "stage"
}, },
"DirectoriesConfig": { "DirectoriesConfig": {
"VideosDirectory": "E:\\Azaion6", "VideosDirectory": "E:\\Azaion6",
@@ -13,16 +14,16 @@
"ThumbnailsDirectory": "E:\\thumbnails" "ThumbnailsDirectory": "E:\\thumbnails"
}, },
"AnnotationConfig": { "AnnotationConfig": {
"AnnotationClasses": [ "DetectionClasses": [
{ "Id": 0, "Name": "Броньована техніка", "ShortName": "Бронь" }, { "Id": 0, "Name": "Броньована техніка", "ShortName": "Броня" },
{ "Id": 1, "Name": "Вантажівка", "ShortName": "Вантаж" }, { "Id": 1, "Name": "Вантажівка", "ShortName": "Вантаж." },
{ "Id": 2, "Name": "Машина легкова", "ShortName": "Машина" }, { "Id": 2, "Name": "Машина легкова", "ShortName": "Машина" },
{ "Id": 3, "Name": "Артилерія", "ShortName": "Арта" }, { "Id": 3, "Name": "Артилерія", "ShortName": "Арта" },
{ "Id": 4, "Name": "Тінь від техніки", "ShortName": "Тінь" }, { "Id": 4, "Name": "Тінь від техніки", "ShortName": "Тінь" },
{ "Id": 5, "Name": "Окопи", "ShortName": "Окопи" }, { "Id": 5, "Name": "Окопи", "ShortName": "Окопи" },
{ "Id": 6, "Name": "Військовий", "ShortName": "Військов" }, { "Id": 6, "Name": "Військовий", "ShortName": "Військов" },
{ "Id": 7, "Name": "Накати", "ShortName": "Накати" }, { "Id": 7, "Name": "Накати", "ShortName": "Накати" },
{ "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк захист" }, { "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк.захист" },
{ "Id": 9, "Name": "Дим", "ShortName": "Дим" }, { "Id": 9, "Name": "Дим", "ShortName": "Дим" },
{ "Id": 10, "Name": "Літак", "ShortName": "Літак" }, { "Id": 10, "Name": "Літак", "ShortName": "Літак" },
{ "Id": 11, "Name": "Мотоцикл", "ShortName": "Мото" } { "Id": 11, "Name": "Мотоцикл", "ShortName": "Мото" }
+6 -2
View File
@@ -1,6 +1,5 @@
@echo off @echo off
cd Azaion.Suite cd Azaion.Suite
echo Build .net app echo Build .net app
dotnet build -c Release dotnet build -c Release
@@ -17,7 +16,7 @@ move dist\Azaion.Annotator.dll dist\dummy\
move dist\Azaion.Dataset.dll dist\dummy\ move dist\Azaion.Dataset.dll dist\dummy\
echo Build Cython app echo Build Cython app
cd Azaion.Inference\ cd Azaion.Inference
call ".\venv\Scripts\activate.bat" call ".\venv\Scripts\activate.bat"
pyinstaller --onefile ^ pyinstaller --onefile ^
--collect-all jwt ^ --collect-all jwt ^
@@ -43,3 +42,8 @@ pyinstaller --onefile ^
--hidden-import remote_command_handler ^ --hidden-import remote_command_handler ^
start.py start.py
move dist\start.exe ..\dist\azaion-inference.exe move dist\start.exe ..\dist\azaion-inference.exe
copy config.yaml ..\dist
echo Copy ico
cd ..
copy logo.ico dist\