mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 11:16:30 +00:00
add ai recognition: stage 1, works, but doesn't show
This commit is contained in:
@@ -0,0 +1,54 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using Azaion.Annotator.DTO;
|
||||||
|
using Azaion.Annotator.Extensions;
|
||||||
|
using Compunet.YoloV8;
|
||||||
|
using LibVLCSharp.Shared;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace Azaion.Annotator;
|
||||||
|
|
||||||
|
public class AIDetector(Config config, MediaPlayer mediaPlayer, VLCFrameExtractor frameExtractor)
|
||||||
|
: IRequestHandler<AIDetectEvent, List<YoloLabel>>
|
||||||
|
{
|
||||||
|
public async Task<List<YoloLabel>> Handle(AIDetectEvent request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
using var predictor = new YoloPredictor(config.AIModelPath);
|
||||||
|
await frameExtractor.Start(async stream =>
|
||||||
|
{
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
var sw = Stopwatch.StartNew();
|
||||||
|
var result = await predictor.DetectAsync(stream);
|
||||||
|
sw.Stop();
|
||||||
|
var log = string.Join("|", result.Select(det =>
|
||||||
|
$"{det.Name.Id}.{det.Name.Name}: xy=({det.Bounds.X},{det.Bounds.Y}), size=({det.Bounds.Width}, {det.Bounds.Height}), Prob: {det.Confidence*100:F1}%"));
|
||||||
|
log += $". Inf time: {sw.ElapsedMilliseconds} ms";
|
||||||
|
Console.WriteLine(log);
|
||||||
|
});
|
||||||
|
|
||||||
|
while (mediaPlayer.IsPlaying)
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// using var thumbnail = await mediaPlayer.Media.GenerateThumbnail(time: 200,
|
||||||
|
// speed: ThumbnailerSeekSpeed.Fast,
|
||||||
|
// width: 1280,
|
||||||
|
// height: resultHeight,
|
||||||
|
// crop: false,
|
||||||
|
// pictureType: PictureType.Argb)
|
||||||
|
//
|
||||||
|
// mediaPlayer.TakeSnapshot(0, TEMP_IMG, 1280, resultHeight);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
//var result = predictor.Detect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<YoloLabel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -49,6 +49,7 @@ public partial class App : Application
|
|||||||
services.AddSingleton<IConfigRepository, FileConfigRepository>();
|
services.AddSingleton<IConfigRepository, FileConfigRepository>();
|
||||||
services.AddSingleton<Config>(sp => sp.GetRequiredService<IConfigRepository>().Get());
|
services.AddSingleton<Config>(sp => sp.GetRequiredService<IConfigRepository>().Get());
|
||||||
services.AddSingleton<MainWindowEventHandler>();
|
services.AddSingleton<MainWindowEventHandler>();
|
||||||
|
services.AddSingleton<VLCFrameExtractor>();
|
||||||
})
|
})
|
||||||
.UseSerilog()
|
.UseSerilog()
|
||||||
.Build();
|
.Build();
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.20" />
|
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.20" />
|
||||||
<PackageReference Include="VirtualizingWrapPanel" Version="2.0.10" />
|
<PackageReference Include="VirtualizingWrapPanel" Version="2.0.10" />
|
||||||
<PackageReference Include="WindowsAPICodePack" Version="7.0.4" />
|
<PackageReference Include="WindowsAPICodePack" Version="7.0.4" />
|
||||||
|
<PackageReference Include="YoloV8.Gpu" Version="5.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -9,34 +9,35 @@ namespace Azaion.Annotator.DTO;
|
|||||||
|
|
||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
public const string ThumbnailPrefix = "_thumb";
|
public const string THUMBNAIL_PREFIX = "_thumb";
|
||||||
public const string ThumbnailsCacheFile = "thumbnails.cache";
|
public const string THUMBNAILS_CACHE_FILE = "thumbnails.cache";
|
||||||
|
|
||||||
public string VideosDirectory { get; set; }
|
public string VideosDirectory { get; set; } = null!;
|
||||||
public string LabelsDirectory { get; set; }
|
public string LabelsDirectory { get; set; } = null!;
|
||||||
public string ImagesDirectory { get; set; }
|
public string ImagesDirectory { get; set; } = null!;
|
||||||
public string ResultsDirectory { get; set; }
|
public string ResultsDirectory { get; set; } = null!;
|
||||||
public string ThumbnailsDirectory { get; set; }
|
public string ThumbnailsDirectory { get; set; } = null!;
|
||||||
public string UnknownImages { get; set; }
|
public string UnknownImages { get; set; } = null!;
|
||||||
|
|
||||||
public List<AnnotationClass> AnnotationClasses { get; set; } = [];
|
public List<AnnotationClass> AnnotationClasses { get; set; } = [];
|
||||||
|
|
||||||
private Dictionary<int, AnnotationClass>? _annotationClassesDict;
|
private Dictionary<int, AnnotationClass>? _annotationClassesDict;
|
||||||
public Dictionary<int, AnnotationClass> AnnotationClassesDict => _annotationClassesDict ??= AnnotationClasses.ToDictionary(x => x.Id);
|
public Dictionary<int, AnnotationClass> AnnotationClassesDict => _annotationClassesDict ??= AnnotationClasses.ToDictionary(x => x.Id);
|
||||||
|
|
||||||
public WindowConfig MainWindowConfig { get; set; }
|
public WindowConfig MainWindowConfig { get; set; } = null!;
|
||||||
public WindowConfig DatasetExplorerConfig { get; set; }
|
public WindowConfig DatasetExplorerConfig { get; set; } = null!;
|
||||||
|
|
||||||
public double LeftPanelWidth { get; set; }
|
public double LeftPanelWidth { get; set; }
|
||||||
public double RightPanelWidth { get; set; }
|
public double RightPanelWidth { get; set; }
|
||||||
|
|
||||||
public bool ShowHelpOnStart { get; set; }
|
public bool ShowHelpOnStart { get; set; }
|
||||||
|
|
||||||
public List<string> VideoFormats { get; set; }
|
public List<string> VideoFormats { get; set; } = null!;
|
||||||
public List<string> ImageFormats { get; set; }
|
public List<string> ImageFormats { get; set; } = null!;
|
||||||
|
|
||||||
public ThumbnailConfig ThumbnailConfig { get; set; }
|
public ThumbnailConfig ThumbnailConfig { get; set; } = null!;
|
||||||
public int? LastSelectedExplorerClass { get; set; }
|
public int? LastSelectedExplorerClass { get; set; }
|
||||||
|
public string AIModelPath { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WindowConfig
|
public class WindowConfig
|
||||||
|
|||||||
@@ -18,3 +18,5 @@ public class VolumeChangedEvent(int volume) : INotification
|
|||||||
{
|
{
|
||||||
public int Volume { get; set; } = volume;
|
public int Volume { get; set; } = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class AIDetectEvent : IRequest<List<YoloLabel>>;
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ public partial class DatasetExplorer
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var name = Path.GetFileNameWithoutExtension(thumbnail)[..^Config.ThumbnailPrefix.Length];
|
var name = Path.GetFileNameWithoutExtension(thumbnail)[..^Config.THUMBNAIL_PREFIX.Length];
|
||||||
var imagePath = Path.Combine(_config.ImagesDirectory, name);
|
var imagePath = Path.Combine(_config.ImagesDirectory, name);
|
||||||
foreach (var f in _config.ImageFormats)
|
foreach (var f in _config.ImageFormats)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Azaion.Annotator.DTO;
|
||||||
|
using LibVLCSharp.Shared;
|
||||||
|
using SixLabors.ImageSharp.Drawing;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace Azaion.Annotator.Extensions;
|
||||||
|
|
||||||
|
public class VLCFrameExtractor(LibVLC libVLC, MainWindow mainWindow)
|
||||||
|
{
|
||||||
|
private const uint RGBA_BYTES = 4;
|
||||||
|
private const int PLAYBACK_RATE = 3;
|
||||||
|
private const uint DEFAULT_WIDTH = 1280;
|
||||||
|
|
||||||
|
private uint _pitch; // Number of bytes per "line", aligned to x32.
|
||||||
|
private uint _lines; // Number of lines in the buffer, aligned to x32.
|
||||||
|
private uint _width; // Thumbnail width
|
||||||
|
private uint _height; // Thumbnail height
|
||||||
|
private uint _videoFPS;
|
||||||
|
private Func<Stream,Task> _frameProcessFn = null!;
|
||||||
|
|
||||||
|
private MediaPlayer _mediaPlayer = null!;
|
||||||
|
|
||||||
|
private static uint Align32(uint size)
|
||||||
|
{
|
||||||
|
if (size % 32 == 0)
|
||||||
|
return size;
|
||||||
|
return (size / 32 + 1) * 32;// Align on the next multiple of 32
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SKBitmap? _currentBitmap;
|
||||||
|
private static readonly ConcurrentQueue<SKBitmap?> FilesToProcess = new();
|
||||||
|
private static long _frameCounter;
|
||||||
|
|
||||||
|
public async Task Start(Func<Stream, Task> frameProcessFn)
|
||||||
|
{
|
||||||
|
_frameProcessFn = frameProcessFn;
|
||||||
|
var processingCancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
|
_mediaPlayer = new MediaPlayer(libVLC);
|
||||||
|
_mediaPlayer.Stopped += (s, e) => processingCancellationTokenSource.CancelAfter(1);
|
||||||
|
|
||||||
|
using var media = new Media(libVLC, ((MediaFileInfo)mainWindow.LvFiles.SelectedItem).Path);
|
||||||
|
await media.Parse(cancellationToken: processingCancellationTokenSource.Token);
|
||||||
|
var videoTrack = media.Tracks.FirstOrDefault(x => x.Data.Video.Width != 0);
|
||||||
|
_width = videoTrack.Data.Video.Width;
|
||||||
|
_height = videoTrack.Data.Video.Height;
|
||||||
|
_videoFPS = videoTrack.Data.Video.FrameRateNum;
|
||||||
|
|
||||||
|
//rescaling to DEFAULT_WIDTH
|
||||||
|
_height = (uint)(DEFAULT_WIDTH * _height / (double)_width);
|
||||||
|
_width = DEFAULT_WIDTH;
|
||||||
|
|
||||||
|
_pitch = Align32(_width * RGBA_BYTES);
|
||||||
|
_lines = Align32(_height);
|
||||||
|
_mediaPlayer.Play(media);
|
||||||
|
_mediaPlayer.SetRate(3);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
media.AddOption(":no-audio");
|
||||||
|
_mediaPlayer.SetVideoFormat("RV32", _width, _height, _pitch);
|
||||||
|
_mediaPlayer.SetVideoCallbacks(Lock, null, Display);
|
||||||
|
await ProcessThumbnailsAsync(processingCancellationTokenSource.Token);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e.Message);
|
||||||
|
_mediaPlayer.Stop();
|
||||||
|
_mediaPlayer.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessThumbnailsAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
_frameCounter = 0;
|
||||||
|
var surface = SKSurface.Create(new SKImageInfo((int) _width, (int) _height));
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
if (FilesToProcess.TryDequeue(out var bitmap))
|
||||||
|
{
|
||||||
|
if (bitmap == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
surface.Canvas.DrawBitmap(bitmap, 0, 0); // Effectively crops the original bitmap to get only the visible area
|
||||||
|
|
||||||
|
using var outputImage = surface.Snapshot();
|
||||||
|
using var data = outputImage.Encode(SKEncodedImageFormat.Jpeg, 85);
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
data.SaveTo(ms);
|
||||||
|
if (_frameProcessFn != null)
|
||||||
|
await _frameProcessFn(ms);
|
||||||
|
|
||||||
|
Console.WriteLine($"Time: {TimeSpan.FromMilliseconds(_mediaPlayer.Time):mm\\:ss} Queue size: {FilesToProcess.Count}");
|
||||||
|
bitmap.Dispose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(1), token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_mediaPlayer.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr Lock(IntPtr opaque, IntPtr planes)
|
||||||
|
{
|
||||||
|
_currentBitmap = new SKBitmap(new SKImageInfo((int)(_pitch / RGBA_BYTES), (int)_lines, SKColorType.Bgra8888));
|
||||||
|
Marshal.WriteIntPtr(planes, _currentBitmap.GetPixels());
|
||||||
|
return IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Display(IntPtr opaque, IntPtr picture)
|
||||||
|
{
|
||||||
|
if (_frameCounter % (int)(_videoFPS / 3.0) == 0)
|
||||||
|
FilesToProcess.Enqueue(_currentBitmap);
|
||||||
|
else
|
||||||
|
_currentBitmap?.Dispose();
|
||||||
|
|
||||||
|
_currentBitmap = null;
|
||||||
|
_frameCounter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,7 +49,7 @@ public class GalleryManager : IGalleryManager
|
|||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_thumbnailsCacheFile = Path.Combine(config.ThumbnailsDirectory, Config.ThumbnailsCacheFile);
|
_thumbnailsCacheFile = Path.Combine(config.ThumbnailsDirectory, Config.THUMBNAILS_CACHE_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearThumbnails()
|
public void ClearThumbnails()
|
||||||
@@ -63,7 +63,7 @@ public class GalleryManager : IGalleryManager
|
|||||||
await _updateLock.WaitAsync();
|
await _updateLock.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var prefixLen = Config.ThumbnailPrefix.Length;
|
var prefixLen = Config.THUMBNAIL_PREFIX.Length;
|
||||||
|
|
||||||
var thumbnails = ThumbnailsDirectory.GetFiles()
|
var thumbnails = ThumbnailsDirectory.GetFiles()
|
||||||
.Select(x => Path.GetFileNameWithoutExtension(x.Name)[..^prefixLen])
|
.Select(x => Path.GetFileNameWithoutExtension(x.Name)[..^prefixLen])
|
||||||
@@ -122,7 +122,7 @@ public class GalleryManager : IGalleryManager
|
|||||||
await File.WriteAllTextAsync(_thumbnailsCacheFile, labelsCacheStr);
|
await File.WriteAllTextAsync(_thumbnailsCacheFile, labelsCacheStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CreateThumbnail(string imgPath, CancellationToken cancellationToken = default)
|
public async Task<ThumbnailDto?> CreateThumbnail(string imgPath, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var width = (int)_config.ThumbnailConfig.Size.Width;
|
var width = (int)_config.ThumbnailConfig.Size.Width;
|
||||||
var height = (int)_config.ThumbnailConfig.Size.Height;
|
var height = (int)_config.ThumbnailConfig.Size.Height;
|
||||||
@@ -144,9 +144,9 @@ public class GalleryManager : IGalleryManager
|
|||||||
{
|
{
|
||||||
File.Move(imgPath, Path.Combine(_config.UnknownImages, imgName));
|
File.Move(imgPath, Path.Combine(_config.UnknownImages, imgName));
|
||||||
_logger.LogInformation($"No labels found for image {imgName}! Moved image to the {_config.UnknownImages} folder.");
|
_logger.LogInformation($"No labels found for image {imgName}! Moved image to the {_config.UnknownImages} folder.");
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
var labels = (await YoloLabel.ReadFromFile(labelName))
|
var labels = (await YoloLabel.ReadFromFile(labelName, cancellationToken))
|
||||||
.Select(x => new CanvasLabel(x, size, size))
|
.Select(x => new CanvasLabel(x, size, size))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@@ -204,13 +204,16 @@ public class GalleryManager : IGalleryManager
|
|||||||
g.FillRectangle(brush, rectangle);
|
g.FillRectangle(brush, rectangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var thumbnailName = Path.Combine(ThumbnailsDirectory.FullName, $"{Path.GetFileNameWithoutExtension(imgPath)}{Config.THUMBNAIL_PREFIX}.jpg");
|
||||||
|
bitmap.Save(thumbnailName, ImageFormat.Jpeg);
|
||||||
|
|
||||||
|
return new ThumbnailDto
|
||||||
if (bitmap != null)
|
|
||||||
{
|
{
|
||||||
var thumbnailName = Path.Combine(ThumbnailsDirectory.FullName, $"{Path.GetFileNameWithoutExtension(imgPath)}{Config.ThumbnailPrefix}.jpg");
|
ThumbnailPath = thumbnailName,
|
||||||
bitmap.Save(thumbnailName, ImageFormat.Jpeg);
|
ImagePath = imgPath,
|
||||||
}
|
LabelPath = labelName,
|
||||||
|
ImageDate = File.GetCreationTimeUtc(imgPath)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +223,7 @@ public interface IGalleryManager
|
|||||||
double ThumbnailsPercentage { get; set; }
|
double ThumbnailsPercentage { get; set; }
|
||||||
Task SaveLabelsCache();
|
Task SaveLabelsCache();
|
||||||
ConcurrentDictionary<string, LabelInfo> LabelsCache { get; set; }
|
ConcurrentDictionary<string, LabelInfo> LabelsCache { get; set; }
|
||||||
Task CreateThumbnail(string imgPath, CancellationToken cancellationToken = default);
|
Task<ThumbnailDto?> CreateThumbnail(string imgPath, CancellationToken cancellationToken = default);
|
||||||
Task RefreshThumbnails();
|
Task RefreshThumbnails();
|
||||||
void ClearThumbnails();
|
void ClearThumbnails();
|
||||||
}
|
}
|
||||||
+297
-256
@@ -47,237 +47,254 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
|
|
||||||
<Grid
|
<Grid Name="GlobalGrid"
|
||||||
Name="MainGrid"
|
ShowGridLines="False"
|
||||||
ShowGridLines="False"
|
Background="Black">
|
||||||
Background="Black"
|
|
||||||
HorizontalAlignment="Stretch">
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="28"></RowDefinition>
|
|
||||||
<RowDefinition Height="28"></RowDefinition>
|
|
||||||
<RowDefinition Height="28"></RowDefinition>
|
|
||||||
<RowDefinition Height="*"></RowDefinition>
|
|
||||||
<RowDefinition Height="*"></RowDefinition>
|
<RowDefinition Height="*"></RowDefinition>
|
||||||
<RowDefinition Height="28"></RowDefinition>
|
<RowDefinition Height="28"></RowDefinition>
|
||||||
<RowDefinition Height="32"></RowDefinition>
|
<RowDefinition Height="32"></RowDefinition>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="250" />
|
|
||||||
<ColumnDefinition Width="4"/>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="4"/>
|
|
||||||
<ColumnDefinition Width="200" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Menu Grid.Row="0"
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.ColumnSpan="3"
|
|
||||||
Background="Black">
|
|
||||||
<MenuItem Header="Файл" Foreground="#FFBDBCBC" Margin="0,3,0,0">
|
|
||||||
<MenuItem x:Name="OpenFolderItem"
|
|
||||||
Foreground="Black"
|
|
||||||
IsEnabled="True" Header="Відкрити папку..." Click="OpenFolderItemClick"/>
|
|
||||||
<MenuItem x:Name="OpenDataExplorerItem"
|
|
||||||
Foreground="Black"
|
|
||||||
IsEnabled="True" Header="Відкрити переглядач анотацій..." Click="OpenDataExplorerItemClick"/>
|
|
||||||
<MenuItem x:Name="ReloadThumbnailsItem"
|
|
||||||
Foreground="Black"
|
|
||||||
IsEnabled="True" Header="Оновити базу іконок" Click="ReloadThumbnailsItemClick"/>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem Header="Допомога" Foreground="#FFBDBCBC" Margin="0,3,0,0">
|
|
||||||
<MenuItem x:Name="OpenHelpWindow"
|
|
||||||
Foreground="Black"
|
|
||||||
IsEnabled="True" Header="Як анотувати" Click="OpenHelpWindowClick"/>
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
<Grid
|
<Grid
|
||||||
HorizontalAlignment="Stretch"
|
Name="MainGrid"
|
||||||
Grid.Column="0"
|
ShowGridLines="False"
|
||||||
Grid.Row="1">
|
Background="Black"
|
||||||
|
HorizontalAlignment="Stretch">
|
||||||
|
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="28"></RowDefinition>
|
||||||
|
<RowDefinition Height="28"></RowDefinition>
|
||||||
|
<RowDefinition Height="28"></RowDefinition>
|
||||||
|
<RowDefinition Height="*"></RowDefinition>
|
||||||
|
<RowDefinition Height="*"></RowDefinition>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="250" />
|
||||||
|
<ColumnDefinition Width="4"/>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="30"/>
|
<ColumnDefinition Width="4"/>
|
||||||
|
<ColumnDefinition Width="200" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBox
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.Row="0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Margin="1"
|
|
||||||
x:Name="TbFolder"></TextBox>
|
|
||||||
<Button
|
|
||||||
Grid.Row="0"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="1"
|
|
||||||
Click="OpenFolderButtonClick">
|
|
||||||
. . .
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid
|
<Menu Grid.Row="0"
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.Row="2">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="50" />
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Label
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.Row="0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Margin="1"
|
|
||||||
Foreground="LightGray"
|
|
||||||
Content="Фільтр: "/>
|
|
||||||
<TextBox
|
|
||||||
Grid.Column="1"
|
|
||||||
Grid.Row="0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Margin="1"
|
|
||||||
x:Name="TbFilter"
|
|
||||||
TextChanged="TbFilter_OnTextChanged">
|
|
||||||
</TextBox>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<ListView Grid.Row="3"
|
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Name="LvFiles"
|
Grid.ColumnSpan="4"
|
||||||
Background="Black"
|
Background="Black">
|
||||||
SelectedItem="{Binding Path=SelectedVideo}" Foreground="#FFA4AFCC"
|
<MenuItem Header="Файл" Foreground="#FFBDBCBC" Margin="0,3,0,0">
|
||||||
>
|
<MenuItem x:Name="OpenFolderItem"
|
||||||
<ListView.Resources>
|
Foreground="Black"
|
||||||
<Style TargetType="{x:Type ListViewItem}">
|
IsEnabled="True" Header="Відкрити папку..." Click="OpenFolderItemClick"/>
|
||||||
<Style.Triggers>
|
<MenuItem x:Name="OpenDataExplorerItem"
|
||||||
<DataTrigger Binding="{Binding HasAnnotations}" Value="true">
|
Foreground="Black"
|
||||||
<Setter Property="Background" Value="Gray"/>
|
IsEnabled="True" Header="Відкрити переглядач анотацій..." Click="OpenDataExplorerItemClick"/>
|
||||||
</DataTrigger>
|
<MenuItem x:Name="ReloadThumbnailsItem"
|
||||||
</Style.Triggers>
|
Foreground="Black"
|
||||||
</Style>
|
IsEnabled="True" Header="Оновити базу іконок" Click="ReloadThumbnailsItemClick"/>
|
||||||
</ListView.Resources>
|
</MenuItem>
|
||||||
<ListView.View>
|
<MenuItem Header="Допомога" Foreground="#FFBDBCBC" Margin="0,3,0,0">
|
||||||
<GridView>
|
<MenuItem x:Name="OpenHelpWindow"
|
||||||
<GridViewColumn Width="Auto"
|
Foreground="Black"
|
||||||
Header="Файл"
|
IsEnabled="True" Header="Як анотувати" Click="OpenHelpWindowClick"/>
|
||||||
DisplayMemberBinding="{Binding Path=Name}"/>
|
</MenuItem>
|
||||||
<GridViewColumn Width="Auto"
|
</Menu>
|
||||||
Header="Тривалість"
|
<Grid
|
||||||
DisplayMemberBinding="{Binding Path=DurationStr}"/>
|
HorizontalAlignment="Stretch"
|
||||||
</GridView>
|
Grid.Column="0"
|
||||||
</ListView.View>
|
Grid.Row="1">
|
||||||
</ListView>
|
|
||||||
<controls:AnnotationClasses
|
<Grid.ColumnDefinitions>
|
||||||
x:Name="LvClasses"
|
<ColumnDefinition Width="*" />
|
||||||
Grid.Column="0"
|
<ColumnDefinition Width="30"/>
|
||||||
Grid.Row="4">
|
</Grid.ColumnDefinitions>
|
||||||
</controls:AnnotationClasses>
|
<TextBox
|
||||||
<GridSplitter
|
Grid.Column="0"
|
||||||
Background="DarkGray"
|
Grid.Row="0"
|
||||||
ResizeDirection="Columns"
|
HorizontalAlignment="Stretch"
|
||||||
Grid.Column="1"
|
Margin="1"
|
||||||
Grid.Row="1"
|
x:Name="TbFolder"></TextBox>
|
||||||
Grid.RowSpan="4"
|
<Button
|
||||||
ResizeBehavior="PreviousAndNext"
|
Grid.Row="0"
|
||||||
HorizontalAlignment="Stretch"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Stretch"
|
Margin="1"
|
||||||
DragCompleted="Thumb_OnDragCompleted"
|
Click="OpenFolderButtonClick">
|
||||||
|
. . .
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="2">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="50" />
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Margin="1"
|
||||||
|
Foreground="LightGray"
|
||||||
|
Content="Фільтр: "/>
|
||||||
|
<TextBox
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.Row="0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Margin="1"
|
||||||
|
x:Name="TbFilter"
|
||||||
|
TextChanged="TbFilter_OnTextChanged">
|
||||||
|
</TextBox>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<ListView Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
|
Name="LvFiles"
|
||||||
|
Background="Black"
|
||||||
|
SelectedItem="{Binding Path=SelectedVideo}" Foreground="#FFA4AFCC"
|
||||||
|
>
|
||||||
|
<ListView.Resources>
|
||||||
|
<Style TargetType="{x:Type ListViewItem}">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding HasAnnotations}" Value="true">
|
||||||
|
<Setter Property="Background" Value="Gray"/>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</ListView.Resources>
|
||||||
|
<ListView.View>
|
||||||
|
<GridView>
|
||||||
|
<GridViewColumn Width="Auto"
|
||||||
|
Header="Файл"
|
||||||
|
DisplayMemberBinding="{Binding Path=Name}"/>
|
||||||
|
<GridViewColumn Width="Auto"
|
||||||
|
Header="Тривалість"
|
||||||
|
DisplayMemberBinding="{Binding Path=DurationStr}"/>
|
||||||
|
</GridView>
|
||||||
|
</ListView.View>
|
||||||
|
</ListView>
|
||||||
|
<controls:AnnotationClasses
|
||||||
|
x:Name="LvClasses"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="4">
|
||||||
|
</controls:AnnotationClasses>
|
||||||
|
|
||||||
|
<GridSplitter
|
||||||
|
Background="DarkGray"
|
||||||
|
ResizeDirection="Columns"
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.RowSpan="4"
|
||||||
|
ResizeBehavior="PreviousAndNext"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
DragCompleted="Thumb_OnDragCompleted"/>
|
||||||
|
|
||||||
|
<wpf:VideoView
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="2"
|
||||||
|
Grid.RowSpan="4"
|
||||||
|
x:Name="VideoView">
|
||||||
|
<controls:CanvasEditor x:Name="Editor"
|
||||||
|
Background="#01000000"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalAlignment="Stretch" />
|
||||||
|
</wpf:VideoView>
|
||||||
|
|
||||||
|
<GridSplitter
|
||||||
|
Background="DarkGray"
|
||||||
|
ResizeDirection="Columns"
|
||||||
|
Grid.Column="3"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.RowSpan="4"
|
||||||
|
ResizeBehavior="PreviousAndNext"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
DragCompleted="Thumb_OnDragCompleted"
|
||||||
/>
|
/>
|
||||||
<wpf:VideoView
|
|
||||||
Grid.Row="1"
|
<DataGrid x:Name="DgAnnotations"
|
||||||
Grid.Column="2"
|
Grid.Column="4"
|
||||||
Grid.RowSpan="4"
|
Grid.Row="1"
|
||||||
x:Name="VideoView">
|
Grid.RowSpan="4"
|
||||||
<controls:CanvasEditor x:Name="Editor"
|
Background="Black"
|
||||||
Background="#01000000"
|
RowBackground="#252525"
|
||||||
VerticalAlignment="Stretch"
|
Foreground="White"
|
||||||
HorizontalAlignment="Stretch" />
|
RowHeaderWidth="0"
|
||||||
</wpf:VideoView>
|
Padding="2 0 0 0"
|
||||||
<GridSplitter
|
AutoGenerateColumns="False"
|
||||||
Background="DarkGray"
|
SelectionMode="Single"
|
||||||
ResizeDirection="Columns"
|
CellStyle="{DynamicResource DataGridCellStyle1}"
|
||||||
Grid.Column="3"
|
IsReadOnly="True"
|
||||||
Grid.Row="1"
|
CanUserResizeRows="False"
|
||||||
Grid.RowSpan="4"
|
CanUserResizeColumns="False">
|
||||||
ResizeBehavior="PreviousAndNext"
|
<DataGrid.Columns>
|
||||||
HorizontalAlignment="Stretch"
|
<DataGridTextColumn
|
||||||
VerticalAlignment="Stretch"
|
Width="60"
|
||||||
DragCompleted="Thumb_OnDragCompleted"
|
Header="Кадр"
|
||||||
/>
|
CanUserSort="False"
|
||||||
<DataGrid x:Name="DgAnnotations"
|
Binding="{Binding Path=TimeStr}">
|
||||||
Grid.Column="4"
|
<DataGridTextColumn.HeaderStyle>
|
||||||
Grid.Row="1"
|
<Style TargetType="DataGridColumnHeader">
|
||||||
Grid.RowSpan="6"
|
<Setter Property="Background" Value="#252525"></Setter>
|
||||||
Background="Black"
|
</Style>
|
||||||
RowBackground="#252525"
|
</DataGridTextColumn.HeaderStyle>
|
||||||
Foreground="White"
|
</DataGridTextColumn>
|
||||||
RowHeaderWidth="0"
|
<DataGridTextColumn
|
||||||
Padding="2 0 0 0"
|
Width="*"
|
||||||
AutoGenerateColumns="False"
|
Header="Клас"
|
||||||
SelectionMode="Single"
|
Binding="{Binding Path=ClassName}"
|
||||||
CellStyle="{DynamicResource DataGridCellStyle1}"
|
CanUserSort="False">
|
||||||
IsReadOnly="True"
|
<DataGridTextColumn.HeaderStyle>
|
||||||
CanUserResizeRows="False"
|
<Style TargetType="DataGridColumnHeader">
|
||||||
CanUserResizeColumns="False">
|
<Setter Property="Background" Value="#252525"></Setter>
|
||||||
<DataGrid.Columns>
|
</Style>
|
||||||
<DataGridTextColumn
|
</DataGridTextColumn.HeaderStyle>
|
||||||
Width="60"
|
<DataGridTextColumn.CellStyle>
|
||||||
Header="Кадр"
|
<Style TargetType="DataGridCell">
|
||||||
CanUserSort="False"
|
<Setter Property="Background">
|
||||||
Binding="{Binding Path=TimeStr}">
|
<Setter.Value>
|
||||||
<DataGridTextColumn.HeaderStyle>
|
<SolidColorBrush Color="{Binding Path=ClassColor}"></SolidColorBrush>
|
||||||
<Style TargetType="DataGridColumnHeader">
|
</Setter.Value>
|
||||||
<Setter Property="Background" Value="#252525"></Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
</DataGridTextColumn.HeaderStyle>
|
</DataGridTextColumn.CellStyle>
|
||||||
</DataGridTextColumn>
|
</DataGridTextColumn>
|
||||||
<DataGridTextColumn
|
</DataGrid.Columns>
|
||||||
Width="*"
|
<DataGrid.ItemContainerStyle>
|
||||||
Header="Клас"
|
<Style TargetType="DataGridRow">
|
||||||
Binding="{Binding Path=ClassName}"
|
<EventSetter Event="MouseDoubleClick" Handler="DgAnnotationsRowClick"></EventSetter>
|
||||||
CanUserSort="False">
|
</Style>
|
||||||
<DataGridTextColumn.HeaderStyle>
|
</DataGrid.ItemContainerStyle>
|
||||||
<Style TargetType="DataGridColumnHeader">
|
</DataGrid>
|
||||||
<Setter Property="Background" Value="#252525"></Setter>
|
</Grid>
|
||||||
</Style>
|
|
||||||
</DataGridTextColumn.HeaderStyle>
|
|
||||||
<DataGridTextColumn.CellStyle>
|
|
||||||
<Style TargetType="DataGridCell">
|
|
||||||
<Setter Property="Background">
|
|
||||||
<Setter.Value>
|
|
||||||
<SolidColorBrush Color="{Binding Path=ClassColor}"></SolidColorBrush>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
</DataGridTextColumn.CellStyle>
|
|
||||||
</DataGridTextColumn>
|
|
||||||
</DataGrid.Columns>
|
|
||||||
<DataGrid.ItemContainerStyle>
|
|
||||||
<Style TargetType="DataGridRow">
|
|
||||||
<EventSetter Event="MouseDoubleClick" Handler="DgAnnotationsRowClick"></EventSetter>
|
|
||||||
</Style>
|
|
||||||
</DataGrid.ItemContainerStyle>
|
|
||||||
</DataGrid>
|
|
||||||
|
|
||||||
<controls:UpdatableProgressBar x:Name="VideoSlider"
|
<controls:UpdatableProgressBar x:Name="VideoSlider"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Grid.Row="5"
|
Grid.Row="1"
|
||||||
Grid.ColumnSpan="4"
|
|
||||||
Background="#252525"
|
Background="#252525"
|
||||||
Foreground="LightBlue">
|
Foreground="LightBlue">
|
||||||
|
|
||||||
</controls:UpdatableProgressBar>
|
</controls:UpdatableProgressBar>
|
||||||
|
|
||||||
|
<!-- Buttons -->
|
||||||
<Grid
|
<Grid
|
||||||
Grid.Row="6"
|
Name="Buttons"
|
||||||
Grid.Column="0"
|
Grid.Row="2"
|
||||||
Background="Black"
|
Background="Black"
|
||||||
>
|
>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="28" />
|
<ColumnDefinition Width="28" /> <!-- 0 -->
|
||||||
<ColumnDefinition Width="28"/>
|
<ColumnDefinition Width="28" /> <!-- 1 -->
|
||||||
<ColumnDefinition Width="28"/>
|
<ColumnDefinition Width="28" /> <!-- 2 -->
|
||||||
<ColumnDefinition Width="28"/>
|
<ColumnDefinition Width="28" /> <!-- 3 -->
|
||||||
<ColumnDefinition Width="28"/>
|
<ColumnDefinition Width="28" /> <!-- 4 -->
|
||||||
<ColumnDefinition Width="28"/>
|
<ColumnDefinition Width="28" /> <!-- 5 -->
|
||||||
<ColumnDefinition Width="28"/>
|
<ColumnDefinition Width="28" /> <!-- 6 -->
|
||||||
<ColumnDefinition Width="28"/>
|
<ColumnDefinition Width="28" /> <!-- 7 -->
|
||||||
<ColumnDefinition Width="28"/>
|
<ColumnDefinition Width="28" /> <!-- 8 -->
|
||||||
|
<ColumnDefinition Width="56" /> <!-- 9 -->
|
||||||
|
<ColumnDefinition Width="28" /> <!-- 10 -->
|
||||||
|
<ColumnDefinition Width="*" /> <!-- 11 -->
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Button Grid.Column="0" Padding="5" ToolTip="Включити програвання" Background="Black" BorderBrush="Black"
|
<Button Grid.Column="0" Padding="5" ToolTip="Включити програвання" Background="Black" BorderBrush="Black"
|
||||||
Click="PlayClick">
|
Click="PlayClick">
|
||||||
@@ -445,53 +462,77 @@
|
|||||||
</Image.Source>
|
</Image.Source>
|
||||||
</Image>
|
</Image>
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
|
||||||
<StatusBar
|
|
||||||
Grid.Row="6"
|
|
||||||
Grid.Column="2"
|
|
||||||
Grid.ColumnSpan="2"
|
|
||||||
Background="#252525"
|
|
||||||
Foreground="White"
|
|
||||||
>
|
|
||||||
<StatusBar.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Grid.RowDefinitions>
|
<controls:UpdatableProgressBar
|
||||||
<RowDefinition Height="*" />
|
x:Name="Volume"
|
||||||
</Grid.RowDefinitions>
|
Grid.Column="9"
|
||||||
</Grid>
|
Width="70" Height="15"
|
||||||
</ItemsPanelTemplate>
|
HorizontalAlignment="Stretch"
|
||||||
</StatusBar.ItemsPanel>
|
Background="#252525" BorderBrush="#252525" Foreground="LightBlue"
|
||||||
<StatusBarItem Grid.Column="0" Background="Black">
|
Maximum="100" Minimum="0">
|
||||||
<controls:UpdatableProgressBar x:Name="Volume"
|
</controls:UpdatableProgressBar>
|
||||||
Width="70"
|
|
||||||
Height="15"
|
<Button
|
||||||
HorizontalAlignment="Stretch"
|
x:Name="AIDetectBtn"
|
||||||
Background="#252525"
|
Grid.Column="10"
|
||||||
BorderBrush="#252525"
|
Padding="2" Width="25"
|
||||||
Foreground="LightBlue"
|
Height="25"
|
||||||
Maximum="100"
|
ToolTip="Розпізнати за допомогою AI. Клавіша: [A]" Background="Black" BorderBrush="Black"
|
||||||
Minimum="0">
|
Click="AutoDetect">
|
||||||
</controls:UpdatableProgressBar>
|
<Path Stretch="Fill" Fill="LightGray" Data="M144.317 85.269h223.368c15.381 0 29.391 6.325 39.567 16.494l.025-.024c10.163 10.164 16.477 24.193 16.477
|
||||||
</StatusBarItem>
|
39.599v189.728c0 15.401-6.326 29.425-16.485 39.584-10.159 10.159-24.183 16.484-39.584 16.484H144.317c-15.4
|
||||||
<StatusBarItem Grid.Column="1">
|
0-29.437-6.313-39.601-16.476-10.152-10.152-16.47-24.167-16.47-39.592V141.338c0-15.374 6.306-29.379 16.463-39.558l.078-.078c10.178-10.139
|
||||||
<TextBlock Margin="3 0 0 0" x:Name="StatusClock" FontSize="16" Text="00:00 / 00:00"></TextBlock>
|
24.168-16.433 39.53-16.433zm59.98 204.329h-39.825l30.577-117.964h58.32l30.577 117.964h-39.825l-3.051-18.686h-33.725l-3.048 18.686zm15.645-81.726l-5.801
|
||||||
</StatusBarItem>
|
33.032h19.945l-5.61-33.032h-8.534zm74.007 81.726V171.634h37.749v117.964h-37.749zm161.348-35.797v30.763c0 3.165 2.587 5.751 5.752 5.751h45.199c3.165 0
|
||||||
<Separator Grid.Column="2" />
|
5.752-2.586 5.752-5.751v-30.763c0-3.165-2.587-5.752-5.752-5.752h-45.199c-3.165 0-5.752 2.587-5.752 5.752zm0-70.639v30.762c0 3.163 2.587 5.752 5.752
|
||||||
<StatusBarItem Grid.Column="3">
|
5.752h45.199c3.165 0 5.752-2.589 5.752-5.752v-30.762c0-3.168-2.587-5.752-5.752-5.752h-45.199c-3.165 0-5.752 2.584-5.752 5.752zm0 141.278v30.763c0 3.165
|
||||||
<TextBlock Margin="3 0 0 0" x:Name="StatusHelp" FontSize="12" ></TextBlock>
|
2.587 5.752 5.752 5.752h45.199c3.165 0 5.752-2.587 5.752-5.752V324.44c0-3.165-2.587-5.751-5.752-5.751h-45.199c-3.165 0-5.752 2.586-5.752 5.751zm0-211.92v30.763c0
|
||||||
</StatusBarItem>
|
3.164 2.587 5.751 5.752 5.751h45.199c3.165 0 5.752-2.587 5.752-5.751V112.52c0-3.165-2.587-5.752-5.752-5.752h-45.199c-3.165 0-5.752 2.587-5.752 5.752zM56.703
|
||||||
<StatusBarItem Grid.Column="4">
|
253.801v30.763c0 3.165-2.587 5.751-5.752 5.751H5.752c-3.165 0-5.752-2.586-5.752-5.751v-30.763c0-3.165 2.587-5.752 5.752-5.752h45.199c3.165 0 5.752 2.587
|
||||||
<TextBlock x:Name="Status"></TextBlock>
|
5.752 5.752zm0-70.639v30.762c0 3.163-2.587 5.752-5.752 5.752H5.752c-3.165 0-5.752-2.589-5.752-5.752v-30.762c0-3.168 2.587-5.752 5.752-5.752h45.199c3.165
|
||||||
</StatusBarItem>
|
0 5.752 2.584 5.752 5.752zm0 141.278v30.763c0 3.165-2.587 5.752-5.752 5.752H5.752c-3.165 0-5.752-2.587-5.752-5.752V324.44c0-3.165 2.587-5.751
|
||||||
</StatusBar>
|
5.752-5.751h45.199c3.165 0 5.752 2.586 5.752 5.751zm0-211.92v30.763c0 3.164-2.587 5.751-5.752 5.751H5.752c-3.165 0-5.752-2.587-5.752-5.751V112.52c0-3.165
|
||||||
|
2.587-5.752 5.752-5.752h45.199c3.165 0 5.752 2.587 5.752 5.752zM346.579 415.7h30.763c3.162 0 5.751 2.587 5.751 5.752v45.199c0 3.165-2.589 5.752-5.751
|
||||||
|
5.752h-30.763c-3.167 0-5.752-2.587-5.752-5.752v-45.199c0-3.165 2.585-5.752 5.752-5.752zm-70.642 0H306.7c3.165 0 5.751 2.587 5.751 5.752v45.199c0 3.165-2.586
|
||||||
|
5.752-5.751 5.752h-30.763c-3.165 0-5.752-2.587-5.752-5.752v-45.199c0-3.165 2.587-5.752 5.752-5.752zm-70.639 0h30.762c3.165 0 5.752 2.587 5.752 5.752v45.199c0
|
||||||
|
3.165-2.587 5.752-5.752 5.752h-30.762c-3.165 0-5.752-2.587-5.752-5.752v-45.199c0-3.165 2.587-5.752 5.752-5.752zm-70.64 0h30.763c3.165 0 5.752 2.587 5.752
|
||||||
|
5.752v45.199c0 3.165-2.587 5.752-5.752 5.752h-30.763c-3.165 0-5.751-2.587-5.751-5.752v-45.199c0-3.165 2.586-5.752 5.751-5.752zM346.579 0h30.763c3.162 0 5.751
|
||||||
|
2.587 5.751 5.752v45.199c0 3.165-2.589 5.752-5.751 5.752h-30.763c-3.167 0-5.752-2.587-5.752-5.752V5.752c0-3.165 2.585-5.752 5.752-5.752zm-70.642 0H306.7c3.165
|
||||||
|
0 5.751 2.587 5.751 5.752v45.199c0 3.165-2.586 5.752-5.751 5.752h-30.763c-3.165 0-5.752-2.587-5.752-5.752V5.752c0-3.165 2.587-5.752 5.752-5.752zm-70.639
|
||||||
|
0h30.762c3.165 0 5.752 2.587 5.752 5.752v45.199c0 3.165-2.587 5.752-5.752 5.752h-30.762c-3.165 0-5.752-2.587-5.752-5.752V5.752c0-3.165 2.587-5.752
|
||||||
|
5.752-5.752zm-70.64 0h30.763c3.165 0 5.752 2.587 5.752 5.752v45.199c0 3.165-2.587 5.752-5.752 5.752h-30.763c-3.165 0-5.751-2.587-5.751-5.752V5.752c0-3.165
|
||||||
|
2.586-5.752 5.751-5.752zm233.027 111.097H144.317a30.11 30.11 0 00-21.35 8.844l-.049.049a30.117 30.117 0 00-8.844 21.348v189.728c0 8.292 3.414 15.847 8.9
|
||||||
|
21.333 5.494 5.493 13.058 8.907 21.343 8.907h223.368c8.273 0 15.833-3.421 21.326-8.914s8.915-13.053
|
||||||
|
8.915-21.326V141.338c0-8.283-3.414-15.848-8.908-21.341v-.049c-5.454-5.456-13.006-8.851-21.333-8.851z" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<StatusBar Grid.Column="11"
|
||||||
|
Background="#252525"
|
||||||
|
Foreground="White">
|
||||||
|
<StatusBar.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
</Grid>
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</StatusBar.ItemsPanel>
|
||||||
|
<StatusBarItem Grid.Column="0">
|
||||||
|
<TextBlock Margin="3 0 0 0" x:Name="StatusClock" FontSize="16" Text="00:00 / 00:00"></TextBlock>
|
||||||
|
</StatusBarItem>
|
||||||
|
<Separator Grid.Column="1" />
|
||||||
|
<StatusBarItem Grid.Column="2">
|
||||||
|
<TextBlock Margin="3 0 0 0" x:Name="StatusHelp" FontSize="12" ></TextBlock>
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem Grid.Column="3">
|
||||||
|
<TextBlock x:Name="Status"></TextBlock>
|
||||||
|
</StatusBarItem>
|
||||||
|
</StatusBar>
|
||||||
|
</Grid>
|
||||||
|
<!-- /Buttons -->
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@@ -83,15 +83,7 @@ public partial class MainWindow
|
|||||||
{
|
{
|
||||||
Core.Initialize();
|
Core.Initialize();
|
||||||
InitControls();
|
InitControls();
|
||||||
|
_ = Task.Run(async () => await _galleryManager.RefreshThumbnails());
|
||||||
_ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
await _galleryManager.RefreshThumbnails();
|
|
||||||
await Task.Delay(30000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
_suspendLayout = true;
|
_suspendLayout = true;
|
||||||
|
|
||||||
@@ -141,6 +133,7 @@ public partial class MainWindow
|
|||||||
Dispatcher.Invoke(() => StatusHelp.Text = "");
|
Dispatcher.Invoke(() => StatusHelp.Text = "");
|
||||||
await Task.Delay(200);
|
await Task.Delay(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dispatcher.Invoke(() => StatusHelp.Text = helpText);
|
Dispatcher.Invoke(() => StatusHelp.Text = helpText);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -249,7 +242,7 @@ public partial class MainWindow
|
|||||||
{
|
{
|
||||||
var name = Path.GetFileNameWithoutExtension(file.Name);
|
var name = Path.GetFileNameWithoutExtension(file.Name);
|
||||||
var time = _formState.GetTime(name);
|
var time = _formState.GetTime(name);
|
||||||
await AddAnnotation(time, await YoloLabel.ReadFromFile(file.FullName));
|
await AddAnnotation(time, await YoloLabel.ReadFromFile(file.FullName, cancellationToken));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,11 +260,11 @@ public partial class MainWindow
|
|||||||
_formState.AnnotationResults.Remove(existingResult);
|
_formState.AnnotationResults.Remove(existingResult);
|
||||||
|
|
||||||
var dict = _formState.AnnotationResults
|
var dict = _formState.AnnotationResults
|
||||||
.Select((x,i) => new { x.Time, Index = i })
|
.Select((x, i) => new { x.Time, Index = i })
|
||||||
.ToDictionary(x => x.Time, x => x.Index);
|
.ToDictionary(x => x.Time, x => x.Index);
|
||||||
|
|
||||||
var index = dict.Where(x => x.Key < timeValue)
|
var index = dict.Where(x => x.Key < timeValue)
|
||||||
.OrderBy(x => x.Key - timeValue)
|
.OrderBy(x => timeValue - x.Key)
|
||||||
.Select(x => x.Value + 1)
|
.Select(x => x.Value + 1)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
@@ -299,7 +292,7 @@ public partial class MainWindow
|
|||||||
|
|
||||||
var videoFiles = dir.GetFiles(_config.VideoFormats.ToArray()).Select(x =>
|
var videoFiles = dir.GetFiles(_config.VideoFormats.ToArray()).Select(x =>
|
||||||
{
|
{
|
||||||
var media = new Media(_libVLC, x.FullName);
|
using var media = new Media(_libVLC, x.FullName);
|
||||||
media.Parse();
|
media.Parse();
|
||||||
var fInfo = new MediaFileInfo
|
var fInfo = new MediaFileInfo
|
||||||
{
|
{
|
||||||
@@ -346,6 +339,7 @@ public partial class MainWindow
|
|||||||
// }
|
// }
|
||||||
private async void OpenFolderItemClick(object sender, RoutedEventArgs e) => await OpenFolder();
|
private async void OpenFolderItemClick(object sender, RoutedEventArgs e) => await OpenFolder();
|
||||||
private async void OpenFolderButtonClick(object sender, RoutedEventArgs e) => await OpenFolder();
|
private async void OpenFolderButtonClick(object sender, RoutedEventArgs e) => await OpenFolder();
|
||||||
|
|
||||||
private async Task OpenFolder()
|
private async Task OpenFolder()
|
||||||
{
|
{
|
||||||
var dlg = new CommonOpenFileDialog
|
var dlg = new CommonOpenFileDialog
|
||||||
@@ -365,6 +359,7 @@ public partial class MainWindow
|
|||||||
|
|
||||||
ReloadFiles();
|
ReloadFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TbFilter_OnTextChanged(object sender, TextChangedEventArgs e)
|
private void TbFilter_OnTextChanged(object sender, TextChangedEventArgs e)
|
||||||
{
|
{
|
||||||
FilteredMediaFiles = new ObservableCollection<MediaFileInfo>(AllMediaFiles.Where(x => x.Name.ToLower().Contains(TbFilter.Text.ToLower())).ToList());
|
FilteredMediaFiles = new ObservableCollection<MediaFileInfo>(AllMediaFiles.Where(x => x.Name.ToLower().Contains(TbFilter.Text.ToLower())).ToList());
|
||||||
@@ -387,14 +382,21 @@ public partial class MainWindow
|
|||||||
private void StopClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.Stop));
|
private void StopClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.Stop));
|
||||||
|
|
||||||
private void PreviousFrameClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.PreviousFrame));
|
private void PreviousFrameClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.PreviousFrame));
|
||||||
private void NextFrameClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.NextFrame));
|
private void NextFrameClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.NextFrame));
|
||||||
|
|
||||||
private void SaveAnnotationsClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.SaveAnnotations));
|
private void SaveAnnotationsClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.SaveAnnotations));
|
||||||
|
|
||||||
private void RemoveSelectedClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.RemoveSelectedAnns));
|
private void RemoveSelectedClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.RemoveSelectedAnns));
|
||||||
private void RemoveAllClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.RemoveAllAnns));
|
private void RemoveAllClick(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.RemoveAllAnns));
|
||||||
private void TurnOffVolume(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.TurnOffVolume));
|
private void TurnOffVolume(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.TurnOffVolume));
|
||||||
private void TurnOnVolume(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.TurnOnVolume));
|
private void TurnOnVolume(object sender, RoutedEventArgs e) => _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.TurnOnVolume));
|
||||||
|
|
||||||
|
private async void AutoDetect(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (LvFiles.SelectedItem == null)
|
||||||
|
return;
|
||||||
|
await _mediator.Send(new AIDetectEvent());
|
||||||
|
}
|
||||||
|
|
||||||
private void OpenHelpWindowClick(object sender, RoutedEventArgs e)
|
private void OpenHelpWindowClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -410,7 +412,7 @@ public partial class MainWindow
|
|||||||
var dgRow = ItemsControl.ContainerFromElement((DataGrid)sender, (args.OriginalSource as DependencyObject)!) as DataGridRow;
|
var dgRow = ItemsControl.ContainerFromElement((DataGrid)sender, (args.OriginalSource as DependencyObject)!) as DataGridRow;
|
||||||
var res = (AnnotationResult)dgRow!.Item;
|
var res = (AnnotationResult)dgRow!.Item;
|
||||||
_mediaPlayer.SetPause(true);
|
_mediaPlayer.SetPause(true);
|
||||||
_mediaPlayer.Time = (long)res.Time.TotalMilliseconds;// + 250;
|
_mediaPlayer.Time = (long)res.Time.TotalMilliseconds; // + 250;
|
||||||
ShowTimeAnnotations(res.Time);
|
ShowTimeAnnotations(res.Time);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ public class MainWindowEventHandler :
|
|||||||
private readonly MainWindow _mainWindow;
|
private readonly MainWindow _mainWindow;
|
||||||
private readonly FormState _formState;
|
private readonly FormState _formState;
|
||||||
private readonly Config _config;
|
private readonly Config _config;
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
private readonly IGalleryManager _galleryManager;
|
||||||
|
private readonly DatasetExplorer _datasetExplorer;
|
||||||
private readonly ILogger<MainWindowEventHandler> _logger;
|
private readonly ILogger<MainWindowEventHandler> _logger;
|
||||||
|
|
||||||
private const int STEP = 20;
|
private const int STEP = 20;
|
||||||
@@ -42,6 +45,9 @@ public class MainWindowEventHandler :
|
|||||||
MainWindow mainWindow,
|
MainWindow mainWindow,
|
||||||
FormState formState,
|
FormState formState,
|
||||||
Config config,
|
Config config,
|
||||||
|
IMediator mediator,
|
||||||
|
IGalleryManager galleryManager,
|
||||||
|
DatasetExplorer datasetExplorer,
|
||||||
ILogger<MainWindowEventHandler> logger)
|
ILogger<MainWindowEventHandler> logger)
|
||||||
{
|
{
|
||||||
_libVLC = libVLC;
|
_libVLC = libVLC;
|
||||||
@@ -49,6 +55,9 @@ public class MainWindowEventHandler :
|
|||||||
_mainWindow = mainWindow;
|
_mainWindow = mainWindow;
|
||||||
_formState = formState;
|
_formState = formState;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
_mediator = mediator;
|
||||||
|
_galleryManager = galleryManager;
|
||||||
|
_datasetExplorer = datasetExplorer;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +94,9 @@ public class MainWindowEventHandler :
|
|||||||
if (_keysControlEnumDict.TryGetValue(key, out var value))
|
if (_keysControlEnumDict.TryGetValue(key, out var value))
|
||||||
await ControlPlayback(value);
|
await ControlPlayback(value);
|
||||||
|
|
||||||
|
if (key == Key.A)
|
||||||
|
await _mediator.Send( new AIDetectEvent(), cancellationToken);
|
||||||
|
|
||||||
await VolumeControl(key);
|
await VolumeControl(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,5 +271,11 @@ public class MainWindowEventHandler :
|
|||||||
File.Copy(_formState.CurrentMedia.Path, destinationPath, overwrite: true);
|
File.Copy(_formState.CurrentMedia.Path, destinationPath, overwrite: true);
|
||||||
await NextMedia();
|
await NextMedia();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var thumbnailDto = await _galleryManager.CreateThumbnail(destinationPath);
|
||||||
|
var selectedClass = ((AnnotationClass?)_datasetExplorer.LvClasses.SelectedItem)?.Id;
|
||||||
|
|
||||||
|
if (selectedClass != null && (selectedClass == -1 || currentAnns.Any(x => x.ClassNumber == selectedClass)))
|
||||||
|
_datasetExplorer.ThumbnailsDtos.Insert(0, thumbnailDto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,5 +35,6 @@
|
|||||||
"RightPanelWidth": 300,
|
"RightPanelWidth": 300,
|
||||||
"ShowHelpOnStart": false,
|
"ShowHelpOnStart": false,
|
||||||
"VideoFormats": ["mov", "mp4"],
|
"VideoFormats": ["mov", "mp4"],
|
||||||
"ImageFormats": ["jpg", "jpeg", "png", "bmp", "gif"]
|
"ImageFormats": ["jpg", "jpeg", "png", "bmp", "gif"],
|
||||||
|
"AIModelPath": "D:\\dev\\azaion\\azaion_2024-09-19.onnx"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user