add nth frame to ai recognition to config

This commit is contained in:
Alex Bezdieniezhnykh
2024-12-03 11:36:20 +02:00
parent 0b38d9b24c
commit 3944df8efe
12 changed files with 81 additions and 29 deletions
+59 -13
View File
@@ -7,6 +7,7 @@ using System.Windows.Controls;
using System.Windows.Controls.Primitives; using System.Windows.Controls.Primitives;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading; using System.Windows.Threading;
using Azaion.Annotator.DTO; using Azaion.Annotator.DTO;
using Azaion.Annotator.Extensions; using Azaion.Annotator.Extensions;
@@ -187,10 +188,25 @@ public partial class Annotator
OpenAnnotationResult((AnnotationResult)DgAnnotations.SelectedItem); OpenAnnotationResult((AnnotationResult)DgAnnotations.SelectedItem);
break; break;
case Key.Delete: case Key.Delete:
var result = MessageBox.Show("Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.OKCancel, MessageBoxImage.Question); var result = MessageBox.Show(Application.Current.MainWindow, "Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.OKCancel, MessageBoxImage.Question);
if (result != MessageBoxResult.OK) if (result != MessageBoxResult.OK)
return; return;
// var allWindows = Application.Current.Windows.Cast<Window>();
// try
// {
// foreach (var window in allWindows)
// window.IsEnabled = false;
//
// }
// finally
// {
// foreach (var window in allWindows)
// {
// window.IsEnabled = true;
// }
// }
var res = DgAnnotations.SelectedItems.Cast<AnnotationResult>().ToList(); var res = DgAnnotations.SelectedItems.Cast<AnnotationResult>().ToList();
foreach (var annotationResult in res) foreach (var annotationResult in res)
{ {
@@ -506,12 +522,14 @@ public partial class Annotator
private (TimeSpan Time, List<Detection> Detections)? _previousDetection; private (TimeSpan Time, List<Detection> Detections)? _previousDetection;
public void AutoDetect(object sender, RoutedEventArgs e) public async void AutoDetect(object sender, RoutedEventArgs e)
{ {
if (LvFiles.SelectedItem == null) if (LvFiles.Items.IsEmpty)
return; return;
if (LvFiles.SelectedIndex == -1)
LvFiles.SelectedIndex = 0;
_mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.Play)); await _mediator.Publish(new PlaybackControlEvent(PlaybackControlEnum.Play));
_mediaPlayer.SetPause(true); _mediaPlayer.SetPause(true);
var manualCancellationSource = new CancellationTokenSource(); var manualCancellationSource = new CancellationTokenSource();
@@ -528,6 +546,7 @@ public partial class Annotator
_mediaPlayer.SeekTo(TimeSpan.Zero); _mediaPlayer.SeekTo(TimeSpan.Zero);
Editor.RemoveAllAnns(); Editor.RemoveAllAnns();
}; };
_autoDetectDialog.Top = Height - _autoDetectDialog.Height - 80; _autoDetectDialog.Top = Height - _autoDetectDialog.Height - 80;
_autoDetectDialog.Left = 5; _autoDetectDialog.Left = 5;
@@ -535,33 +554,38 @@ public partial class Annotator
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
MediaFileInfo mediaInfo = null!; var mediaInfo = Dispatcher.Invoke(() => (MediaFileInfo)LvFiles.SelectedItem);
Dispatcher.Invoke(() =>
{
mediaInfo = (MediaFileInfo)LvFiles.SelectedItem;
});
while (mediaInfo != null) while (mediaInfo != null)
{ {
_formState.CurrentMedia = mediaInfo; _formState.CurrentMedia = mediaInfo;
await Dispatcher.Invoke(async () => await ReloadAnnotations(token));
if (mediaInfo.MediaType == MediaTypes.Image) if (mediaInfo.MediaType == MediaTypes.Image)
{ {
await DetectImage(mediaInfo, manualCancellationSource, token); await DetectImage(mediaInfo, manualCancellationSource, token);
await Task.Delay(70, token);
} }
else else
await DetectVideo(mediaInfo, manualCancellationSource, token); await DetectVideo(mediaInfo, manualCancellationSource, token);
mediaInfo = Dispatcher.Invoke(() => mediaInfo = Dispatcher.Invoke(() =>
{ {
if (LvFiles.SelectedIndex == LvFiles.Items.Count - 1)
return null;
LvFiles.SelectedIndex += 1; LvFiles.SelectedIndex += 1;
return (MediaFileInfo)LvFiles.SelectedItem; return (MediaFileInfo)LvFiles.SelectedItem;
}); });
} }
Dispatcher.Invoke(() => _autoDetectDialog.Close()); Dispatcher.Invoke(() =>
{
_autoDetectDialog.Close();
_mediaPlayer.Stop();
LvFiles.Items.Refresh();
});
}, token); }, token);
_autoDetectDialog.ShowDialog(); _autoDetectDialog.ShowDialog();
Dispatcher.Invoke(() => Editor.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0))); Dispatcher.Invoke(() => Editor.ResetBackground());
} }
private async Task DetectImage(MediaFileInfo mediaInfo, CancellationTokenSource manualCancellationSource, CancellationToken token) private async Task DetectImage(MediaFileInfo mediaInfo, CancellationTokenSource manualCancellationSource, CancellationToken token)
@@ -571,6 +595,8 @@ public partial class Annotator
var stream = new FileStream(mediaInfo.Path, FileMode.Open); var stream = new FileStream(mediaInfo.Path, FileMode.Open);
var detections = await _aiDetector.Detect(stream, token); var detections = await _aiDetector.Detect(stream, token);
await ProcessDetection((TimeSpan.FromMilliseconds(0), stream), detections, token); await ProcessDetection((TimeSpan.FromMilliseconds(0), stream), detections, token);
if (detections.Count != 0)
mediaInfo.HasAnnotations = true;
} }
catch (Exception e) catch (Exception e)
{ {
@@ -584,18 +610,38 @@ public partial class Annotator
var prevSeekTime = 0.0; var prevSeekTime = 0.0;
await foreach (var timeframe in _vlcFrameExtractor.ExtractFrames(mediaInfo.Path, token)) await foreach (var timeframe in _vlcFrameExtractor.ExtractFrames(mediaInfo.Path, token))
{ {
Console.WriteLine($"Detect time: {timeframe.Time}");
try try
{ {
var detections = await _aiDetector.Detect(timeframe.Stream, token); var detections = await _aiDetector.Detect(timeframe.Stream, token);
var isValid = IsValidDetection(timeframe.Time, detections);
if (timeframe.Time.TotalSeconds > prevSeekTime + 1) if (timeframe.Time.TotalSeconds > prevSeekTime + 1)
{ {
Dispatcher.Invoke(() => SeekTo(timeframe.Time)); Dispatcher.Invoke(() => SeekTo(timeframe.Time));
prevSeekTime = timeframe.Time.TotalSeconds; prevSeekTime = timeframe.Time.TotalSeconds;
if (!isValid) //Show frame anyway
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
timeframe.Stream.Seek(0, SeekOrigin.Begin);
bitmap.StreamSource = timeframe.Stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
Dispatcher.Invoke(() =>
{
Editor.RemoveAllAnns();
Editor.Background = new ImageBrush { ImageSource = bitmap };
});
}
} }
if (!IsValidDetection(timeframe.Time, detections)) if (!isValid)
continue; continue;
mediaInfo.HasAnnotations = true;
await ProcessDetection(timeframe, detections, token); await ProcessDetection(timeframe, detections, token);
} }
catch (Exception ex) catch (Exception ex)
+3 -2
View File
@@ -132,7 +132,7 @@ public class AnnotatorEventHandler(
mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.AnnotationHelp]); mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.AnnotationHelp]);
if (formState.BackgroundTime.HasValue) if (formState.BackgroundTime.HasValue)
{ {
mainWindow.Editor.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)); mainWindow.Editor.ResetBackground();
formState.BackgroundTime = null; formState.BackgroundTime = null;
} }
break; break;
@@ -213,6 +213,7 @@ public class AnnotatorEventHandler(
if (mainWindow.LvFiles.SelectedItem == null) if (mainWindow.LvFiles.SelectedItem == null)
return; return;
var mediaInfo = (MediaFileInfo)mainWindow.LvFiles.SelectedItem; var mediaInfo = (MediaFileInfo)mainWindow.LvFiles.SelectedItem;
mainWindow.Editor.ResetBackground();
formState.CurrentMedia = mediaInfo; formState.CurrentMedia = mediaInfo;
mediaPlayer.Stop(); mediaPlayer.Stop();
@@ -250,7 +251,7 @@ public class AnnotatorEventHandler(
if (formState.BackgroundTime.HasValue) if (formState.BackgroundTime.HasValue)
{ {
//no need to save image, it's already there, just remove background //no need to save image, it's already there, just remove background
mainWindow.Editor.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)); mainWindow.Editor.ResetBackground();
formState.BackgroundTime = null; formState.BackgroundTime = null;
//next item //next item
@@ -2,12 +2,13 @@
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Azaion.Common.DTO.Config;
using LibVLCSharp.Shared; using LibVLCSharp.Shared;
using SkiaSharp; using SkiaSharp;
namespace Azaion.Annotator.Extensions; namespace Azaion.Annotator.Extensions;
public class VLCFrameExtractor(LibVLC libVLC) public class VLCFrameExtractor(LibVLC libVLC, AIRecognitionConfig config)
{ {
private const uint RGBA_BYTES = 4; private const uint RGBA_BYTES = 4;
private const int PLAYBACK_RATE = 4; private const int PLAYBACK_RATE = 4;
@@ -104,10 +105,11 @@ public class VLCFrameExtractor(LibVLC libVLC)
_lastFrameTimestamp = playerTime; _lastFrameTimestamp = playerTime;
} }
if (_frameCounter > 20 && _frameCounter % 10 == 0) if (_frameCounter > 20 && _frameCounter % config.FramePeriodRecognition == 0)
{ {
var msToAdd = (_frameCounter - _lastFrame) * (_lastFrame == 0 ? 0 : _lastFrameTimestamp.TotalMilliseconds / _lastFrame); var msToAdd = (_frameCounter - _lastFrame) * (_lastFrame == 0 ? 0 : _lastFrameTimestamp.TotalMilliseconds / _lastFrame);
var time = _lastFrameTimestamp.Add(TimeSpan.FromMilliseconds(msToAdd)); var time = _lastFrameTimestamp.Add(TimeSpan.FromMilliseconds(msToAdd));
FramesQueue.Enqueue(new FrameInfo(time, _currentBitmap)); FramesQueue.Enqueue(new FrameInfo(time, _currentBitmap));
} }
else else
+4 -3
View File
@@ -50,9 +50,10 @@ public class Constants
# region AIRecognitionConfig # region AIRecognitionConfig
public const double DEFAULT_FRAME_RECOGNITION_SECONDS = 2; public const double DEFAULT_FRAME_RECOGNITION_SECONDS = 2;
public const double TRACKING_DISTANCE_CONFIDENCE = 0.15; public const double TRACKING_DISTANCE_CONFIDENCE = 0.15;
public const double TRACKING_PROBABILITY_INCREASE = 15; public const double TRACKING_PROBABILITY_INCREASE = 15;
public const double TRACKING_INTERSECTION_THRESHOLD = 0.8; public const double TRACKING_INTERSECTION_THRESHOLD = 0.8;
public const int DEFAULT_FRAME_PERIOD_RECOGNITION = 4;
# endregion AIRecognitionConfig # endregion AIRecognitionConfig
+2
View File
@@ -360,4 +360,6 @@ public class CanvasEditor : Canvas
.ToList(); .ToList();
RemoveAnnotations(expiredAnns); RemoveAnnotations(expiredAnns);
} }
public void ResetBackground() => Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0));
} }
@@ -6,4 +6,5 @@ public class AIRecognitionConfig
public double TrackingDistanceConfidence { get; set; } public double TrackingDistanceConfidence { get; set; }
public double TrackingProbabilityIncrease { get; set; } public double TrackingProbabilityIncrease { get; set; }
public double TrackingIntersectionThreshold { get; set; } public double TrackingIntersectionThreshold { get; set; }
public int FramePeriodRecognition { get; set; }
} }
+2 -1
View File
@@ -77,7 +77,8 @@ public class ConfigUpdater : IConfigUpdater
FrameRecognitionSeconds = Constants.DEFAULT_FRAME_RECOGNITION_SECONDS, FrameRecognitionSeconds = Constants.DEFAULT_FRAME_RECOGNITION_SECONDS,
TrackingDistanceConfidence = Constants.TRACKING_DISTANCE_CONFIDENCE, TrackingDistanceConfidence = Constants.TRACKING_DISTANCE_CONFIDENCE,
TrackingProbabilityIncrease = Constants.TRACKING_PROBABILITY_INCREASE, TrackingProbabilityIncrease = Constants.TRACKING_PROBABILITY_INCREASE,
TrackingIntersectionThreshold = Constants.TRACKING_INTERSECTION_THRESHOLD TrackingIntersectionThreshold = Constants.TRACKING_INTERSECTION_THRESHOLD,
FramePeriodRecognition = Constants.DEFAULT_FRAME_PERIOD_RECOGNITION
} }
}; };
Save(appConfig); Save(appConfig);
@@ -1,10 +1,10 @@
using System.IO; using System.IO;
namespace Azaion.Annotator.Extensions; namespace Azaion.Common.Extensions;
public static class DirectoryInfoExtensions public static class DirectoryInfoExtensions
{ {
public static IEnumerable<FileInfo> GetFiles(this DirectoryInfo dir, params string[] searchExtensions) => public static IEnumerable<FileInfo> GetFiles(this DirectoryInfo dir, params string[] searchExtensions) =>
dir.GetFiles("*.*", SearchOption.AllDirectories) dir.GetFiles("*.*", SearchOption.AllDirectories)
.Where(f => searchExtensions.Any(s => f.Name.Contains(s, StringComparison.CurrentCultureIgnoreCase))).ToList(); .Where(f => searchExtensions.Any(s => f.Name.ToLower().Contains(s))).ToList();
} }
+1 -1
View File
@@ -185,7 +185,7 @@ public partial class App
if (windowEnum != WindowEnum.None) if (windowEnum != WindowEnum.None)
return windowEnum; return windowEnum;
element = element.Parent as FrameworkElement; element = (element.Parent ?? element.TemplatedParent) as FrameworkElement;
} }
return WindowEnum.None; return WindowEnum.None;
+1 -3
View File
@@ -8,8 +8,7 @@
WindowStyle="None" WindowStyle="None"
ResizeMode="NoResize" ResizeMode="NoResize"
Top="0" Top="0"
Topmost="True" Topmost="True">
>
<Grid Background="Black"> <Grid Background="Black">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="48"></ColumnDefinition> <ColumnDefinition Width="48"></ColumnDefinition>
@@ -29,7 +28,6 @@
</ItemsPanelTemplate> </ItemsPanelTemplate>
</ListView.ItemsPanel> </ListView.ItemsPanel>
</ListView> </ListView>
<Border Grid.Column="2"> <Border Grid.Column="2">
<Button <Button
VerticalAlignment="Top" VerticalAlignment="Top"
+2 -1
View File
@@ -47,7 +47,8 @@
"FrameRecognitionSeconds" : 2, "FrameRecognitionSeconds" : 2,
"TrackingDistanceConfidence" : 0.15, "TrackingDistanceConfidence" : 0.15,
"TrackingProbabilityIncrease" : 15, "TrackingProbabilityIncrease" : 15,
"TrackingIntersectionThreshold" : 0.8 "TrackingIntersectionThreshold" : 0.8,
"FramePeriodRecognition": 4
}, },
"ThumbnailConfig": { "ThumbnailConfig": {
-1
View File
@@ -38,5 +38,4 @@ curl --location %API_URL%/resources ^
-H "Content-Type: multipart/form-data" ^ -H "Content-Type: multipart/form-data" ^
--form "data=@%FILE2_TO_UPLOAD%" --form "data=@%FILE2_TO_UPLOAD%"
echo Done! echo Done!