remove fix, todo: test

This commit is contained in:
Alex Bezdieniezhnykh
2025-01-03 18:32:56 +02:00
parent 9aebfd787b
commit ae2c62350a
19 changed files with 353 additions and 245 deletions
+53 -6
View File
@@ -12,7 +12,7 @@
WindowState="Maximized">
<Window.Resources>
<DataTemplate x:Key="ThumbnailTemplate" DataType="{x:Type dto:AnnotationImageView}">
<DataTemplate x:Key="ThumbnailTemplate" DataType="{x:Type dto:AnnotationThumbnail}">
<Border BorderBrush="IndianRed" Padding="5">
<Border.Style>
<Style TargetType="Border">
@@ -123,11 +123,12 @@
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="2" Background="Black">
<StatusBarItem Grid.Column="0" Background="Black">
<Button Name="ValidateBtn"
Padding="2"
ToolTip="Підтвердити валідність. Клавіша: [A]"
Background="Black" BorderBrush="Black" Cursor="Hand"
ToolTip="Підтвердити валідність. Клавіша: [V]"
Background="Black" BorderBrush="Black"
Cursor="Hand"
Click="ValidateAnnotationsClick">
<StackPanel Orientation="Horizontal">
<Image>
@@ -148,8 +149,54 @@
</StackPanel>
</Button>
</StatusBarItem>
<Separator Grid.Column="4"/>
<StatusBarItem Grid.Column="5" Background="Black">
<Separator Grid.Column="1" />
<StatusBarItem x:Name="RefreshThumbnailsButtonItem" Grid.Column="2" Background="Black">
<Button
Padding="2"
Height="25"
ToolTip="Оновити базу іконок" Background="Black"
BorderBrush="Black"
Cursor="Hand"
Click="RefreshThumbnailsBtnClick">
<StackPanel Orientation="Horizontal">
<Image>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V1200 H1200 V0 H0 Z">
<GeometryDrawing Brush="LightGray" Geometry="M889.68 166.32c-93.608-102.216-228.154-166.32-377.68-166.32-282.77 0-512
229.23-512 512h96c0-229.75 186.25-416 416-416 123.020 0 233.542 53.418 309.696 138.306l-149.696 149.694h352v-352l-134.32 134.32z" />
<GeometryDrawing Brush="LightGray" Geometry="M928 512c0 229.75-186.25 416-416 416-123.020
0-233.542-53.418-309.694-138.306l149.694-149.694h-352v352l134.32-134.32c93.608 102.216 228.154 166.32 377.68 166.32 282.77 0 512-229.23 512-512h-96z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<TextBlock Foreground="White" Padding="8 0 0 0">Оновити базу іконок</TextBlock>
</StackPanel>
</Button>
</StatusBarItem>
<StatusBarItem Grid.Column="2" x:Name="RefreshProgressBarItem" Visibility="Hidden">
<StackPanel>
<TextBlock Name="RefreshThumbCaption" Padding="0 0 5 0">База іконок:</TextBlock>
<ProgressBar x:Name="RefreshThumbBar"
Width="150"
Height="15"
HorizontalAlignment="Stretch"
Background="#252525"
BorderBrush="#252525"
Foreground="LightBlue"
Maximum="100"
Minimum="0"
Value="0">
</ProgressBar>
</StackPanel>
</StatusBarItem>
<StatusBarItem Grid.Column="3" Background="Black">
<TextBlock Name="StatusText" Text=""/>
</StatusBarItem>
</StatusBar>
+75 -45
View File
@@ -2,12 +2,11 @@
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Azaion.Common;
using Azaion.Common.Database;
using Azaion.Common.DTO;
using Azaion.Common.DTO.Config;
using Azaion.Common.Events;
using Azaion.Common.Services;
using Azaion.CommonSecurity.Services;
using LinqToDB;
using MediatR;
using Microsoft.Extensions.Logging;
@@ -17,28 +16,28 @@ using Color = ScottPlot.Color;
namespace Azaion.Dataset;
public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEvent>
public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEvent>, INotificationHandler<AnnotationsDeletedEvent>
{
private readonly ILogger<DatasetExplorer> _logger;
private readonly AnnotationConfig _annotationConfig;
private readonly DirectoriesConfig _directoriesConfig;
private Dictionary<int, List<Annotation>> _annotationsDict;
private readonly CancellationTokenSource _cts = new();
public ObservableCollection<AnnotationImageView> SelectedAnnotations { get; set; } = new();
public ObservableCollection<DetectionClass> AllAnnotationClasses { get; set; } = new();
public ObservableCollection<DetectionClass> AllDetectionClasses { get; set; } = new();
public ObservableCollection<AnnotationThumbnail> SelectedAnnotations { get; set; } = new();
private Dictionary<string, LabelInfo> LabelsCache { get; set; } = new();
private int _tempSelectedClassIdx = 0;
private readonly IGalleryService _galleryService;
private readonly IDbFactory _dbFactory;
private readonly IMediator _mediator;
private readonly AzaionApiClient _apiClient;
private readonly Dictionary<string, AnnotationThumbnail> _selectedAnnotationDict = new();
public bool ThumbnailLoading { get; set; }
public AnnotationImageView? CurrentAnnotation { get; set; }
public AnnotationThumbnail? CurrentAnnotation { get; set; }
public DatasetExplorer(
IOptions<DirectoriesConfig> directoriesConfig,
@@ -47,8 +46,7 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
IGalleryService galleryService,
FormState formState,
IDbFactory dbFactory,
IMediator mediator,
AzaionApiClient apiClient)
IMediator mediator)
{
_directoriesConfig = directoriesConfig.Value;
_annotationConfig = annotationConfig.Value;
@@ -56,18 +54,17 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
_galleryService = galleryService;
_dbFactory = dbFactory;
_mediator = mediator;
_apiClient = apiClient;
InitializeComponent();
Loaded += OnLoaded;
Activated += (_, _) => formState.ActiveWindow = WindowEnum.DatasetExplorer;
ThumbnailsView.KeyDown += async (sender, args) =>
ThumbnailsView.KeyDown += async (sender, args) =>
{
switch (args.Key)
{
case Key.Delete:
DeleteAnnotations();
await DeleteAnnotations();
break;
case Key.Enter:
await EditAnnotation();
@@ -79,19 +76,24 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
ThumbnailsView.SelectionChanged += (_, _) =>
{
StatusText.Text = $"Обрано: {ThumbnailsView.SelectedItems.Count} | {ThumbnailsView.SelectedIndex} / {SelectedAnnotations.Count}";
ValidateBtn.Visibility = ThumbnailsView.SelectedItems.Cast<AnnotationImageView>().Any(x => x.IsSeed)
ValidateBtn.Visibility = ThumbnailsView.SelectedItems.Cast<AnnotationThumbnail>().Any(x => x.IsSeed)
? Visibility.Visible
: Visibility.Hidden;
};
ExplorerEditor.GetTimeFunc = () => Constants.GetTime(CurrentAnnotation!.Annotation.ImagePath);
ExplorerEditor.GetTimeFunc = () => CurrentAnnotation!.Annotation.Time;
_galleryService.ThumbnailsUpdate += thumbnailsPercentage =>
{
Dispatcher.Invoke(() => RefreshThumbBar.Value = thumbnailsPercentage);
};
Closing += (_, _) => _cts.Cancel();
}
private async void OnLoaded(object sender, RoutedEventArgs e)
{
AllAnnotationClasses = new ObservableCollection<DetectionClass>(
AllDetectionClasses = new ObservableCollection<DetectionClass>(
new List<DetectionClass> { new() {Id = -1, Name = "All", ShortName = "All"}}
.Concat(_annotationConfig.AnnotationClasses));
LvClasses.ItemsSource = AllAnnotationClasses;
LvClasses.ItemsSource = AllDetectionClasses;
LvClasses.MouseUp += async (_, _) =>
{
@@ -128,9 +130,10 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
{
var allAnnotations = await db.Annotations
.LoadWith(x => x.Detections)
.OrderByDescending(x => x.CreatedDate)
.OrderBy(x => x.AnnotationStatus)
.ThenByDescending(x => x.CreatedDate)
.ToListAsync();
_annotationsDict = AllAnnotationClasses.ToDictionary(x => x.Id, _ => new List<Annotation>());
_annotationsDict = AllDetectionClasses.ToDictionary(x => x.Id, _ => new List<Annotation>());
foreach (var annotation in allAnnotations)
AddAnnotationToDict(annotation);
@@ -150,15 +153,14 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
private async Task LoadClassDistribution()
{
var data = LabelsCache
.SelectMany(x => x.Value.Classes)
.GroupBy(x => x)
.Select(x => new
var data = _annotationsDict
.Where(x => x.Key != -1)
.Select(gr => new
{
x.Key,
_annotationConfig.DetectionClassesDict[x.Key].Name,
_annotationConfig.DetectionClassesDict[x.Key].Color,
ClassCount = x.Count()
gr.Key,
_annotationConfig.DetectionClassesDict[gr.Key].Name,
_annotationConfig.DetectionClassesDict[gr.Key].Color,
ClassCount = gr.Value.Count
})
.ToList();
@@ -191,14 +193,20 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
ClassDistribution.Refresh();
}
private void ReloadThumbnailsItemClick(object sender, RoutedEventArgs e)
private async void RefreshThumbnailsBtnClick(object sender, RoutedEventArgs e)
{
RefreshThumbnailsButtonItem.Visibility = Visibility.Hidden;
RefreshProgressBarItem.Visibility = Visibility.Visible;
var result = MessageBox.Show($"Видалити всі іконки і згенерувати нову базу іконок в {_directoriesConfig.ThumbnailsDirectory}?",
"Підтвердження оновлення іконок", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result != MessageBoxResult.Yes)
return;
_galleryService.ClearThumbnails();
_galleryService.RefreshThumbnails();
await _galleryService.ClearThumbnails();
await _galleryService.RefreshThumbnails();
RefreshProgressBarItem.Visibility = Visibility.Hidden;
RefreshThumbnailsButtonItem.Visibility = Visibility.Visible;
}
private async Task EditAnnotation()
@@ -210,7 +218,7 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
if (ThumbnailsView.SelectedItem == null)
return;
CurrentAnnotation = (ThumbnailsView.SelectedItem as AnnotationImageView)!;
CurrentAnnotation = (ThumbnailsView.SelectedItem as AnnotationThumbnail)!;
var ann = CurrentAnnotation.Annotation;
ExplorerEditor.Background = new ImageBrush
{
@@ -218,13 +226,13 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
};
SwitchTab(toEditor: true);
var time = Constants.GetTime(ann.ImagePath);
var time = ann.Time;
ExplorerEditor.RemoveAllAnns();
foreach (var deetection in ann.Detections)
{
var annClass = _annotationConfig.DetectionClassesDict[deetection.ClassNumber];
var canvasLabel = new CanvasLabel(deetection, ExplorerEditor.RenderSize, ExplorerEditor.RenderSize);
ExplorerEditor.CreateAnnotation(annClass, time, canvasLabel);
ExplorerEditor.CreateDetectionControl(annClass, time, canvasLabel);
}
ThumbnailLoading = false;
@@ -257,26 +265,23 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
{
AnnotationsTab.Visibility = Visibility.Visible;
EditorTab.Visibility = Visibility.Collapsed;
LvClasses.ItemsSource = AllAnnotationClasses;
LvClasses.ItemsSource = AllDetectionClasses;
LvClasses.SelectedIndex = _tempSelectedClassIdx;
Switcher.SelectedIndex = 0;
}
}
private void DeleteAnnotations()
private async Task DeleteAnnotations()
{
var tempSelected = ThumbnailsView.SelectedIndex;
var result = MessageBox.Show("Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result != MessageBoxResult.Yes)
return;
var selected = ThumbnailsView.SelectedItems.Count;
for (var i = 0; i < selected; i++)
{
var dto = (ThumbnailsView.SelectedItems[0] as AnnotationImageView)!;
dto.Delete();
SelectedAnnotations.Remove(dto);
}
var annotations = ThumbnailsView.SelectedItems.Cast<AnnotationThumbnail>().Select(x => x.Annotation)
.ToList();
await _mediator.Publish(new AnnotationsDeletedEvent(annotations));
ThumbnailsView.SelectedIndex = Math.Min(SelectedAnnotations.Count, tempSelected);
}
@@ -284,7 +289,11 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
{
SelectedAnnotations.Clear();
foreach (var ann in _annotationsDict[ExplorerEditor.CurrentAnnClass.Id])
SelectedAnnotations.Add(new AnnotationImageView(ann));
{
var annThumb = new AnnotationThumbnail(ann);
SelectedAnnotations.Add(annThumb);
_selectedAnnotationDict.Add(annThumb.Annotation.Name, annThumb);
}
}
public async Task Handle(AnnotationCreatedEvent notification, CancellationToken cancellationToken)
@@ -298,15 +307,36 @@ public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEve
AddAnnotationToDict(annotation);
if (annotation.Classes.Contains(selectedClass.Value))
{
SelectedAnnotations.Add(new AnnotationImageView(annotation));
var annThumb = new AnnotationThumbnail(annotation);
SelectedAnnotations.Add(annThumb);
_selectedAnnotationDict.Add(annThumb.Annotation.Name, annThumb);
}
}
public async Task Handle(AnnotationsDeletedEvent notification, CancellationToken cancellationToken)
{
var names = notification.Annotations.Select(x => x.Name).ToList();
var annThumbs = _selectedAnnotationDict
.Where(x => names.Contains(x.Key))
.Select(x => x.Value)
.ToList();
foreach (var annThumb in annThumbs)
{
SelectedAnnotations.Remove(annThumb);
_selectedAnnotationDict.Remove(annThumb.Annotation.Name);
}
}
private async void ValidateAnnotationsClick(object sender, RoutedEventArgs e)
{
var result = MessageBox.Show("Підтверджуєте валідність обраних аннотацій?","Підтвердження валідності", MessageBoxButton.OKCancel, MessageBoxImage.Question);
if (result != MessageBoxResult.OK)
return;
try
{
await _mediator.Publish(new DatasetExplorerControlEvent(PlaybackControlEnum.ValidateAnnotations));
await _mediator.Publish(new DatasetExplorerControlEvent(PlaybackControlEnum.ValidateAnnotations), _cts.Token);
}
catch (Exception ex)
{
@@ -2,6 +2,7 @@
using System.Windows.Input;
using Azaion.Common.DTO;
using Azaion.Common.DTO.Queue;
using Azaion.Common.Events;
using Azaion.Common.Services;
using MediatR;
@@ -19,7 +20,7 @@ public class DatasetExplorerEventHandler(
{ Key.Delete, PlaybackControlEnum.RemoveSelectedAnns },
{ Key.X, PlaybackControlEnum.RemoveAllAnns },
{ Key.Escape, PlaybackControlEnum.Close },
{ Key.A, PlaybackControlEnum.ValidateAnnotations}
{ Key.V, PlaybackControlEnum.ValidateAnnotations}
};
public async Task Handle(DatasetExplorerControlEvent notification, CancellationToken cancellationToken)
@@ -74,13 +75,11 @@ public class DatasetExplorerEventHandler(
datasetExplorer.SwitchTab(toEditor: false);
break;
case PlaybackControlEnum.ValidateAnnotations:
var annotations = datasetExplorer.ThumbnailsView.SelectedItems.Cast<AnnotationImageView>()
var annotations = datasetExplorer.ThumbnailsView.SelectedItems.Cast<AnnotationThumbnail>()
.Select(x => x.Annotation)
.ToList();
foreach (var annotation in annotations)
{
await annotationService.ValidateAnnotation(annotation, cancellationToken);
}
break;
}
}