add ai recognition: stage 1, works, but doesn't show

This commit is contained in:
Alex Bezdieniezhnykh
2024-10-25 00:17:24 +03:00
parent d2186eb326
commit 596f6db217
13 changed files with 591 additions and 336 deletions
+54
View File
@@ -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>();
}
}
+1
View File
@@ -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();
+1
View File
@@ -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>
+14 -13
View File
@@ -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
+2
View File
@@ -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>>;
+1 -1
View File
@@ -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++;
}
}
+14 -11
View File
@@ -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();
} }
+326 -285
View File
@@ -46,242 +46,259 @@
</Style.Triggers> </Style.Triggers>
</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> <controls:UpdatableProgressBar x:Name="VideoSlider"
<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"
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">
<Path Stretch="Fill" Fill="LightGray" Data="m295.84 146.049-256-144c-4.96-2.784-11.008-2.72-15.904.128-4.928 <Path Stretch="Fill" Fill="LightGray" Data="m295.84 146.049-256-144c-4.96-2.784-11.008-2.72-15.904.128-4.928
2.88-7.936 8.128-7.936 13.824v288c0 5.696 3.008 10.944 7.936 13.824 2.496 1.44 5.28 2.176 8.064 2.176 2.688 2.88-7.936 8.128-7.936 13.824v288c0 5.696 3.008 10.944 7.936 13.824 2.496 1.44 5.28 2.176 8.064 2.176 2.688
0 5.408-.672 7.84-2.048l256-144c5.024-2.848 8.16-8.16 8.16-13.952s-3.136-11.104-8.16-13.952z" /> 0 5.408-.672 7.84-2.048l256-144c5.024-2.848 8.16-8.16 8.16-13.952s-3.136-11.104-8.16-13.952z" />
</Button> </Button>
@@ -302,7 +319,7 @@
</Button> </Button>
<Button Grid.Column="2" Padding="2" Width="25" Height="25" ToolTip="Зупинити перегляд" Background="Black" BorderBrush="Black" <Button Grid.Column="2" Padding="2" Width="25" Height="25" ToolTip="Зупинити перегляд" Background="Black" BorderBrush="Black"
Click="StopClick"> Click="StopClick">
<Path Stretch="Fill" Fill="LightGray" Data="m288 0h-256c-17.632 0-32 14.368-32 32v256c0 17.632 14.368 32 32 32h256c17.632 <Path Stretch="Fill" Fill="LightGray" Data="m288 0h-256c-17.632 0-32 14.368-32 32v256c0 17.632 14.368 32 32 32h256c17.632
0 32-14.368 32-32v-256c0-17.632-14.368-32-32-32z" /> 0 32-14.368 32-32v-256c0-17.632-14.368-32-32-32z" />
</Button> </Button>
<Button Grid.Column="3" Padding="2" Width="25" Height="25" ToolTip="На 1 кадр назад. +[Ctrl] на 5 секунд назад. Клавіша: [Вліво]" Background="Black" BorderBrush="Black" <Button Grid.Column="3" Padding="2" Width="25" Height="25" ToolTip="На 1 кадр назад. +[Ctrl] на 5 секунд назад. Клавіша: [Вліво]" Background="Black" BorderBrush="Black"
@@ -344,7 +361,7 @@
<DrawingImage> <DrawingImage>
<DrawingImage.Drawing> <DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V320 H320 V0 H0 Z"> <DrawingGroup ClipGeometry="M0,0 V320 H320 V0 H0 Z">
<GeometryDrawing Brush="LightGray" Geometry="m30.71 7.29-6-6a1 1 0 0 0 -.71-.29h-2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 <GeometryDrawing Brush="LightGray" Geometry="m30.71 7.29-6-6a1 1 0 0 0 -.71-.29h-2v8a2 2 0 0 1 -2 2h-8a2 2 0 0
1 -2-2v-8h-6a3 3 0 0 0 -3 3v24a3 3 0 0 0 3 3h2v-9a3 3 0 0 1 3-3h14a3 3 0 0 1 3 3v9h2a3 3 0 0 0 3-3v-20a1 1 0 0 0 -.29-.71z" /> 1 -2-2v-8h-6a3 3 0 0 0 -3 3v24a3 3 0 0 0 3 3h2v-9a3 3 0 0 1 3-3h14a3 3 0 0 1 3 3v9h2a3 3 0 0 0 3-3v-20a1 1 0 0 0 -.29-.71z" />
<GeometryDrawing Brush="LightGray" Geometry="m12 1h8v8h-8z" /> <GeometryDrawing Brush="LightGray" Geometry="m12 1h8v8h-8z" />
<GeometryDrawing Brush="LightGray" Geometry="m23 21h-14a1 1 0 0 0 -1 1v9h16v-9a1 1 0 0 0 -1-1z" /> <GeometryDrawing Brush="LightGray" Geometry="m23 21h-14a1 1 0 0 0 -1 1v9h16v-9a1 1 0 0 0 -1-1z" />
@@ -374,23 +391,23 @@
<DrawingImage> <DrawingImage>
<DrawingImage.Drawing> <DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V320 H320 V0 H0 Z"> <DrawingGroup ClipGeometry="M0,0 V320 H320 V0 H0 Z">
<GeometryDrawing Brush="LightGray" Geometry="m66.1455 13.1562c2.2083-4.26338 7.4546-5.92939 11.718-3.72109 4.2702 2.21179 <GeometryDrawing Brush="LightGray" Geometry="m66.1455 13.1562c2.2083-4.26338 7.4546-5.92939 11.718-3.72109 4.2702 2.21179
5.9335 7.47029 3.7121 11.73549l-8.9288 17.1434c-.3573.6862-.8001 1.3124-1.312 1.8677 2.44 3.6128 3.1963 8.2582 1.6501 5.9335 7.47029 3.7121 11.73549l-8.9288 17.1434c-.3573.6862-.8001 1.3124-1.312 1.8677 2.44 3.6128 3.1963 8.2582 1.6501
12.6558-.3523 1.002-.7242 2.0466-1.1108 3.1145-.1645.4546-.6923.659-1.1208.4351l-28.8106-15.0558c-.4666-.2438-.5746-.8639-.2219-1.2547.7171-.7943 12.6558-.3523 1.002-.7242 2.0466-1.1108 3.1145-.1645.4546-.6923.659-1.1208.4351l-28.8106-15.0558c-.4666-.2438-.5746-.8639-.2219-1.2547.7171-.7943
1.4152-1.5917 2.0855-2.3761 3.1513-3.6881 7.8213-5.7743 12.5381-5.6197.0534-.1099.1097-.2193.1689-.3283z" /> 1.4152-1.5917 2.0855-2.3761 3.1513-3.6881 7.8213-5.7743 12.5381-5.6197.0534-.1099.1097-.2193.1689-.3283z" />
<GeometryDrawing Brush="LightGray" Geometry="m37.7187 44.9911c-.3028-.1582-.6723-.1062-.9226.1263-1.7734 1.6478-3.5427 <GeometryDrawing Brush="LightGray" Geometry="m37.7187 44.9911c-.3028-.1582-.6723-.1062-.9226.1263-1.7734 1.6478-3.5427
3.0861-5.1934 4.1101-5.5739 3.4578-10.1819 4.704-13.0435 5.1463-1.6736.2587-3.032 1.3362-3.6937 2.7335-.6912 1.4595-.6391 3.0861-5.1934 4.1101-5.5739 3.4578-10.1819 4.704-13.0435 5.1463-1.6736.2587-3.032 1.3362-3.6937 2.7335-.6912 1.4595-.6391
3.3721.7041 4.8522 1.48 1.6309 3.6724 3.7893 6.8345 6.3861.1854.1523.4298.2121.665.1649 2.2119-.4446 4.5148-.8643 3.3721.7041 4.8522 1.48 1.6309 3.6724 3.7893 6.8345 6.3861.1854.1523.4298.2121.665.1649 2.2119-.4446 4.5148-.8643
6.5245-1.9149.5849-.3058 1.4606-.8505 2.5588-1.7923 1.0935-.9379 2.7579-.8372 3.7175.2247.9595 1.062.8509 2.6831-.2426 6.5245-1.9149.5849-.3058 1.4606-.8505 2.5588-1.7923 1.0935-.9379 2.7579-.8372 3.7175.2247.9595 1.062.8509 2.6831-.2426
3.621-1.3886 1.1908-2.596 1.965-3.5534 2.4655-.7833.4094-1.603.7495-2.4399 1.0396-.6358.2203-.7846 1.0771-.2325 1.4619 3.621-1.3886 1.1908-2.596 1.965-3.5534 2.4655-.7833.4094-1.603.7495-2.4399 1.0396-.6358.2203-.7846 1.0771-.2325 1.4619
1.5928 1.1099 3.3299 2.2689 5.223 3.4729.9682.6158 1.9229 1.1946 2.8588 1.7383.2671.1552.6002.141.8515-.0387 1.351-.9664 1.5928 1.1099 3.3299 2.2689 5.223 3.4729.9682.6158 1.9229 1.1946 2.8588 1.7383.2671.1552.6002.141.8515-.0387 1.351-.9664
2.5145-1.9362 3.463-2.8261 2.1458-2.013 3.9974-4.231 5.4947-6.7819.7286-1.2414 2.3312-1.6783 3.5794-.9757s1.6693 2.2785.9406 2.5145-1.9362 3.463-2.8261 2.1458-2.013 3.9974-4.231 5.4947-6.7819.7286-1.2414 2.3312-1.6783 3.5794-.9757s1.6693 2.2785.9406
3.52c-1.7525 2.9859-3.9213 5.6002-6.4356 7.9591-.4351.4082-.9081.8302-1.4172 1.2601-.4505.3805-.3701 1.1048.1642 1.3543 3.184 3.52c-1.7525 2.9859-3.9213 5.6002-6.4356 7.9591-.4351.4082-.9081.8302-1.4172 1.2601-.4505.3805-.3701 1.1048.1642 1.3543 3.184
1.4867 5.8634 2.4904 7.7071 3.1131 2.6745.9033 5.5327-.1298 7.0673-2.4281 1.9401-2.9057 5.3476-8.3855 8.2732-15.0533.7591-1.7301 1.4867 5.8634 2.4904 7.7071 3.1131 2.6745.9033 5.5327-.1298 7.0673-2.4281 1.9401-2.9057 5.3476-8.3855 8.2732-15.0533.7591-1.7301
1.5313-3.6163 2.2883-5.5494.1485-.3793-.0133-.8092-.3743-.9978z" /> 1.5313-3.6163 2.2883-5.5494.1485-.3793-.0133-.8092-.3743-.9978z" />
<GeometryDrawing Brush="LightGray" Geometry="m22.9737 37.9072c2.0802 0 3.7666-1.6864 3.7666-3.7667 0-2.0802-1.6864-3.7666-3.7666-3.7666-2.0803 <GeometryDrawing Brush="LightGray" Geometry="m22.9737 37.9072c2.0802 0 3.7666-1.6864 3.7666-3.7667 0-2.0802-1.6864-3.7666-3.7666-3.7666-2.0803
0-3.7667 1.6864-3.7667 3.7666 0 2.0803 1.6864 3.7667 3.7667 3.7667z" /> 0-3.7667 1.6864-3.7667 3.7666 0 2.0803 1.6864 3.7667 3.7667 3.7667z" />
<GeometryDrawing Brush="LightGray" Geometry="m12.7198 49.4854c2.0802 0 3.7666-1.6864 3.7666-3.7667 0-2.0802-1.6864-3.7666-3.7666-3.7666-2.0803 <GeometryDrawing Brush="LightGray" Geometry="m12.7198 49.4854c2.0802 0 3.7666-1.6864 3.7666-3.7667 0-2.0802-1.6864-3.7666-3.7666-3.7666-2.0803
0-3.76667 1.6864-3.76668 3.7666 0 2.0803 1.68638 3.7667 3.76668 3.7667z" /> 0-3.76667 1.6864-3.76668 3.7666 0 2.0803 1.68638 3.7667 3.76668 3.7667z" />
</DrawingGroup> </DrawingGroup>
</DrawingImage.Drawing> </DrawingImage.Drawing>
@@ -401,7 +418,7 @@
<Button <Button
x:Name="TurnOffVolumeBtn" x:Name="TurnOffVolumeBtn"
Visibility="Visible" Visibility="Visible"
Grid.Column="8" Padding="2" Width="25" Grid.Column="8" Padding="2" Width="25"
Height="25" Height="25"
ToolTip="Виключити звук. Клавіша: [M]" Background="Black" BorderBrush="Black" ToolTip="Виключити звук. Клавіша: [M]" Background="Black" BorderBrush="Black"
Click="TurnOffVolume"> Click="TurnOffVolume">
@@ -409,20 +426,20 @@
.55558v11.99998c-.00004.1978-.05871.3911-.1686.5555-.10988.1644-.26605.2925-.44875.3682s-.38373.0955-.57768.0569-.37212-.1338-.51197-.2736l-3.707 .55558v11.99998c-.00004.1978-.05871.3911-.1686.5555-.10988.1644-.26605.2925-.44875.3682s-.38373.0955-.57768.0569-.37212-.1338-.51197-.2736l-3.707
-3.707h-2.586c-.26522 0-.51957-.1053-.70711-.2929-.18753-.1875-.29289-.4419-.29289-.7071v-3.99998c0-.26522.10536-.51957.29289-.70711.18754-.18754 -3.707h-2.586c-.26522 0-.51957-.1053-.70711-.2929-.18753-.1875-.29289-.4419-.29289-.7071v-3.99998c0-.26522.10536-.51957.29289-.70711.18754-.18754
.44189-.29289.70711-.29289h2.586l3.707-3.707c.13985-.13994.31805-.23524.51208-.27387.19402-.03863.39515-.01884.57792.05687zm5.274-.147c.1875-.18747 .44189-.29289.70711-.29289h2.586l3.707-3.707c.13985-.13994.31805-.23524.51208-.27387.19402-.03863.39515-.01884.57792.05687zm5.274-.147c.1875-.18747
.4418-.29279.707-.29279s.5195.10532.707.29279c.9298.92765 1.6672 2.02985 2.1699 3.24331.5026 1.21345.7606 2.51425.7591 3.82767.0015 1.3135-.2565 .4418-.29279.707-.29279s.5195.10532.707.29279c.9298.92765 1.6672 2.02985 2.1699 3.24331.5026 1.21345.7606 2.51425.7591 3.82767.0015 1.3135-.2565
2.6143-.7591 3.8277-.5027 1.2135-1.2401 2.3157-2.1699 3.2433-.1886.1822-.4412.283-.7034.2807s-.513-.1075-.6984-.2929-.2906-.4362-.2929-.6984 2.6143-.7591 3.8277-.5027 1.2135-1.2401 2.3157-2.1699 3.2433-.1886.1822-.4412.283-.7034.2807s-.513-.1075-.6984-.2929-.2906-.4362-.2929-.6984
.0985-.5148.2807-.7034c.7441-.7419 1.3342-1.6237 1.7363-2.5945.4022-.9709.6083-2.0117.6067-3.0625 0-2.20998-.894-4.20798-2.343-5.65698-.1875 .0985-.5148.2807-.7034c.7441-.7419 1.3342-1.6237 1.7363-2.5945.4022-.9709.6083-2.0117.6067-3.0625 0-2.20998-.894-4.20798-2.343-5.65698-.1875
-.18753-.2928-.44184-.2928-.707 0-.26517.1053-.51948.2928-.707zm-2.829 2.828c.0929-.09298.2032-.16674.3246-.21706.1214-.05033.2515-.07623.3829 -.18753-.2928-.44184-.2928-.707 0-.26517.1053-.51948.2928-.707zm-2.829 2.828c.0929-.09298.2032-.16674.3246-.21706.1214-.05033.2515-.07623.3829
-.07623s.2615.0259.3829.07623c.1214.05032.2317.12408.3246.21706.5579.55666 1.0003 1.21806 1.3018 1.94621.3015.72814.4562 1.50868.4552 2.29677.001 -.07623s.2615.0259.3829.07623c.1214.05032.2317.12408.3246.21706.5579.55666 1.0003 1.21806 1.3018 1.94621.3015.72814.4562 1.50868.4552 2.29677.001
.7881-.1537 1.5686-.4553 2.2968-.3015.7281-.7439 1.3895-1.3017 1.9462-.1876.1877-.4421.2931-.7075.2931s-.5199-.1054-.7075-.2931c-.1876-.1876 .7881-.1537 1.5686-.4553 2.2968-.3015.7281-.7439 1.3895-1.3017 1.9462-.1876.1877-.4421.2931-.7075.2931s-.5199-.1054-.7075-.2931c-.1876-.1876
-.2931-.4421-.2931-.7075 0-.2653.1055-.5198.2931-.7075.3722-.3708.6673-.8116.8685-1.2969.2011-.4854.3043-1.0057.3035-1.5311.0008-.52537-.1023 -.2931-.4421-.2931-.7075 0-.2653.1055-.5198.2931-.7075.3722-.3708.6673-.8116.8685-1.2969.2011-.4854.3043-1.0057.3035-1.5311.0008-.52537-.1023
-1.04572-.3035-1.53107-.2011-.48536-.4963-.92612-.8685-1.29691-.093-.09288-.1667-.20316-.2171-.32456-.0503-.1214-.0762-.25153-.0762-.38294 -1.04572-.3035-1.53107-.2011-.48536-.4963-.92612-.8685-1.29691-.093-.09288-.1667-.20316-.2171-.32456-.0503-.1214-.0762-.25153-.0762-.38294
0-.13142.0259-.26155.0762-.38294.0504-.1214.1241-.23169.2171-.32456z" /> 0-.13142.0259-.26155.0762-.38294.0504-.1214.1241-.23169.2171-.32456z" />
</Button> </Button>
<Button <Button
x:Name="TurnOnVolumeBtn" x:Name="TurnOnVolumeBtn"
Visibility="Collapsed" Visibility="Collapsed"
Grid.Column="8" Padding="2" Width="25" Grid.Column="8" Padding="2" Width="25"
Height="25" Height="25"
ToolTip="Включити звук. Клавіша: [M]" Background="Black" BorderBrush="Black" ToolTip="Включити звук. Клавіша: [M]" Background="Black" BorderBrush="Black"
Click="TurnOnVolume"> Click="TurnOnVolume">
@@ -431,13 +448,13 @@
<DrawingImage> <DrawingImage>
<DrawingImage.Drawing> <DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V320 H320 V0 H0 Z"> <DrawingGroup ClipGeometry="M0,0 V320 H320 V0 H0 Z">
<GeometryDrawing Brush="LightGray" Geometry="m9.38268 3.07615c.37368.15478.61732.51942.61732.92388v11.99997c0 <GeometryDrawing Brush="LightGray" Geometry="m9.38268 3.07615c.37368.15478.61732.51942.61732.92388v11.99997c0
.4045-.24364.7691-.61732.9239-.37367.1548-.80379.0692-1.08979-.2168l-3.7071-3.7071h-2.58579c-.55228 .4045-.24364.7691-.61732.9239-.37367.1548-.80379.0692-1.08979-.2168l-3.7071-3.7071h-2.58579c-.55228
0-1-.4477-1-1v-3.99997c0-.55229.44772-1 1-1h2.58579l3.7071-3.70711c.286-.286.71612-.37155 1.08979-.21677z" /> 0-1-.4477-1-1v-3.99997c0-.55229.44772-1 1-1h2.58579l3.7071-3.70711c.286-.286.71612-.37155 1.08979-.21677z" />
<GeometryDrawing Brush="LightGray" Geometry="m12.2929 7.29289c.3905-.39052 1.0237-.39052 1.4142 0l1.2929 <GeometryDrawing Brush="LightGray" Geometry="m12.2929 7.29289c.3905-.39052 1.0237-.39052 1.4142 0l1.2929
1.2929 1.2929-1.2929c.3905-.39052 1.0237-.39052 1.4142 0 .3905.39053.3905 1.02369 0 1.41422l-1.2929 1.29289 1.2929 1.2929-1.2929c.3905-.39052 1.0237-.39052 1.4142 0 .3905.39053.3905 1.02369 0 1.41422l-1.2929 1.29289
1.2929 1.2929c.3905.3905.3905 1.0237 0 1.4142s-1.0237.3905-1.4142 0l-1.2929-1.2929-1.2929 1.2929 1.2929c.3905.3905.3905 1.0237 0 1.4142s-1.0237.3905-1.4142 0l-1.2929-1.2929-1.2929
1.2929c-.3905.3905-1.0237.3905-1.4142 0s-.3905-1.0237 0-1.4142l1.2929-1.2929-1.2929-1.29289c-.3905-.39053-.3905-1.02369 1.2929c-.3905.3905-1.0237.3905-1.4142 0s-.3905-1.0237 0-1.4142l1.2929-1.2929-1.2929-1.29289c-.3905-.39053-.3905-1.02369
0-1.41422z" /> 0-1.41422z" />
</DrawingGroup> </DrawingGroup>
</DrawingImage.Drawing> </DrawingImage.Drawing>
@@ -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>
+27 -25
View File
@@ -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;
@@ -123,10 +115,10 @@ public partial class MainWindow
LvClasses.ItemsSource = AnnotationClasses; LvClasses.ItemsSource = AnnotationClasses;
LvClasses.SelectedIndex = 0; LvClasses.SelectedIndex = 0;
if (LvFiles.Items.IsEmpty) if (LvFiles.Items.IsEmpty)
BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.Initial]); BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.Initial]);
if (_config.ShowHelpOnStart) if (_config.ShowHelpOnStart)
_helpWindow.Show(); _helpWindow.Show();
} }
@@ -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);
}); });
} }
@@ -171,7 +164,7 @@ public partial class MainWindow
}; };
LvFiles.MouseDoubleClick += async (_, _) => await _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.Play)); LvFiles.MouseDoubleClick += async (_, _) => await _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.Play));
LvClasses.SelectionChanged += (_, _) => LvClasses.SelectionChanged += (_, _) =>
{ {
var selectedClass = (AnnotationClass)LvClasses.SelectedItem; var selectedClass = (AnnotationClass)LvClasses.SelectedItem;
@@ -194,7 +187,7 @@ public partial class MainWindow
SizeChanged += async (_, _) => await SaveUserSettings(); SizeChanged += async (_, _) => await SaveUserSettings();
LocationChanged += async (_, _) => await SaveUserSettings(); LocationChanged += async (_, _) => await SaveUserSettings();
StateChanged += async (_, _) => await SaveUserSettings(); StateChanged += async (_, _) => await SaveUserSettings();
Editor.FormState = _formState; Editor.FormState = _formState;
Editor.Mediator = _mediator; Editor.Mediator = _mediator;
DgAnnotations.ItemsSource = _formState.AnnotationResults; DgAnnotations.ItemsSource = _formState.AnnotationResults;
@@ -243,13 +236,13 @@ public partial class MainWindow
var labelDir = new DirectoryInfo(_config.LabelsDirectory); var labelDir = new DirectoryInfo(_config.LabelsDirectory);
if (!labelDir.Exists) if (!labelDir.Exists)
return; return;
var labelFiles = labelDir.GetFiles($"{_formState.VideoName}_??????.txt"); var labelFiles = labelDir.GetFiles($"{_formState.VideoName}_??????.txt");
foreach (var file in labelFiles) foreach (var file in labelFiles)
{ {
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
{ {
@@ -325,7 +318,7 @@ public partial class MainWindow
TbFolder.Text = _config.VideosDirectory; TbFolder.Text = _config.VideosDirectory;
BlinkHelp(AllMediaFiles.Count == 0 BlinkHelp(AllMediaFiles.Count == 0
? HelpTexts.HelpTextsDict[HelpTextEnum.Initial] ? HelpTexts.HelpTextsDict[HelpTextEnum.Initial]
: HelpTexts.HelpTextsDict[HelpTextEnum.PlayVideo]); : HelpTexts.HelpTextsDict[HelpTextEnum.PlayVideo]);
} }
@@ -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,15 +382,22 @@ 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)
{ {
_helpWindow.Show(); _helpWindow.Show();
@@ -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);
} }
} }
+2 -1
View File
@@ -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"
} }
+4
View File
@@ -1,2 +1,6 @@
Azaion.Annotator is a tool for annotation videos. Azaion.Annotator is a tool for annotation videos.
Works on Windows only for now Works on Windows only for now
Install:
1. C# dotnet with wpf
2. CUDNN