From 2236eb7fcbab3dda7fcd0bbd31054035967f54ec Mon Sep 17 00:00:00 2001 From: Alex Bezdieniezhnykh Date: Mon, 16 Sep 2024 20:12:05 +0300 Subject: [PATCH] lot of small fixes for dataset explorer --- Azaion.Annotator/DTO/PlaybackControlEnum.cs | 3 +- Azaion.Annotator/DTO/ThumbnailDto.cs | 26 +----- Azaion.Annotator/DatasetExplorer.xaml | 2 +- Azaion.Annotator/DatasetExplorer.xaml.cs | 92 ++++++++++++------- .../DatasetExplorerEventHandler.cs | 11 ++- .../Extensions/BitmapExtensions.cs | 19 ++++ 6 files changed, 94 insertions(+), 59 deletions(-) create mode 100644 Azaion.Annotator/Extensions/BitmapExtensions.cs diff --git a/Azaion.Annotator/DTO/PlaybackControlEnum.cs b/Azaion.Annotator/DTO/PlaybackControlEnum.cs index 21a2c99..7aa091f 100644 --- a/Azaion.Annotator/DTO/PlaybackControlEnum.cs +++ b/Azaion.Annotator/DTO/PlaybackControlEnum.cs @@ -14,5 +14,6 @@ public enum PlaybackControlEnum TurnOffVolume = 9, TurnOnVolume = 10, Previous = 11, - Next = 12 + Next = 12, + Close = 13 } \ No newline at end of file diff --git a/Azaion.Annotator/DTO/ThumbnailDto.cs b/Azaion.Annotator/DTO/ThumbnailDto.cs index 80b2330..822b15b 100644 --- a/Azaion.Annotator/DTO/ThumbnailDto.cs +++ b/Azaion.Annotator/DTO/ThumbnailDto.cs @@ -1,6 +1,7 @@ using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Media.Imaging; +using Azaion.Annotator.Extensions; namespace Azaion.Annotator.DTO; @@ -16,7 +17,7 @@ public class ThumbnailDto : INotifyPropertyChanged get { if (_image == null) - LoadImageAsync(); + Task.Run(async () => Image = await ThumbnailPath.OpenImage()); return _image; } set @@ -26,28 +27,7 @@ public class ThumbnailDto : INotifyPropertyChanged } } - private async void LoadImageAsync() - { - await Task.Run(() => - { - try - { - var bitmap = new BitmapImage(); - bitmap.BeginInit(); - bitmap.UriSource = new Uri(ThumbnailPath); - bitmap.CacheOption = BitmapCacheOption.OnLoad; - bitmap.DecodePixelWidth = 480; - bitmap.DecodePixelHeight = 270; - bitmap.EndInit(); - bitmap.Freeze(); // Freeze to make it cross-thread accessible - Image = bitmap; - } - catch (Exception e) - { - Console.WriteLine(e); - } - }); - } + public void UpdateImage() => _image = null; public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) diff --git a/Azaion.Annotator/DatasetExplorer.xaml b/Azaion.Annotator/DatasetExplorer.xaml index 8843055..d0febe5 100644 --- a/Azaion.Annotator/DatasetExplorer.xaml +++ b/Azaion.Annotator/DatasetExplorer.xaml @@ -103,7 +103,7 @@ - + diff --git a/Azaion.Annotator/DatasetExplorer.xaml.cs b/Azaion.Annotator/DatasetExplorer.xaml.cs index 2ac2db1..1136a86 100644 --- a/Azaion.Annotator/DatasetExplorer.xaml.cs +++ b/Azaion.Annotator/DatasetExplorer.xaml.cs @@ -23,25 +23,24 @@ public partial class DatasetExplorer private int _tempSelectedClassIdx = 0; private readonly string _thumbnailsCacheFile; - private IConfigRepository _configRepository; + private readonly IConfigRepository _configRepository; private readonly FormState _formState; - private readonly IGalleryManager _galleryManager; private static Dictionary> LabelsCache { get; set; } = new(); + public bool ThumbnailLoading { get; set; } + public ThumbnailDto? CurrentThumbnail { get; set; } public DatasetExplorer( Config config, ILogger logger, IConfigRepository configRepository, - FormState formState, - IGalleryManager galleryManager) + FormState formState) { _config = config; _logger = logger; _configRepository = configRepository; _formState = formState; - _galleryManager = galleryManager; _thumbnailsCacheFile = Path.Combine(config.ThumbnailsDirectory, Config.ThumbnailsCacheFile); if (File.Exists(_thumbnailsCacheFile)) { @@ -116,33 +115,12 @@ public partial class DatasetExplorer }; ThumbnailsView.MouseDoubleClick += async (_, _) => await EditAnnotation(); - Activated += (_, _) => { _formState.ActiveWindow = WindowsEnum.DatasetExplorer; }; - - ExplorerEditor.GetTimeFunc = () => _formState.GetTime(CurrentThumbnail!.ImagePath)!.Value; - } - - private async Task EditAnnotation() - { - if (ThumbnailsView.SelectedItem == null) - return; - - var dto = (ThumbnailsView.SelectedItem as ThumbnailDto)!; - ExplorerEditor.Background = new ImageBrush + ThumbnailsView.SelectionChanged += (_, _) => { - ImageSource = new BitmapImage(new Uri(dto.ImagePath)) + StatusText.Text = $"Обрано: {ThumbnailsView.SelectedItems.Count} | {ThumbnailsView.SelectedIndex} / {ThumbnailsDtos.Count}"; }; - CurrentThumbnail = dto; - Switcher.SelectedIndex = 1; - LvClasses.SelectedIndex = 1; - - var time = _formState.GetTime(dto.ImagePath)!.Value; - foreach (var ann in await YoloLabel.ReadFromFile(dto.LabelPath)) - { - var annClass = _config.AnnotationClasses[ann.ClassNumber]; - var annInfo = new CanvasLabel(ann, ExplorerEditor.RenderSize, ExplorerEditor.RenderSize); - Dispatcher.Invoke(() => ExplorerEditor.CreateAnnotation(annClass, time, annInfo)); - } + Activated += (_, _) => { _formState.ActiveWindow = WindowsEnum.DatasetExplorer; }; Switcher.SelectionChanged += (sender, args) => { @@ -157,8 +135,53 @@ public partial class DatasetExplorer //Explorer LvClasses.ItemsSource = AllAnnotationClasses; LvClasses.SelectedIndex = _tempSelectedClassIdx; + ExplorerEditor.Background = null; } }; + + ExplorerEditor.GetTimeFunc = () => _formState.GetTime(CurrentThumbnail!.ImagePath)!.Value; + } + + private async Task EditAnnotation() + { + try + { + ThumbnailLoading = true; + + if (ThumbnailsView.SelectedItem == null) + return; + + var dto = (ThumbnailsView.SelectedItem as ThumbnailDto)!; + CurrentThumbnail = dto; + ExplorerEditor.Background = new ImageBrush + { + ImageSource = await dto.ImagePath.OpenImage() + }; + + Switcher.SelectedIndex = 1; + LvClasses.SelectedIndex = 1; + + var time = _formState.GetTime(dto.ImagePath)!.Value; + ExplorerEditor.RemoveAllAnns(); + foreach (var ann in await YoloLabel.ReadFromFile(dto.LabelPath)) + { + var annClass = _config.AnnotationClasses[ann.ClassNumber]; + var annInfo = new CanvasLabel(ann, ExplorerEditor.RenderSize, ExplorerEditor.RenderSize); + ExplorerEditor.CreateAnnotation(annClass, time, annInfo); + } + + ThumbnailLoading = false; + } + catch (Exception e) + { + _logger.LogError(e, e.Message); + throw; + } + finally + { + ThumbnailLoading = false; + } + } private async Task SaveUserSettings() @@ -173,6 +196,7 @@ public partial class DatasetExplorer private void DeleteAnnotations() { + var tempSelected = ThumbnailsView.SelectedIndex; var result = MessageBox.Show("Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.YesNo, MessageBoxImage.Question); if (result != MessageBoxResult.Yes) return; @@ -186,6 +210,7 @@ public partial class DatasetExplorer File.Delete(dto.ThumbnailPath); ThumbnailsDtos.Remove(dto); } + ThumbnailsView.SelectedIndex = Math.Min(ThumbnailsDtos.Count, tempSelected); } private async Task ReloadThumbnails() @@ -212,11 +237,14 @@ public partial class DatasetExplorer { var name = Path.GetFileNameWithoutExtension(thumbnail)[..^Config.ThumbnailPrefix.Length]; var imageName = Path.Combine(_config.ImagesDirectory, name); - foreach (var imageFormat in _config.ImageFormats) + foreach (var f in _config.ImageFormats) { - imageName = $"{imageName}.{imageFormat}"; - if (File.Exists(imageName)) + var curName = $"{imageName}.{f}"; + if (File.Exists(curName)) + { + imageName = curName; break; + } } var labelPath = Path.Combine(_config.LabelsDirectory, $"{name}.txt"); diff --git a/Azaion.Annotator/DatasetExplorerEventHandler.cs b/Azaion.Annotator/DatasetExplorerEventHandler.cs index 7225e4d..8025293 100644 --- a/Azaion.Annotator/DatasetExplorerEventHandler.cs +++ b/Azaion.Annotator/DatasetExplorerEventHandler.cs @@ -14,7 +14,8 @@ public class DatasetExplorerEventHandler(DatasetExplorer datasetExplorer, { { Key.Enter, PlaybackControlEnum.SaveAnnotations }, { Key.Delete, PlaybackControlEnum.RemoveSelectedAnns }, - { Key.X, PlaybackControlEnum.RemoveAllAnns } + { Key.X, PlaybackControlEnum.RemoveAllAnns }, + { Key.Escape, PlaybackControlEnum.Close } }; public async Task Handle(KeyEvent keyEvent, CancellationToken cancellationToken) @@ -42,13 +43,16 @@ public class DatasetExplorerEventHandler(DatasetExplorer datasetExplorer, switch (controlEnum) { case PlaybackControlEnum.SaveAnnotations: + if (datasetExplorer.ThumbnailLoading) + return; + var currentAnns = datasetExplorer.ExplorerEditor.CurrentAnns .Select(x => new YoloLabel(x.Info, datasetExplorer.ExplorerEditor.RenderSize, datasetExplorer.ExplorerEditor.RenderSize)) .ToList(); await YoloLabel.WriteToFile(currentAnns, Path.Combine(config.LabelsDirectory, datasetExplorer.CurrentThumbnail!.LabelPath)); await galleryManager.CreateThumbnail(datasetExplorer.CurrentThumbnail.ImagePath); - + datasetExplorer.CurrentThumbnail.UpdateImage(); datasetExplorer.Switcher.SelectedIndex = 0; break; case PlaybackControlEnum.RemoveSelectedAnns: @@ -57,6 +61,9 @@ public class DatasetExplorerEventHandler(DatasetExplorer datasetExplorer, case PlaybackControlEnum.RemoveAllAnns: datasetExplorer.ExplorerEditor.RemoveAllAnns(); break; + case PlaybackControlEnum.Close: + datasetExplorer.Switcher.SelectedIndex = 0; + break; } } } diff --git a/Azaion.Annotator/Extensions/BitmapExtensions.cs b/Azaion.Annotator/Extensions/BitmapExtensions.cs new file mode 100644 index 0000000..5216731 --- /dev/null +++ b/Azaion.Annotator/Extensions/BitmapExtensions.cs @@ -0,0 +1,19 @@ +using System.IO; +using System.Windows.Media.Imaging; + +namespace Azaion.Annotator.Extensions; + +public static class BitmapExtensions +{ + public static async Task OpenImage(this string imagePath) + { + var image = new BitmapImage(); + await using var stream = File.OpenRead(imagePath); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + image.StreamSource = stream; + image.EndInit(); + image.Freeze(); + return image; + } +} \ No newline at end of file