lot of small fixes for dataset explorer

This commit is contained in:
Alex Bezdieniezhnykh
2024-09-16 20:12:05 +03:00
parent 42fdee599e
commit 2236eb7fcb
6 changed files with 94 additions and 59 deletions
+2 -1
View File
@@ -14,5 +14,6 @@ public enum PlaybackControlEnum
TurnOffVolume = 9, TurnOffVolume = 9,
TurnOnVolume = 10, TurnOnVolume = 10,
Previous = 11, Previous = 11,
Next = 12 Next = 12,
Close = 13
} }
+3 -23
View File
@@ -1,6 +1,7 @@
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Azaion.Annotator.Extensions;
namespace Azaion.Annotator.DTO; namespace Azaion.Annotator.DTO;
@@ -16,7 +17,7 @@ public class ThumbnailDto : INotifyPropertyChanged
get get
{ {
if (_image == null) if (_image == null)
LoadImageAsync(); Task.Run(async () => Image = await ThumbnailPath.OpenImage());
return _image; return _image;
} }
set set
@@ -26,28 +27,7 @@ public class ThumbnailDto : INotifyPropertyChanged
} }
} }
private async void LoadImageAsync() public void UpdateImage() => _image = null;
{
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 event PropertyChangedEventHandler? PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
+1 -1
View File
@@ -103,7 +103,7 @@
</StatusBarItem> </StatusBarItem>
<Separator Grid.Column="2"/> <Separator Grid.Column="2"/>
<StatusBarItem Grid.Column="3" Background="Black"> <StatusBarItem Grid.Column="3" Background="Black">
<TextBlock Text="{Binding AnnotationCount}" /> <TextBlock Name="StatusText" Text="Loading..."/>
</StatusBarItem> </StatusBarItem>
</StatusBar> </StatusBar>
</Grid> </Grid>
+60 -32
View File
@@ -23,25 +23,24 @@ public partial class DatasetExplorer
private int _tempSelectedClassIdx = 0; private int _tempSelectedClassIdx = 0;
private readonly string _thumbnailsCacheFile; private readonly string _thumbnailsCacheFile;
private IConfigRepository _configRepository; private readonly IConfigRepository _configRepository;
private readonly FormState _formState; private readonly FormState _formState;
private readonly IGalleryManager _galleryManager;
private static Dictionary<string, List<int>> LabelsCache { get; set; } = new(); private static Dictionary<string, List<int>> LabelsCache { get; set; } = new();
public bool ThumbnailLoading { get; set; }
public ThumbnailDto? CurrentThumbnail { get; set; } public ThumbnailDto? CurrentThumbnail { get; set; }
public DatasetExplorer( public DatasetExplorer(
Config config, Config config,
ILogger<DatasetExplorer> logger, ILogger<DatasetExplorer> logger,
IConfigRepository configRepository, IConfigRepository configRepository,
FormState formState, FormState formState)
IGalleryManager galleryManager)
{ {
_config = config; _config = config;
_logger = logger; _logger = logger;
_configRepository = configRepository; _configRepository = configRepository;
_formState = formState; _formState = formState;
_galleryManager = galleryManager;
_thumbnailsCacheFile = Path.Combine(config.ThumbnailsDirectory, Config.ThumbnailsCacheFile); _thumbnailsCacheFile = Path.Combine(config.ThumbnailsDirectory, Config.ThumbnailsCacheFile);
if (File.Exists(_thumbnailsCacheFile)) if (File.Exists(_thumbnailsCacheFile))
{ {
@@ -116,33 +115,12 @@ public partial class DatasetExplorer
}; };
ThumbnailsView.MouseDoubleClick += async (_, _) => await EditAnnotation(); ThumbnailsView.MouseDoubleClick += async (_, _) => await EditAnnotation();
Activated += (_, _) => { _formState.ActiveWindow = WindowsEnum.DatasetExplorer; }; ThumbnailsView.SelectionChanged += (_, _) =>
ExplorerEditor.GetTimeFunc = () => _formState.GetTime(CurrentThumbnail!.ImagePath)!.Value;
}
private async Task EditAnnotation()
{ {
if (ThumbnailsView.SelectedItem == null) StatusText.Text = $"Обрано: {ThumbnailsView.SelectedItems.Count} | {ThumbnailsView.SelectedIndex} / {ThumbnailsDtos.Count}";
return;
var dto = (ThumbnailsView.SelectedItem as ThumbnailDto)!;
ExplorerEditor.Background = new ImageBrush
{
ImageSource = new BitmapImage(new Uri(dto.ImagePath))
}; };
CurrentThumbnail = dto;
Switcher.SelectedIndex = 1; Activated += (_, _) => { _formState.ActiveWindow = WindowsEnum.DatasetExplorer; };
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));
}
Switcher.SelectionChanged += (sender, args) => Switcher.SelectionChanged += (sender, args) =>
{ {
@@ -157,8 +135,53 @@ public partial class DatasetExplorer
//Explorer //Explorer
LvClasses.ItemsSource = AllAnnotationClasses; LvClasses.ItemsSource = AllAnnotationClasses;
LvClasses.SelectedIndex = _tempSelectedClassIdx; 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() private async Task SaveUserSettings()
@@ -173,6 +196,7 @@ public partial class DatasetExplorer
private void DeleteAnnotations() private void DeleteAnnotations()
{ {
var tempSelected = ThumbnailsView.SelectedIndex;
var result = MessageBox.Show("Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.YesNo, MessageBoxImage.Question); var result = MessageBox.Show("Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result != MessageBoxResult.Yes) if (result != MessageBoxResult.Yes)
return; return;
@@ -186,6 +210,7 @@ public partial class DatasetExplorer
File.Delete(dto.ThumbnailPath); File.Delete(dto.ThumbnailPath);
ThumbnailsDtos.Remove(dto); ThumbnailsDtos.Remove(dto);
} }
ThumbnailsView.SelectedIndex = Math.Min(ThumbnailsDtos.Count, tempSelected);
} }
private async Task ReloadThumbnails() private async Task ReloadThumbnails()
@@ -212,12 +237,15 @@ public partial class DatasetExplorer
{ {
var name = Path.GetFileNameWithoutExtension(thumbnail)[..^Config.ThumbnailPrefix.Length]; var name = Path.GetFileNameWithoutExtension(thumbnail)[..^Config.ThumbnailPrefix.Length];
var imageName = Path.Combine(_config.ImagesDirectory, name); var imageName = Path.Combine(_config.ImagesDirectory, name);
foreach (var imageFormat in _config.ImageFormats) foreach (var f in _config.ImageFormats)
{ {
imageName = $"{imageName}.{imageFormat}"; var curName = $"{imageName}.{f}";
if (File.Exists(imageName)) if (File.Exists(curName))
{
imageName = curName;
break; break;
} }
}
var labelPath = Path.Combine(_config.LabelsDirectory, $"{name}.txt"); var labelPath = Path.Combine(_config.LabelsDirectory, $"{name}.txt");
@@ -14,7 +14,8 @@ public class DatasetExplorerEventHandler(DatasetExplorer datasetExplorer,
{ {
{ Key.Enter, PlaybackControlEnum.SaveAnnotations }, { Key.Enter, PlaybackControlEnum.SaveAnnotations },
{ Key.Delete, PlaybackControlEnum.RemoveSelectedAnns }, { Key.Delete, PlaybackControlEnum.RemoveSelectedAnns },
{ Key.X, PlaybackControlEnum.RemoveAllAnns } { Key.X, PlaybackControlEnum.RemoveAllAnns },
{ Key.Escape, PlaybackControlEnum.Close }
}; };
public async Task Handle(KeyEvent keyEvent, CancellationToken cancellationToken) public async Task Handle(KeyEvent keyEvent, CancellationToken cancellationToken)
@@ -42,13 +43,16 @@ public class DatasetExplorerEventHandler(DatasetExplorer datasetExplorer,
switch (controlEnum) switch (controlEnum)
{ {
case PlaybackControlEnum.SaveAnnotations: case PlaybackControlEnum.SaveAnnotations:
if (datasetExplorer.ThumbnailLoading)
return;
var currentAnns = datasetExplorer.ExplorerEditor.CurrentAnns var currentAnns = datasetExplorer.ExplorerEditor.CurrentAnns
.Select(x => new YoloLabel(x.Info, datasetExplorer.ExplorerEditor.RenderSize, datasetExplorer.ExplorerEditor.RenderSize)) .Select(x => new YoloLabel(x.Info, datasetExplorer.ExplorerEditor.RenderSize, datasetExplorer.ExplorerEditor.RenderSize))
.ToList(); .ToList();
await YoloLabel.WriteToFile(currentAnns, Path.Combine(config.LabelsDirectory, datasetExplorer.CurrentThumbnail!.LabelPath)); await YoloLabel.WriteToFile(currentAnns, Path.Combine(config.LabelsDirectory, datasetExplorer.CurrentThumbnail!.LabelPath));
await galleryManager.CreateThumbnail(datasetExplorer.CurrentThumbnail.ImagePath); await galleryManager.CreateThumbnail(datasetExplorer.CurrentThumbnail.ImagePath);
datasetExplorer.CurrentThumbnail.UpdateImage();
datasetExplorer.Switcher.SelectedIndex = 0; datasetExplorer.Switcher.SelectedIndex = 0;
break; break;
case PlaybackControlEnum.RemoveSelectedAnns: case PlaybackControlEnum.RemoveSelectedAnns:
@@ -57,6 +61,9 @@ public class DatasetExplorerEventHandler(DatasetExplorer datasetExplorer,
case PlaybackControlEnum.RemoveAllAnns: case PlaybackControlEnum.RemoveAllAnns:
datasetExplorer.ExplorerEditor.RemoveAllAnns(); datasetExplorer.ExplorerEditor.RemoveAllAnns();
break; break;
case PlaybackControlEnum.Close:
datasetExplorer.Switcher.SelectedIndex = 0;
break;
} }
} }
} }
@@ -0,0 +1,19 @@
using System.IO;
using System.Windows.Media.Imaging;
namespace Azaion.Annotator.Extensions;
public static class BitmapExtensions
{
public static async Task<BitmapImage> 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;
}
}