mirror of
https://github.com/azaion/annotations.git
synced 2026-04-23 01:16:31 +00:00
polish autodetection
This commit is contained in:
@@ -3,27 +3,26 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:extensions="clr-namespace:Azaion.Annotator.Extensions"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
WindowStyle="SingleBorderWindow"
|
WindowStyle="SingleBorderWindow"
|
||||||
ResizeMode="NoResize"
|
ResizeMode="NoResize"
|
||||||
Title="AutodetectDialog"
|
Title="Розпізнавання"
|
||||||
Height="250" Width="420"
|
Height="247" Width="400"
|
||||||
Background="LightGray">
|
Background="LightGray">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="40"></RowDefinition>
|
|
||||||
<RowDefinition Height="*"></RowDefinition>
|
<RowDefinition Height="*"></RowDefinition>
|
||||||
<RowDefinition Height="70"></RowDefinition>
|
<RowDefinition Height="70"></RowDefinition>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Grid.Row="0"
|
<ScrollViewer Grid.Row="0"
|
||||||
FontSize="18" TextAlignment="Center" Padding="0 10 0 0">Йде розпізнавання...</TextBlock>
|
extensions:ScrollViewerExtensions.AlwaysScrollToEnd="True">
|
||||||
<ScrollViewer Grid.Row="1">
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Name="TextBlockLog"
|
Name="TextBlockLog"
|
||||||
Padding="10 10 5 5"/>
|
Padding="10 10 5 5"/>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<Button Grid.Row="2"
|
<Button Grid.Row="1"
|
||||||
Width="50" Height="50" ToolTip="Видалити всі аннотації. Клавіша: [X]"
|
Width="50" Height="50" ToolTip="Зупинити розпізнавання. [Esc]"
|
||||||
Background="LightGray" BorderBrush="LightGray"
|
Background="LightGray" BorderBrush="LightGray"
|
||||||
Click="ButtonBase_OnClick">
|
Click="ButtonBase_OnClick">
|
||||||
<Path Stretch="Fill" Fill="Gray" Data="M12,2 C17.5228,2 22,6.47715 22,12 C22,17.5228 17.5228,22 12,22 C6.47715,22 2,17.5228 2,12 C2,6.47715 6.47715,2 12,2 Z
|
<Path Stretch="Fill" Fill="Gray" Data="M12,2 C17.5228,2 22,6.47715 22,12 C22,17.5228 17.5228,22 12,22 C6.47715,22 2,17.5228 2,12 C2,6.47715 6.47715,2 12,2 Z
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
namespace Azaion.Annotator;
|
namespace Azaion.Annotator;
|
||||||
|
|
||||||
@@ -7,13 +8,15 @@ public partial class AutodetectDialog : Window
|
|||||||
public AutodetectDialog()
|
public AutodetectDialog()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
KeyUp += (sender, args) =>
|
||||||
|
{
|
||||||
|
if (args.Key == Key.Escape)
|
||||||
|
Close();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Log(string message) =>
|
public void Log(string message) =>
|
||||||
TextBlockLog.Text = TextBlockLog.Text + Environment.NewLine + message;
|
TextBlockLog.Text = TextBlockLog.Text + Environment.NewLine + message;
|
||||||
|
|
||||||
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
|
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) => Close();
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,7 @@ public class AnnotationControl : Border
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_grid.Background = value.ColorBrush;
|
_grid.Background = value.ColorBrush;
|
||||||
|
_probabilityLabel.Background = value.ColorBrush;
|
||||||
_classNameLabel.Text = value.Name;
|
_classNameLabel.Text = value.Name;
|
||||||
_annotationClass = value;
|
_annotationClass = value;
|
||||||
}
|
}
|
||||||
@@ -59,10 +60,12 @@ public class AnnotationControl : Border
|
|||||||
};
|
};
|
||||||
_probabilityLabel = new Label
|
_probabilityLabel = new Label
|
||||||
{
|
{
|
||||||
Content = probability?.ToString("F1") ?? string.Empty,
|
Content = probability.HasValue ? $"{probability.Value:F0}%" : string.Empty,
|
||||||
HorizontalAlignment = HorizontalAlignment.Right,
|
HorizontalAlignment = HorizontalAlignment.Right,
|
||||||
VerticalAlignment = VerticalAlignment.Top,
|
VerticalAlignment = VerticalAlignment.Top,
|
||||||
Margin = new Thickness(0, -15, 0, 0),
|
Margin = new Thickness(0, -32, 0, 0),
|
||||||
|
FontSize = 16,
|
||||||
|
Visibility = Visibility.Visible
|
||||||
};
|
};
|
||||||
_selectionFrame = new Rectangle
|
_selectionFrame = new Rectangle
|
||||||
{
|
{
|
||||||
@@ -81,6 +84,7 @@ public class AnnotationControl : Border
|
|||||||
{
|
{
|
||||||
_selectionFrame,
|
_selectionFrame,
|
||||||
_classNameLabel,
|
_classNameLabel,
|
||||||
|
_probabilityLabel,
|
||||||
AddRect("rLT", HorizontalAlignment.Left, VerticalAlignment.Top, Cursors.SizeNWSE),
|
AddRect("rLT", HorizontalAlignment.Left, VerticalAlignment.Top, Cursors.SizeNWSE),
|
||||||
AddRect("rCT", HorizontalAlignment.Center, VerticalAlignment.Top, Cursors.SizeNS),
|
AddRect("rCT", HorizontalAlignment.Center, VerticalAlignment.Top, Cursors.SizeNS),
|
||||||
AddRect("rRT", HorizontalAlignment.Right, VerticalAlignment.Top, Cursors.SizeNESW),
|
AddRect("rRT", HorizontalAlignment.Right, VerticalAlignment.Top, Cursors.SizeNESW),
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace Azaion.Annotator.Extensions;
|
||||||
|
|
||||||
|
public class ScrollViewerExtensions
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty AlwaysScrollToEndProperty =
|
||||||
|
DependencyProperty.RegisterAttached("AlwaysScrollToEnd", typeof(bool), typeof(ScrollViewerExtensions), new PropertyMetadata(false, AlwaysScrollToEndChanged));
|
||||||
|
|
||||||
|
private static bool _autoScroll;
|
||||||
|
|
||||||
|
private static void AlwaysScrollToEndChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is not ScrollViewer scroll)
|
||||||
|
throw new InvalidOperationException("The attached AlwaysScrollToEnd property can only be applied to ScrollViewer instances.");
|
||||||
|
|
||||||
|
var alwaysScrollToEnd = e.NewValue != null && (bool)e.NewValue;
|
||||||
|
if (alwaysScrollToEnd)
|
||||||
|
{
|
||||||
|
scroll.ScrollToEnd();
|
||||||
|
scroll.ScrollChanged += ScrollChanged;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
scroll.ScrollChanged -= ScrollChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GetAlwaysScrollToEnd(ScrollViewer scroll)
|
||||||
|
{
|
||||||
|
if (scroll == null)
|
||||||
|
throw new ArgumentNullException("scroll");
|
||||||
|
return (bool)scroll.GetValue(AlwaysScrollToEndProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetAlwaysScrollToEnd(ScrollViewer scroll, bool alwaysScrollToEnd)
|
||||||
|
{
|
||||||
|
if (scroll == null)
|
||||||
|
throw new ArgumentNullException("scroll");
|
||||||
|
scroll.SetValue(AlwaysScrollToEndProperty, alwaysScrollToEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ScrollChanged(object sender, ScrollChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var scroll = sender as ScrollViewer;
|
||||||
|
if (scroll == null)
|
||||||
|
throw new InvalidOperationException("The attached AlwaysScrollToEnd property can only be applied to ScrollViewer instances.");
|
||||||
|
|
||||||
|
if (e.ExtentHeightChange == 0)
|
||||||
|
_autoScroll = scroll.VerticalOffset == scroll.ScrollableHeight;
|
||||||
|
|
||||||
|
if (_autoScroll && e.ExtentHeightChange != 0)
|
||||||
|
scroll.ScrollToVerticalOffset(scroll.ExtentHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,11 +47,6 @@ public class VLCFrameExtractor(LibVLC libVLC)
|
|||||||
_width = videoTrack.Data.Video.Width;
|
_width = videoTrack.Data.Video.Width;
|
||||||
_height = videoTrack.Data.Video.Height;
|
_height = videoTrack.Data.Video.Height;
|
||||||
|
|
||||||
//rescaling to DEFAULT_WIDTH
|
|
||||||
//TODO: probably rescaling is not necessary, should be checked
|
|
||||||
//_width = DEFAULT_WIDTH;
|
|
||||||
//_height = (uint)(DEFAULT_WIDTH * _height / (double)_width);
|
|
||||||
|
|
||||||
_pitch = Align32(_width * RGBA_BYTES);
|
_pitch = Align32(_width * RGBA_BYTES);
|
||||||
_lines = Align32(_height);
|
_lines = Align32(_height);
|
||||||
_mediaPlayer.SetRate(PLAYBACK_RATE);
|
_mediaPlayer.SetRate(PLAYBACK_RATE);
|
||||||
@@ -81,7 +76,6 @@ public class VLCFrameExtractor(LibVLC libVLC)
|
|||||||
|
|
||||||
yield return (frameInfo.Time, ms);
|
yield return (frameInfo.Time, ms);
|
||||||
|
|
||||||
Console.WriteLine($"Queue size: {FramesQueue.Count}");
|
|
||||||
frameInfo.Bitmap?.Dispose();
|
frameInfo.Bitmap?.Dispose();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -489,9 +489,10 @@ public partial class MainWindow
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.Play));
|
_mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.Play));
|
||||||
|
_mediaPlayer.SetPause(true);
|
||||||
|
|
||||||
var mediaInfo = (MediaFileInfo)LvFiles.SelectedItem;
|
var mediaInfo = (MediaFileInfo)LvFiles.SelectedItem;
|
||||||
_formState.CurrentMedia = mediaInfo;
|
_formState.CurrentMedia = mediaInfo;
|
||||||
_mediaPlayer.Stop();
|
|
||||||
var path = mediaInfo.Path;
|
var path = mediaInfo.Path;
|
||||||
|
|
||||||
var manualCancellationSource = new CancellationTokenSource();
|
var manualCancellationSource = new CancellationTokenSource();
|
||||||
@@ -505,20 +506,28 @@ public partial class MainWindow
|
|||||||
_autoDetectDialog.Closing += (_, _) =>
|
_autoDetectDialog.Closing += (_, _) =>
|
||||||
{
|
{
|
||||||
manualCancellationSource.Cancel();
|
manualCancellationSource.Cancel();
|
||||||
_mediaPlayer.Stop();
|
_mediaPlayer.SeekTo(TimeSpan.Zero);
|
||||||
|
Editor.RemoveAllAnns();
|
||||||
};
|
};
|
||||||
_autoDetectDialog.Top = Height - _autoDetectDialog.Height - 80;
|
_autoDetectDialog.Top = Height - _autoDetectDialog.Height - 80;
|
||||||
|
_autoDetectDialog.Left = 5;
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
using var detector = new YOLODetector(_config);
|
using var detector = new YOLODetector(_config);
|
||||||
Dispatcher.Invoke(() => _autoDetectDialog.Log("Ініціалізація AI..."));
|
Dispatcher.Invoke(() => _autoDetectDialog.Log("Ініціалізація AI..."));
|
||||||
|
var prevSeekTime = 0.0;
|
||||||
|
|
||||||
await foreach (var timeframe in _vlcFrameExtractor.ExtractFrames(path, token))
|
await foreach (var timeframe in _vlcFrameExtractor.ExtractFrames(path, token))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var detections = _aiDetector.Detect(timeframe.Stream);
|
var detections = _aiDetector.Detect(timeframe.Stream);
|
||||||
|
if (timeframe.Time.TotalSeconds > prevSeekTime + 1)
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(() => SeekTo(timeframe.Time));
|
||||||
|
prevSeekTime = timeframe.Time.TotalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsValidDetection(timeframe.Time, detections))
|
if (!IsValidDetection(timeframe.Time, detections))
|
||||||
continue;
|
continue;
|
||||||
@@ -533,9 +542,8 @@ public partial class MainWindow
|
|||||||
}
|
}
|
||||||
_autoDetectDialog.Close();
|
_autoDetectDialog.Close();
|
||||||
}, token);
|
}, token);
|
||||||
|
|
||||||
|
|
||||||
_autoDetectDialog.ShowDialog();
|
_autoDetectDialog.ShowDialog();
|
||||||
|
|
||||||
Dispatcher.Invoke(() => Editor.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)));
|
Dispatcher.Invoke(() => Editor.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,6 +621,7 @@ public partial class MainWindow
|
|||||||
$"xy=({det.Label.CenterX:F2},{det.Label.CenterY:F2}), " +
|
$"xy=({det.Label.CenterX:F2},{det.Label.CenterY:F2}), " +
|
||||||
$"size=({det.Label.Width:F2}, {det.Label.Height:F2}), " +
|
$"size=({det.Label.Width:F2}, {det.Label.Height:F2}), " +
|
||||||
$"prob: {det.Probability:F1}%"));
|
$"prob: {det.Probability:F1}%"));
|
||||||
|
|
||||||
Dispatcher.Invoke(() => _autoDetectDialog.Log(log));
|
Dispatcher.Invoke(() => _autoDetectDialog.Log(log));
|
||||||
|
|
||||||
var thumbnailDto = await _galleryManager.CreateThumbnail(imgPath, token);
|
var thumbnailDto = await _galleryManager.CreateThumbnail(imgPath, token);
|
||||||
|
|||||||
Reference in New Issue
Block a user