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