mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 10:16:30 +00:00
switcher dataset explorer
lat lon -> geopoint correct location for gps if small keypoints number
This commit is contained in:
@@ -73,9 +73,27 @@
|
||||
<ColumnDefinition Width="4"/>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<controls:DetectionClasses x:Name="LvClasses"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0" />
|
||||
<Grid Name="LeftPane"
|
||||
ShowGridLines="False"
|
||||
Background="Black"
|
||||
HorizontalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
<RowDefinition Height="35"></RowDefinition>
|
||||
<RowDefinition Height="35"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<controls:DetectionClasses
|
||||
x:Name="LvClasses"
|
||||
Grid.Column="0"
|
||||
Grid.Row="0" />
|
||||
<CheckBox Grid.Row="1"
|
||||
Margin="10"
|
||||
Foreground="White"
|
||||
Name="ShowWithObjectsOnlyChBox"
|
||||
Click="ShowWithObjectsOnly_OnClick">
|
||||
Показувати лише анотації з об'єктами
|
||||
</CheckBox>
|
||||
</Grid>
|
||||
<TabControl
|
||||
Name="Switcher"
|
||||
Grid.Column="2"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using Azaion.Common.Database;
|
||||
@@ -18,60 +19,56 @@ namespace Azaion.Dataset;
|
||||
public partial class DatasetExplorer
|
||||
{
|
||||
private readonly ILogger<DatasetExplorer> _logger;
|
||||
private readonly AnnotationConfig _annotationConfig;
|
||||
private readonly DirectoriesConfig _directoriesConfig;
|
||||
private readonly AppConfig _appConfig;
|
||||
|
||||
private readonly Dictionary<int, Dictionary<string, Annotation>> _annotationsDict;
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
|
||||
public List<DetectionClass> AllDetectionClasses { get; set; }
|
||||
public ObservableCollection<AnnotationThumbnail> SelectedAnnotations { get; set; } = new();
|
||||
private List<DetectionClass> AllDetectionClasses { get; }
|
||||
public ObservableCollection<AnnotationThumbnail> SelectedAnnotations { get; } = new();
|
||||
public readonly Dictionary<string, AnnotationThumbnail> SelectedAnnotationDict = new();
|
||||
|
||||
private int _tempSelectedClassIdx = 0;
|
||||
private int _tempSelectedClassIdx;
|
||||
private readonly IGalleryService _galleryService;
|
||||
private readonly IDbFactory _dbFactory;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public readonly List<DetectionClass> AnnotationsClasses;
|
||||
private IAzaionApi _azaionApi;
|
||||
|
||||
private readonly IAzaionApi _azaionApi;
|
||||
private readonly IConfigUpdater _configUpdater;
|
||||
|
||||
public bool ThumbnailLoading { get; set; }
|
||||
|
||||
public AnnotationThumbnail? CurrentAnnotation { get; set; }
|
||||
|
||||
public DatasetExplorer(
|
||||
IOptions<DirectoriesConfig> directoriesConfig,
|
||||
IOptions<AnnotationConfig> annotationConfig,
|
||||
IOptions<AppConfig> appConfig,
|
||||
ILogger<DatasetExplorer> logger,
|
||||
IGalleryService galleryService,
|
||||
FormState formState,
|
||||
IDbFactory dbFactory,
|
||||
IMediator mediator,
|
||||
IAzaionApi azaionApi)
|
||||
IAzaionApi azaionApi,
|
||||
IConfigUpdater configUpdater)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_directoriesConfig = directoriesConfig.Value;
|
||||
_annotationConfig = annotationConfig.Value;
|
||||
_appConfig = appConfig.Value;
|
||||
_logger = logger;
|
||||
_galleryService = galleryService;
|
||||
_dbFactory = dbFactory;
|
||||
_mediator = mediator;
|
||||
_azaionApi = azaionApi;
|
||||
_configUpdater = configUpdater;
|
||||
|
||||
ShowWithObjectsOnlyChBox.IsChecked = _appConfig.UIConfig.ShowDatasetWithDetectionsOnly;
|
||||
var photoModes = Enum.GetValues(typeof(PhotoMode)).Cast<PhotoMode>().ToList();
|
||||
_annotationsDict = _annotationConfig.DetectionClasses.SelectMany(cls => photoModes.Select(mode => (int)mode + cls.Id))
|
||||
_annotationsDict = _appConfig.AnnotationConfig.DetectionClasses.SelectMany(cls => photoModes.Select(mode => (int)mode + cls.Id))
|
||||
.ToDictionary(x => x, _ => new Dictionary<string, Annotation>());
|
||||
_annotationsDict.Add(-1, []);
|
||||
|
||||
AnnotationsClasses = annotationConfig.Value.DetectionClasses;
|
||||
|
||||
Loaded += OnLoaded;
|
||||
Activated += (_, _) => formState.ActiveWindow = WindowEnum.DatasetExplorer;
|
||||
|
||||
ThumbnailsView.KeyDown += async (sender, args) =>
|
||||
ThumbnailsView.KeyDown += async (_, args) =>
|
||||
{
|
||||
switch (args.Key)
|
||||
{
|
||||
@@ -102,7 +99,7 @@ public partial class DatasetExplorer
|
||||
|
||||
AllDetectionClasses = new List<DetectionClass>(
|
||||
new List<DetectionClass> { new() {Id = -1, Name = "All", ShortName = "All"}}
|
||||
.Concat(_annotationConfig.DetectionClasses));
|
||||
.Concat(_appConfig.AnnotationConfig.DetectionClasses));
|
||||
LvClasses.Init(AllDetectionClasses);
|
||||
}
|
||||
|
||||
@@ -119,7 +116,7 @@ public partial class DatasetExplorer
|
||||
ann.DetectionClass = args.DetectionClass;
|
||||
};
|
||||
|
||||
ExplorerEditor.CurrentAnnClass = LvClasses.CurrentDetectionClass ?? _annotationConfig.DetectionClasses.First();
|
||||
ExplorerEditor.CurrentAnnClass = LvClasses.CurrentDetectionClass ?? _appConfig.AnnotationConfig.DetectionClasses.First();
|
||||
|
||||
var allAnnotations = await _dbFactory.Run(async db =>
|
||||
await db.Annotations.LoadWith(x => x.Detections)
|
||||
@@ -150,8 +147,8 @@ public partial class DatasetExplorer
|
||||
.OrderBy(x => x.Key)
|
||||
.Select(gr => new ClusterDistribution
|
||||
{
|
||||
Label = $"{_annotationConfig.DetectionClassesDict[gr.Key].UIName}: {gr.Value.Count}",
|
||||
Color = _annotationConfig.DetectionClassesDict[gr.Key].Color,
|
||||
Label = $"{_appConfig.AnnotationConfig.DetectionClassesDict[gr.Key].UIName}: {gr.Value.Count}",
|
||||
Color = _appConfig.AnnotationConfig.DetectionClassesDict[gr.Key].Color,
|
||||
ClassCount = gr.Value.Count
|
||||
})
|
||||
.Where(x => x.ClassCount > 0)
|
||||
@@ -173,7 +170,7 @@ public partial class DatasetExplorer
|
||||
RefreshThumbnailsButtonItem.Visibility = Visibility.Hidden;
|
||||
RefreshProgressBarItem.Visibility = Visibility.Visible;
|
||||
|
||||
var result = MessageBox.Show($"Видалити всі іконки та згенерувати нову базу іконок в {_directoriesConfig.ThumbnailsDirectory}?",
|
||||
var result = MessageBox.Show($"Видалити всі іконки та згенерувати нову базу іконок в {_appConfig.DirectoriesConfig.ThumbnailsDirectory}?",
|
||||
"Підтвердження оновлення іконок", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result != MessageBoxResult.Yes)
|
||||
return;
|
||||
@@ -204,7 +201,7 @@ public partial class DatasetExplorer
|
||||
|
||||
var time = ann.Time;
|
||||
ExplorerEditor.RemoveAllAnns();
|
||||
ExplorerEditor.CreateDetections(time, ann.Detections, _annotationConfig.DetectionClasses, ExplorerEditor.RenderSize);
|
||||
ExplorerEditor.CreateDetections(time, ann.Detections, _appConfig.AnnotationConfig.DetectionClasses, ExplorerEditor.RenderSize);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -229,7 +226,7 @@ public partial class DatasetExplorer
|
||||
AnnotationsTab.Visibility = Visibility.Collapsed;
|
||||
EditorTab.Visibility = Visibility.Visible;
|
||||
_tempSelectedClassIdx = LvClasses.CurrentClassNumber;
|
||||
LvClasses.DetectionDataGrid.ItemsSource = _annotationConfig.DetectionClasses;
|
||||
LvClasses.DetectionDataGrid.ItemsSource = _appConfig.AnnotationConfig.DetectionClasses;
|
||||
|
||||
Switcher.SelectedIndex = 1;
|
||||
LvClasses.SelectNum(Math.Max(0, _tempSelectedClassIdx - 1));
|
||||
@@ -259,16 +256,15 @@ public partial class DatasetExplorer
|
||||
|
||||
private async Task ReloadThumbnails()
|
||||
{
|
||||
var withDetectionsOnly = ShowWithObjectsOnlyChBox.IsChecked;
|
||||
SelectedAnnotations.Clear();
|
||||
SelectedAnnotationDict.Clear();
|
||||
var annThumbnails = _annotationsDict[ExplorerEditor.CurrentAnnClass.YoloId]
|
||||
.WhereIf(withDetectionsOnly, x => x.Value.Detections.Any())
|
||||
.Select(x => new AnnotationThumbnail(x.Value, _azaionApi.CurrentUser.Role.IsValidator()))
|
||||
.OrderBy(x => !x.IsSeed)
|
||||
.ThenByDescending(x =>x.Annotation.CreatedDate);
|
||||
|
||||
//var dict = annThumbnails.Take(20).ToDictionary(x => x.Annotation.Name, x => x.IsSeed);
|
||||
|
||||
|
||||
foreach (var thumb in annThumbnails)
|
||||
{
|
||||
SelectedAnnotations.Add(thumb);
|
||||
@@ -292,4 +288,11 @@ public partial class DatasetExplorer
|
||||
_logger.LogError(ex, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private async void ShowWithObjectsOnly_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_appConfig.UIConfig.ShowDatasetWithDetectionsOnly = (sender as CheckBox)?.IsChecked ?? false;
|
||||
_configUpdater.Save(_appConfig);
|
||||
await ReloadThumbnails();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,12 +31,12 @@ public class DatasetExplorerEventHandler(
|
||||
{ Key.V, PlaybackControlEnum.ValidateAnnotations},
|
||||
};
|
||||
|
||||
public async Task Handle(DatasetExplorerControlEvent notification, CancellationToken cancellationToken)
|
||||
public async Task Handle(DatasetExplorerControlEvent notification, CancellationToken token)
|
||||
{
|
||||
await HandleControl(notification.PlaybackControl, cancellationToken);
|
||||
await HandleControl(notification.PlaybackControl, token);
|
||||
}
|
||||
|
||||
public async Task Handle(KeyEvent keyEvent, CancellationToken cancellationToken)
|
||||
public async Task Handle(KeyEvent keyEvent, CancellationToken token)
|
||||
{
|
||||
if (keyEvent.WindowEnum != WindowEnum.DatasetExplorer)
|
||||
return;
|
||||
@@ -52,11 +52,11 @@ public class DatasetExplorerEventHandler(
|
||||
else
|
||||
{
|
||||
if (datasetExplorer.Switcher.SelectedIndex == 1 && _keysControlEnumDict.TryGetValue(key, out var value))
|
||||
await HandleControl(value, cancellationToken);
|
||||
await HandleControl(value, token);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleControl(PlaybackControlEnum controlEnum, CancellationToken cancellationToken = default)
|
||||
private async Task HandleControl(PlaybackControlEnum controlEnum, CancellationToken token = default)
|
||||
{
|
||||
switch (controlEnum)
|
||||
{
|
||||
@@ -70,7 +70,8 @@ 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, token: cancellationToken);
|
||||
var annotation = await annotationService.SaveAnnotation(a.OriginalMediaName, a.Time, detections, token: token);
|
||||
await ValidateAnnotations([annotation], token);
|
||||
await datasetExplorer.EditAnnotation(index + 1);
|
||||
break;
|
||||
case PlaybackControlEnum.RemoveSelectedAnns:
|
||||
@@ -98,19 +99,24 @@ public class DatasetExplorerEventHandler(
|
||||
var annotations = datasetExplorer.ThumbnailsView.SelectedItems.Cast<AnnotationThumbnail>()
|
||||
.Select(x => x.Annotation)
|
||||
.ToList();
|
||||
await annotationService.ValidateAnnotations(annotations.Select(x => x.Name).ToList(), token: cancellationToken);
|
||||
foreach (var ann in datasetExplorer.SelectedAnnotations.Where(x => annotations.Contains(x.Annotation)))
|
||||
{
|
||||
ann.Annotation.AnnotationStatus = AnnotationStatus.Validated;
|
||||
if (datasetExplorer.SelectedAnnotationDict.TryGetValue(ann.Annotation.Name, out var value))
|
||||
value.Annotation.AnnotationStatus = AnnotationStatus.Validated;
|
||||
ann.UpdateUI();
|
||||
}
|
||||
await ValidateAnnotations(annotations, token);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public Task Handle(AnnotationCreatedEvent notification, CancellationToken cancellationToken)
|
||||
private async Task ValidateAnnotations(List<Annotation> annotations, CancellationToken token = default)
|
||||
{
|
||||
await annotationService.ValidateAnnotations(annotations.Select(x => x.Name).ToList(), token: token);
|
||||
foreach (var ann in datasetExplorer.SelectedAnnotations.Where(x => annotations.Contains(x.Annotation)))
|
||||
{
|
||||
ann.Annotation.AnnotationStatus = AnnotationStatus.Validated;
|
||||
if (datasetExplorer.SelectedAnnotationDict.TryGetValue(ann.Annotation.Name, out var value))
|
||||
value.Annotation.AnnotationStatus = AnnotationStatus.Validated;
|
||||
ann.UpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
public Task Handle(AnnotationCreatedEvent notification, CancellationToken token)
|
||||
{
|
||||
datasetExplorer.Dispatcher.Invoke(() =>
|
||||
{
|
||||
@@ -140,7 +146,7 @@ public class DatasetExplorerEventHandler(
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task Handle(AnnotationsDeletedEvent notification, CancellationToken cancellationToken)
|
||||
public async Task Handle(AnnotationsDeletedEvent notification, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user