add db WIP 2, 80%

refactor, renames
This commit is contained in:
Alex Bezdieniezhnykh
2024-12-24 06:07:13 +02:00
parent 5fa18aa514
commit 48c9ccbfda
32 changed files with 499 additions and 459 deletions
+84 -125
View File
@@ -4,8 +4,12 @@ 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.Services;
using LinqToDB;
using MediatR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using ScottPlot;
@@ -13,33 +17,40 @@ using Color = ScottPlot.Color;
namespace Azaion.Dataset;
public partial class DatasetExplorer
public partial class DatasetExplorer : INotificationHandler<AnnotationCreatedEvent>
{
private readonly ILogger<DatasetExplorer> _logger;
private readonly AnnotationConfig _annotationConfig;
private readonly DirectoriesConfig _directoriesConfig;
public ObservableCollection<ThumbnailDto> ThumbnailsDtos { get; set; } = new();
private ObservableCollection<AnnotationClass> AllAnnotationClasses { get; set; } = new();
private Dictionary<int, List<Annotation>> _annotationsDict;
public ObservableCollection<AnnotationImageView> SelectedAnnotations { get; set; } = new();
private ObservableCollection<DetectionClass> AllAnnotationClasses { get; set; } = new();
public Dictionary<string, LabelInfo> LabelsCache { get; set; } = new();
private int _tempSelectedClassIdx = 0;
private readonly IGalleryManager _galleryManager;
private readonly IGalleryService _galleryService;
private readonly IDbFactory _dbFactory;
public bool ThumbnailLoading { get; set; }
public ThumbnailDto? CurrentThumbnail { get; set; }
public AnnotationImageView? CurrentAnnotation { get; set; }
public DatasetExplorer(
IOptions<DirectoriesConfig> directoriesConfig,
IOptions<AnnotationConfig> annotationConfig,
ILogger<DatasetExplorer> logger,
IGalleryManager galleryManager,
FormState formState)
IGalleryService galleryService,
FormState formState,
IDbFactory dbFactory)
{
_directoriesConfig = directoriesConfig.Value;
_annotationConfig = annotationConfig.Value;
_logger = logger;
_galleryManager = galleryManager;
_galleryService = galleryService;
_dbFactory = dbFactory;
InitializeComponent();
Loaded += OnLoaded;
@@ -61,11 +72,11 @@ public partial class DatasetExplorer
ThumbnailsView.SelectionChanged += (_, _) =>
{
StatusText.Text = $"Обрано: {ThumbnailsView.SelectedItems.Count} | {ThumbnailsView.SelectedIndex} / {ThumbnailsDtos.Count}";
StatusText.Text = $"Обрано: {ThumbnailsView.SelectedItems.Count} | {ThumbnailsView.SelectedIndex} / {SelectedAnnotations.Count}";
};
ExplorerEditor.GetTimeFunc = () => Constants.GetTime(CurrentThumbnail!.ImagePath);
galleryManager.ThumbnailsUpdate += thumbnailsPercentage =>
ExplorerEditor.GetTimeFunc = () => Constants.GetTime(CurrentAnnotation!.Annotation.ImagePath);
galleryService.ThumbnailsUpdate += thumbnailsPercentage =>
{
Dispatcher.Invoke(() => RefreshThumbBar.Value = thumbnailsPercentage);
};
@@ -74,24 +85,22 @@ public partial class DatasetExplorer
private async void OnLoaded(object sender, RoutedEventArgs e)
{
_ = Task.Run(async () => await _galleryManager.RefreshThumbnails());
AllAnnotationClasses = new ObservableCollection<AnnotationClass>(
new List<AnnotationClass> { new() {Id = -1, Name = "All", ShortName = "All"}}
AllAnnotationClasses = new ObservableCollection<DetectionClass>(
new List<DetectionClass> { new() {Id = -1, Name = "All", ShortName = "All"}}
.Concat(_annotationConfig.AnnotationClasses));
LvClasses.ItemsSource = AllAnnotationClasses;
LvClasses.MouseUp += async (_, _) =>
{
var selectedClass = (AnnotationClass)LvClasses.SelectedItem;
var selectedClass = (DetectionClass)LvClasses.SelectedItem;
ExplorerEditor.CurrentAnnClass = selectedClass;
_annotationConfig.LastSelectedExplorerClass = selectedClass.Id;
if (Switcher.SelectedIndex == 0)
await ReloadThumbnails();
else
foreach (var ann in ExplorerEditor.CurrentAnns.Where(x => x.IsSelected))
ann.AnnotationClass = selectedClass;
foreach (var ann in ExplorerEditor.CurrentDetections.Where(x => x.IsSelected))
ann.DetectionClass = selectedClass;
};
LvClasses.SelectionChanged += (_, _) =>
@@ -99,35 +108,54 @@ public partial class DatasetExplorer
if (Switcher.SelectedIndex != 1)
return;
var selectedClass = (AnnotationClass)LvClasses.SelectedItem;
var selectedClass = (DetectionClass)LvClasses.SelectedItem;
if (selectedClass == null)
return;
ExplorerEditor.CurrentAnnClass = selectedClass;
foreach (var ann in ExplorerEditor.CurrentAnns.Where(x => x.IsSelected))
ann.AnnotationClass = selectedClass;
foreach (var ann in ExplorerEditor.CurrentDetections.Where(x => x.IsSelected))
ann.DetectionClass = selectedClass;
};
LvClasses.SelectedIndex = _annotationConfig.LastSelectedExplorerClass ?? 0;
ExplorerEditor.CurrentAnnClass = (AnnotationClass)LvClasses.SelectedItem;
await ReloadThumbnails();
LoadClassDistribution();
ExplorerEditor.CurrentAnnClass = (DetectionClass)LvClasses.SelectedItem;
RefreshThumbBar.Value = _galleryManager.ThumbnailsPercentage;
await _dbFactory.Run(async db =>
{
var allAnnotations = await db.Annotations
.LoadWith(x => x.Detections)
.OrderByDescending(x => x.CreatedDate)
.ToListAsync();
_annotationsDict = AllAnnotationClasses.ToDictionary(x => x.Id, _ => new List<Annotation>());
foreach (var annotation in allAnnotations)
AddAnnotationToDict(annotation);
});
await ReloadThumbnails();
await LoadClassDistribution();
RefreshThumbBar.Value = _galleryService.ProcessedThumbnailsPercentage;
DataContext = this;
}
private void LoadClassDistribution()
private void AddAnnotationToDict(Annotation annotation)
{
var data = _galleryManager.LabelsCache
foreach (var c in annotation.Classes)
_annotationsDict[c].Add(annotation);
_annotationsDict[-1].Add(annotation);
}
private async Task LoadClassDistribution()
{
var data = LabelsCache
.SelectMany(x => x.Value.Classes)
.GroupBy(x => x)
.Select(x => new
{
x.Key,
_annotationConfig.AnnotationClassesDict[x.Key].Name,
_annotationConfig.AnnotationClassesDict[x.Key].Color,
_annotationConfig.DetectionClassesDict[x.Key].Name,
_annotationConfig.DetectionClassesDict[x.Key].Color,
ClassCount = x.Count()
})
.ToList();
@@ -167,8 +195,8 @@ public partial class DatasetExplorer
"Підтвердження оновлення іконок", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result != MessageBoxResult.Yes)
return;
_galleryManager.ClearThumbnails();
_galleryManager.RefreshThumbnails();
_galleryService.ClearThumbnails();
_galleryService.RefreshThumbnails();
}
private async Task EditAnnotation()
@@ -180,20 +208,20 @@ public partial class DatasetExplorer
if (ThumbnailsView.SelectedItem == null)
return;
var dto = (ThumbnailsView.SelectedItem as ThumbnailDto)!;
CurrentThumbnail = dto;
CurrentAnnotation = (ThumbnailsView.SelectedItem as AnnotationImageView)!;
var ann = CurrentAnnotation.Annotation;
ExplorerEditor.Background = new ImageBrush
{
ImageSource = await dto.ImagePath.OpenImage()
ImageSource = await ann.ImagePath.OpenImage()
};
SwitchTab(toEditor: true);
var time = Constants.GetTime(dto.ImagePath);
var time = Constants.GetTime(ann.ImagePath);
ExplorerEditor.RemoveAllAnns();
foreach (var ann in await YoloLabel.ReadFromFile(dto.LabelPath))
foreach (var deetection in ann.Detections)
{
var annClass = _annotationConfig.AnnotationClassesDict[ann.ClassNumber];
var canvasLabel = new CanvasLabel(ann, ExplorerEditor.RenderSize, ExplorerEditor.RenderSize);
var annClass = _annotationConfig.DetectionClassesDict[deetection.ClassNumber];
var canvasLabel = new CanvasLabel(deetection, ExplorerEditor.RenderSize, ExplorerEditor.RenderSize);
ExplorerEditor.CreateAnnotation(annClass, time, canvasLabel);
}
@@ -243,101 +271,32 @@ public partial class DatasetExplorer
var selected = ThumbnailsView.SelectedItems.Count;
for (var i = 0; i < selected; i++)
{
var dto = (ThumbnailsView.SelectedItems[0] as ThumbnailDto)!;
File.Delete(dto.ImagePath);
File.Delete(dto.LabelPath);
File.Delete(dto.ThumbnailPath);
ThumbnailsDtos.Remove(dto);
var dto = (ThumbnailsView.SelectedItems[0] as AnnotationImageView)!;
dto.Delete();
SelectedAnnotations.Remove(dto);
}
ThumbnailsView.SelectedIndex = Math.Min(ThumbnailsDtos.Count, tempSelected);
ThumbnailsView.SelectedIndex = Math.Min(SelectedAnnotations.Count, tempSelected);
}
private async Task ReloadThumbnails()
{
LoadingAnnsCaption.Visibility = Visibility.Visible;
LoadingAnnsBar.Visibility = Visibility.Visible;
SelectedAnnotations.Clear();
foreach (var ann in _annotationsDict[ExplorerEditor.CurrentAnnClass.Id])
SelectedAnnotations.Add(new AnnotationImageView(ann));
}
if (!Directory.Exists(_directoriesConfig.ThumbnailsDirectory))
private void AddThumbnail(Annotation annotation)
{
var selectedClass = ((DetectionClass?)LvClasses.SelectedItem)?.Id;
if (selectedClass == null)
return;
var thumbnails = Directory.GetFiles(_directoriesConfig.ThumbnailsDirectory, "*.jpg");
var thumbnailDtos = new List<ThumbnailDto>();
for (int i = 0; i < thumbnails.Length; i++)
{
var thumbnailDto = await GetThumbnail(thumbnails[i]);
if (thumbnailDto != null)
thumbnailDtos.Add(thumbnailDto);
if (i % 1000 == 0)
LoadingAnnsBar.Value = i * 100.0 / thumbnails.Length;
}
ThumbnailsDtos.Clear();
foreach (var th in thumbnailDtos.OrderByDescending(x => x.ImageDate))
ThumbnailsDtos.Add(th);
LoadingAnnsCaption.Visibility = Visibility.Collapsed;
LoadingAnnsBar.Visibility = Visibility.Collapsed;
AddAnnotationToDict(annotation);
if (annotation.Classes.Contains(selectedClass.Value))
SelectedAnnotations.Add(new AnnotationImageView(annotation));
}
private async Task<ThumbnailDto?> GetThumbnail(string thumbnail)
{
try
{
var name = Path.GetFileNameWithoutExtension(thumbnail)[..^Constants.THUMBNAIL_PREFIX.Length];
var imagePath = Path.Combine(_directoriesConfig.ImagesDirectory, name);
var labelPath = Path.Combine(_directoriesConfig.LabelsDirectory, $"{name}.txt");
foreach (var f in _annotationConfig.ImageFormats)
{
var curName = $"{imagePath}.{f}";
if (File.Exists(curName))
{
imagePath = curName;
break;
}
}
if (!_galleryManager.LabelsCache.TryGetValue(Path.GetFileName(imagePath), out var info))
{
if (!File.Exists(imagePath) || !File.Exists(labelPath))
{
File.Delete(thumbnail);
_logger.LogError($"No label {labelPath} found ! Image {imagePath} not found, thumbnail {thumbnail} was removed");
return null;
}
var classes = (await YoloLabel.ReadFromFile(labelPath))
.Select(x => x.ClassNumber)
.Distinct()
.ToList();
info = _galleryManager.AddToCache(imagePath, classes);
}
if (!info.Classes.Contains(ExplorerEditor.CurrentAnnClass.Id) && ExplorerEditor.CurrentAnnClass.Id != -1)
return null;
return new ThumbnailDto
{
ThumbnailPath = thumbnail,
ImagePath = imagePath,
LabelPath = labelPath,
ImageDate = info.ImageDateTime
};
}
catch (Exception e)
{
_logger.LogError(e, e.Message);
return null;
}
}
public void AddThumbnail(ThumbnailDto thumbnailDto, IEnumerable<int> classes)
{
var selectedClass = ((AnnotationClass?)LvClasses.SelectedItem)?.Id;
if (selectedClass != null && (selectedClass == -1 || classes.Any(x => x == selectedClass)))
ThumbnailsDtos.Insert(0, thumbnailDto);
}
public async Task Handle(AnnotationCreatedEvent notification, CancellationToken cancellationToken) =>
AddThumbnail(notification.Annotation);
}