mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 18:26:31 +00:00
fix ai detection bugs #2
This commit is contained in:
@@ -13,12 +13,9 @@ public class AnnotationResult
|
|||||||
[JsonProperty(PropertyName = "t")]
|
[JsonProperty(PropertyName = "t")]
|
||||||
public TimeSpan Time { get; set; }
|
public TimeSpan Time { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "p")]
|
|
||||||
public double Percentage { get; set; }
|
|
||||||
|
|
||||||
public double Lat { get; set; }
|
public double Lat { get; set; }
|
||||||
public double Lon { get; set; }
|
public double Lon { get; set; }
|
||||||
public List<YoloLabel> Labels { get; set; } = new();
|
public List<Detection> Detections { get; set; } = new();
|
||||||
|
|
||||||
#region For Display in the grid
|
#region For Display in the grid
|
||||||
|
|
||||||
@@ -32,10 +29,10 @@ public class AnnotationResult
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (Labels.Count == 0)
|
if (Detections.Count == 0)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
var groups = Labels.Select(x => x.ClassNumber).GroupBy(x => x).ToList();
|
var groups = Detections.Select(x => x.ClassNumber).GroupBy(x => x).ToList();
|
||||||
return groups.Count > 1
|
return groups.Count > 1
|
||||||
? string.Join(",", groups.Select(x => x.Key + 1))
|
? string.Join(",", groups.Select(x => x.Key + 1))
|
||||||
: _config.AnnotationClassesDict[groups.FirstOrDefault().Key].Name;
|
: _config.AnnotationClassesDict[groups.FirstOrDefault().Key].Name;
|
||||||
@@ -49,10 +46,10 @@ public class AnnotationResult
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
var defaultColor = (Color)ColorConverter.ConvertFromString("#404040");
|
var defaultColor = (Color)ColorConverter.ConvertFromString("#404040");
|
||||||
if (Labels.Count == 0)
|
if (Detections.Count == 0)
|
||||||
return defaultColor;
|
return defaultColor;
|
||||||
|
|
||||||
var groups = Labels.Select(x => x.ClassNumber).GroupBy(x => x).ToList();
|
var groups = Detections.Select(x => x.ClassNumber).GroupBy(x => x).ToList();
|
||||||
|
|
||||||
return groups.Count > 1
|
return groups.Count > 1
|
||||||
? defaultColor
|
? defaultColor
|
||||||
@@ -64,12 +61,11 @@ public class AnnotationResult
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public AnnotationResult() { }
|
public AnnotationResult() { }
|
||||||
public AnnotationResult(TimeSpan time, string timeName, List<YoloLabel> labels, Config config)
|
public AnnotationResult(TimeSpan time, string timeName, List<Detection> detections, Config config)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
Labels = labels;
|
Detections = detections;
|
||||||
Time = time;
|
Time = time;
|
||||||
Image = $"{timeName}.jpg";
|
Image = $"{timeName}.jpg";
|
||||||
Percentage = 100;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ public class VLCFrameExtractor(LibVLC libVLC)
|
|||||||
|
|
||||||
if (_frameCounter > 20 && _frameCounter % 10 == 0)
|
if (_frameCounter > 20 && _frameCounter % 10 == 0)
|
||||||
{
|
{
|
||||||
var msToAdd = (_frameCounter - _lastFrame) * (_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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,8 +144,8 @@ public class GalleryManager : IGalleryManager
|
|||||||
var size = new Size(originalImage.Width, originalImage.Height);
|
var size = new Size(originalImage.Width, originalImage.Height);
|
||||||
if (!File.Exists(labelName))
|
if (!File.Exists(labelName))
|
||||||
{
|
{
|
||||||
File.Move(imgPath, Path.Combine(_config.UnknownImages, imgName));
|
File.Delete(imgPath);
|
||||||
_logger.LogInformation($"No labels found for image {imgName}! Moved image to the {_config.UnknownImages} folder.");
|
_logger.LogInformation($"No labels found for image {imgName}! Image deleted!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var labels = (await YoloLabel.ReadFromFile(labelName, cancellationToken))
|
var labels = (await YoloLabel.ReadFromFile(labelName, cancellationToken))
|
||||||
|
|||||||
@@ -206,32 +206,34 @@ public partial class MainWindow
|
|||||||
DgAnnotations.MouseDoubleClick += (sender, args) =>
|
DgAnnotations.MouseDoubleClick += (sender, args) =>
|
||||||
{
|
{
|
||||||
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;
|
OpenAnnotationResult((AnnotationResult)dgRow!.Item);
|
||||||
_mediaPlayer.SetPause(true);
|
|
||||||
Editor.RemoveAllAnns();
|
|
||||||
_mediaPlayer.Time = (long)res.Time.TotalMilliseconds;
|
|
||||||
ShowTimeAnnotations(res.Time, showImage: true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DgAnnotations.KeyUp += (sender, args) =>
|
DgAnnotations.KeyUp += (sender, args) =>
|
||||||
{
|
{
|
||||||
if (args.Key != Key.Delete)
|
switch (args.Key)
|
||||||
return;
|
|
||||||
|
|
||||||
var result = MessageBox.Show("Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.OKCancel, MessageBoxImage.Question);
|
|
||||||
if (result != MessageBoxResult.OK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var res = DgAnnotations.SelectedItems.Cast<AnnotationResult>().ToList();
|
|
||||||
foreach (var annotationResult in res)
|
|
||||||
{
|
{
|
||||||
var imgName = Path.GetFileNameWithoutExtension(annotationResult.Image);
|
case Key.Up:
|
||||||
var thumbnailPath = Path.Combine(_config.ThumbnailsDirectory, $"{imgName}{Config.THUMBNAIL_PREFIX}.jpg");
|
case Key.Down: //cursor is already moved by system behaviour
|
||||||
File.Delete(annotationResult.Image);
|
OpenAnnotationResult((AnnotationResult)DgAnnotations.SelectedItem);
|
||||||
File.Delete(Path.Combine(_config.LabelsDirectory, $"{imgName}.txt"));
|
break;
|
||||||
File.Delete(thumbnailPath);
|
case Key.Delete:
|
||||||
_formState.AnnotationResults.Remove(annotationResult);
|
var result = MessageBox.Show("Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.OKCancel, MessageBoxImage.Question);
|
||||||
Annotations.Remove(Annotations.Query(annotationResult.Time));
|
if (result != MessageBoxResult.OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var res = DgAnnotations.SelectedItems.Cast<AnnotationResult>().ToList();
|
||||||
|
foreach (var annotationResult in res)
|
||||||
|
{
|
||||||
|
var imgName = Path.GetFileNameWithoutExtension(annotationResult.Image);
|
||||||
|
var thumbnailPath = Path.Combine(_config.ThumbnailsDirectory, $"{imgName}{Config.THUMBNAIL_PREFIX}.jpg");
|
||||||
|
File.Delete(annotationResult.Image);
|
||||||
|
File.Delete(Path.Combine(_config.LabelsDirectory, $"{imgName}.txt"));
|
||||||
|
File.Delete(thumbnailPath);
|
||||||
|
_formState.AnnotationResults.Remove(annotationResult);
|
||||||
|
Annotations.Remove(Annotations.Query(annotationResult.Time));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -240,6 +242,21 @@ public partial class MainWindow
|
|||||||
DgAnnotations.ItemsSource = _formState.AnnotationResults;
|
DgAnnotations.ItemsSource = _formState.AnnotationResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OpenAnnotationResult(AnnotationResult res)
|
||||||
|
{
|
||||||
|
_mediaPlayer.SetPause(true);
|
||||||
|
Editor.RemoveAllAnns();
|
||||||
|
_mediaPlayer.Time = (long)res.Time.TotalMilliseconds;
|
||||||
|
|
||||||
|
Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
VideoSlider.Value = _mediaPlayer.Position * VideoSlider.Maximum;
|
||||||
|
StatusClock.Text = $"{TimeSpan.FromMilliseconds(_mediaPlayer.Time):mm\\:ss} / {_formState.CurrentVideoLength:mm\\:ss}";
|
||||||
|
Editor.ClearExpiredAnnotations(res.Time);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAnnotationsToCanvas(res.Time, res.Detections, showImage: true);
|
||||||
|
}
|
||||||
private async Task SaveUserSettings()
|
private async Task SaveUserSettings()
|
||||||
{
|
{
|
||||||
if (_suspendLayout)
|
if (_suspendLayout)
|
||||||
@@ -256,7 +273,7 @@ public partial class MainWindow
|
|||||||
}, TimeSpan.FromSeconds(5));
|
}, TimeSpan.FromSeconds(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowTimeAnnotations(TimeSpan time, bool showImage = false)
|
private void ShowTimeAnnotations(TimeSpan time)
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(() =>
|
Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
@@ -266,7 +283,7 @@ public partial class MainWindow
|
|||||||
});
|
});
|
||||||
|
|
||||||
var annotations = Annotations.Query(time).SelectMany(x => x).Select(x => new Detection(x));
|
var annotations = Annotations.Query(time).SelectMany(x => x).Select(x => new Detection(x));
|
||||||
AddAnnotationsToCanvas(time, annotations, showImage);
|
AddAnnotationsToCanvas(time, annotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddAnnotationsToCanvas(TimeSpan? time, IEnumerable<Detection> labels, bool showImage = false)
|
private void AddAnnotationsToCanvas(TimeSpan? time, IEnumerable<Detection> labels, bool showImage = false)
|
||||||
@@ -316,11 +333,14 @@ public partial class MainWindow
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddAnnotations(TimeSpan? time, List<YoloLabel> annotations, CancellationToken ct = default)
|
public async Task AddAnnotations(TimeSpan? time, List<YoloLabel> annotations, CancellationToken ct = default)
|
||||||
|
=> await AddAnnotations(time, annotations.Select(x => new Detection(x)).ToList(), ct);
|
||||||
|
|
||||||
|
public async Task AddAnnotations(TimeSpan? time, List<Detection> annotations, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var timeValue = time ?? TimeSpan.FromMinutes(0);
|
var timeValue = time ?? TimeSpan.FromMinutes(0);
|
||||||
var previousAnnotations = Annotations.Query(timeValue);
|
var previousAnnotations = Annotations.Query(timeValue);
|
||||||
Annotations.Remove(previousAnnotations);
|
Annotations.Remove(previousAnnotations);
|
||||||
Annotations.Add(timeValue.Subtract(_thresholdBefore), timeValue.Add(_thresholdAfter), annotations);
|
Annotations.Add(timeValue.Subtract(_thresholdBefore), timeValue.Add(_thresholdAfter), annotations.Cast<YoloLabel>().ToList());
|
||||||
|
|
||||||
var existingResult = _formState.AnnotationResults.FirstOrDefault(x => x.Time == time);
|
var existingResult = _formState.AnnotationResults.FirstOrDefault(x => x.Time == time);
|
||||||
if (existingResult != null)
|
if (existingResult != null)
|
||||||
@@ -633,7 +653,7 @@ public partial class MainWindow
|
|||||||
Editor.Background = new ImageBrush { ImageSource = await imgPath.OpenImage() };
|
Editor.Background = new ImageBrush { ImageSource = await imgPath.OpenImage() };
|
||||||
Editor.RemoveAllAnns();
|
Editor.RemoveAllAnns();
|
||||||
AddAnnotationsToCanvas(time, detections, true);
|
AddAnnotationsToCanvas(time, detections, true);
|
||||||
await AddAnnotations(timeframe.Time, detections.Cast<YoloLabel>().ToList(), token);
|
await AddAnnotations(timeframe.Time, detections, token);
|
||||||
|
|
||||||
var log = string.Join(Environment.NewLine, detections.Select(det =>
|
var log = string.Join(Environment.NewLine, detections.Select(det =>
|
||||||
$"{_config.AnnotationClassesDict[det.ClassNumber].Name}: " +
|
$"{_config.AnnotationClassesDict[det.ClassNumber].Name}: " +
|
||||||
|
|||||||
@@ -243,6 +243,8 @@ public class MainWindowEventHandler :
|
|||||||
|
|
||||||
private async Task SaveAnnotations()
|
private async Task SaveAnnotations()
|
||||||
{
|
{
|
||||||
|
var annGridSelectedIndex = _mainWindow.DgAnnotations.SelectedIndex;
|
||||||
|
|
||||||
if (_formState.CurrentMedia == null)
|
if (_formState.CurrentMedia == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -270,14 +272,17 @@ public class MainWindowEventHandler :
|
|||||||
//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.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0));
|
||||||
_formState.BackgroundShown = false;
|
_formState.BackgroundShown = false;
|
||||||
|
|
||||||
|
var annGrid = _mainWindow.DgAnnotations;
|
||||||
|
annGrid.SelectedIndex = Math.Min(annGrid.Items.Count, annGridSelectedIndex + 1);
|
||||||
|
_mainWindow.OpenAnnotationResult((AnnotationResult)annGrid.SelectedItem);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var resultHeight = (uint)Math.Round(RESULT_WIDTH / _formState.CurrentVideoSize.Width * _formState.CurrentVideoSize.Height);
|
var resultHeight = (uint)Math.Round(RESULT_WIDTH / _formState.CurrentVideoSize.Width * _formState.CurrentVideoSize.Height);
|
||||||
_mediaPlayer.TakeSnapshot(0, destinationPath, RESULT_WIDTH, resultHeight);
|
_mediaPlayer.TakeSnapshot(0, destinationPath, RESULT_WIDTH, resultHeight);
|
||||||
|
_mediaPlayer.Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
_mediaPlayer.Play();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user