mirror of
https://github.com/azaion/annotations.git
synced 2026-04-23 00:06:31 +00:00
sort thumbnails by date in DatasetExplorer
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
using System.Drawing;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using Azaion.Annotator.DTO;
|
||||
using Azaion.Annotator.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Color = System.Drawing.Color;
|
||||
using ParallelOptions = Azaion.Annotator.Extensions.ParallelOptions;
|
||||
using Size = System.Windows.Size;
|
||||
@@ -13,15 +15,21 @@ namespace Azaion.Annotator;
|
||||
|
||||
public delegate void ThumbnailsUpdatedEventHandler(double thumbnailsPercentage);
|
||||
|
||||
public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGalleryManager
|
||||
public class GalleryManager : IGalleryManager
|
||||
{
|
||||
private readonly ILogger<GalleryManager> _logger;
|
||||
|
||||
public event ThumbnailsUpdatedEventHandler ThumbnailsUpdate;
|
||||
private readonly string _thumbnailsCacheFile;
|
||||
|
||||
private readonly SemaphoreSlim _updateLock = new(1);
|
||||
|
||||
public double ThumbnailsPercentage { get; set; }
|
||||
public ConcurrentDictionary<string, LabelInfo> LabelsCache { get; set; } = new();
|
||||
|
||||
private DirectoryInfo? _thumbnailsDirectory;
|
||||
private readonly Config _config;
|
||||
|
||||
private DirectoryInfo ThumbnailsDirectory
|
||||
{
|
||||
get
|
||||
@@ -29,17 +37,24 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
|
||||
if (_thumbnailsDirectory != null)
|
||||
return _thumbnailsDirectory;
|
||||
|
||||
var dir = new DirectoryInfo(config.ThumbnailsDirectory);
|
||||
var dir = new DirectoryInfo(_config.ThumbnailsDirectory);
|
||||
if (!dir.Exists)
|
||||
Directory.CreateDirectory(config.ThumbnailsDirectory);
|
||||
_thumbnailsDirectory = new DirectoryInfo(config.ThumbnailsDirectory);
|
||||
Directory.CreateDirectory(_config.ThumbnailsDirectory);
|
||||
_thumbnailsDirectory = new DirectoryInfo(_config.ThumbnailsDirectory);
|
||||
return _thumbnailsDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
public GalleryManager(Config config, ILogger<GalleryManager> logger)
|
||||
{
|
||||
_config = config;
|
||||
_logger = logger;
|
||||
_thumbnailsCacheFile = Path.Combine(config.ThumbnailsDirectory, Config.ThumbnailsCacheFile);
|
||||
}
|
||||
|
||||
public void ClearThumbnails()
|
||||
{
|
||||
foreach(var file in new DirectoryInfo(config.ThumbnailsDirectory).GetFiles())
|
||||
foreach(var file in new DirectoryInfo(_config.ThumbnailsDirectory).GetFiles())
|
||||
file.Delete();
|
||||
}
|
||||
|
||||
@@ -56,7 +71,16 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
|
||||
.Select(gr => gr.Key)
|
||||
.ToHashSet();
|
||||
|
||||
var files = new DirectoryInfo(config.ImagesDirectory).GetFiles();
|
||||
if (File.Exists(_thumbnailsCacheFile))
|
||||
{
|
||||
var cache = JsonConvert.DeserializeObject<ConcurrentDictionary<string, LabelInfo>>(
|
||||
await File.ReadAllTextAsync(_thumbnailsCacheFile), new DenseDateTimeConverter());
|
||||
LabelsCache = cache ?? new ConcurrentDictionary<string, LabelInfo>();
|
||||
}
|
||||
else
|
||||
LabelsCache = new ConcurrentDictionary<string, LabelInfo>();
|
||||
|
||||
var files = new DirectoryInfo(_config.ImagesDirectory).GetFiles();
|
||||
var imagesCount = files.Length;
|
||||
|
||||
await ParallelExt.ForEachAsync(files, async (file, cancellationToken) =>
|
||||
@@ -70,7 +94,7 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, $"Failed to generate thumbnail for {file.Name}! Error: {e.Message}");
|
||||
_logger.LogError(e, $"Failed to generate thumbnail for {file.Name}! Error: {e.Message}");
|
||||
}
|
||||
}, new ParallelOptions
|
||||
{
|
||||
@@ -87,29 +111,26 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
|
||||
}
|
||||
finally
|
||||
{
|
||||
await SaveLabelsCache();
|
||||
_updateLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateThumbnail(string imgPath, CancellationToken cancellationToken = default)
|
||||
public async Task SaveLabelsCache()
|
||||
{
|
||||
var bitmap = await GenerateThumbnail(imgPath);
|
||||
if (bitmap != null)
|
||||
{
|
||||
var thumbnailName = Path.Combine(ThumbnailsDirectory.FullName, $"{Path.GetFileNameWithoutExtension(imgPath)}{Config.ThumbnailPrefix}.jpg");
|
||||
bitmap.Save(thumbnailName, ImageFormat.Jpeg);
|
||||
}
|
||||
var labelsCacheStr = JsonConvert.SerializeObject(LabelsCache, new DenseDateTimeConverter());
|
||||
await File.WriteAllTextAsync(_thumbnailsCacheFile, labelsCacheStr);
|
||||
}
|
||||
|
||||
private async Task<Bitmap?> GenerateThumbnail(string imgPath)
|
||||
public async Task CreateThumbnail(string imgPath, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var width = (int)config.ThumbnailConfig.Size.Width;
|
||||
var height = (int)config.ThumbnailConfig.Size.Height;
|
||||
var width = (int)_config.ThumbnailConfig.Size.Width;
|
||||
var height = (int)_config.ThumbnailConfig.Size.Height;
|
||||
|
||||
var imgName = Path.GetFileName(imgPath);
|
||||
var labelName = Path.Combine(config.LabelsDirectory, $"{Path.GetFileNameWithoutExtension(imgPath)}.txt");
|
||||
var labelName = Path.Combine(_config.LabelsDirectory, $"{Path.GetFileNameWithoutExtension(imgPath)}.txt");
|
||||
|
||||
var originalImage = Image.FromStream(new MemoryStream(await File.ReadAllBytesAsync(imgPath)));
|
||||
var originalImage = Image.FromStream(new MemoryStream(await File.ReadAllBytesAsync(imgPath, cancellationToken)));
|
||||
|
||||
var bitmap = new Bitmap(width, height);
|
||||
|
||||
@@ -121,16 +142,23 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
|
||||
var size = new Size(originalImage.Width, originalImage.Height);
|
||||
if (!File.Exists(labelName))
|
||||
{
|
||||
File.Move(imgPath, Path.Combine(config.UnknownImages, imgName));
|
||||
logger.LogInformation($"No labels found for image {imgName}! Moved image to the {config.UnknownImages} folder.");
|
||||
return null;
|
||||
File.Move(imgPath, Path.Combine(_config.UnknownImages, imgName));
|
||||
_logger.LogInformation($"No labels found for image {imgName}! Moved image to the {_config.UnknownImages} folder.");
|
||||
return;
|
||||
}
|
||||
var labels = (await YoloLabel.ReadFromFile(labelName))
|
||||
.Select(x => new CanvasLabel(x, size, size))
|
||||
.ToList();
|
||||
|
||||
var thumbWhRatio = width / (float)height;
|
||||
var border = config.ThumbnailConfig.Border;
|
||||
var border = _config.ThumbnailConfig.Border;
|
||||
|
||||
var classes = labels.Select(x => x.ClassNumber).Distinct().ToList();
|
||||
LabelsCache.TryAdd(imgName, new LabelInfo
|
||||
{
|
||||
Classes = classes,
|
||||
ImageDateTime = File.GetCreationTimeUtc(imgPath)
|
||||
});
|
||||
|
||||
var frameX = 0.0;
|
||||
var frameY = 0.0;
|
||||
@@ -169,13 +197,20 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
|
||||
|
||||
foreach (var label in labels)
|
||||
{
|
||||
var color = config.AnnotationClassesDict[label.ClassNumber].Color;
|
||||
var color = _config.AnnotationClassesDict[label.ClassNumber].Color;
|
||||
var brush = new SolidBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
|
||||
|
||||
var rectangle = new RectangleF((float)((label.X - frameX) / scale), (float)((label.Y - frameY) / scale), (float)(label.Width / scale), (float)(label.Height / scale));
|
||||
g.FillRectangle(brush, rectangle);
|
||||
}
|
||||
return bitmap;
|
||||
|
||||
|
||||
|
||||
if (bitmap != null)
|
||||
{
|
||||
var thumbnailName = Path.Combine(ThumbnailsDirectory.FullName, $"{Path.GetFileNameWithoutExtension(imgPath)}{Config.ThumbnailPrefix}.jpg");
|
||||
bitmap.Save(thumbnailName, ImageFormat.Jpeg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +218,8 @@ public interface IGalleryManager
|
||||
{
|
||||
event ThumbnailsUpdatedEventHandler ThumbnailsUpdate;
|
||||
double ThumbnailsPercentage { get; set; }
|
||||
Task SaveLabelsCache();
|
||||
ConcurrentDictionary<string, LabelInfo> LabelsCache { get; set; }
|
||||
Task CreateThumbnail(string imgPath, CancellationToken cancellationToken = default);
|
||||
Task RefreshThumbnails();
|
||||
void ClearThumbnails();
|
||||
|
||||
Reference in New Issue
Block a user