Added slider for identity confidence. Progress is back.

This commit is contained in:
Alexander Shabarshov 2026-06-09 13:51:13 +01:00
parent f2493c1709
commit e5a9a04265
8 changed files with 72 additions and 18 deletions

View File

@ -122,6 +122,19 @@ public partial class JobViewModel : ObservableObject
}
}
public float IdentityThreshold
{
get => Job.IdentityThreshold;
set
{
if (Math.Abs(Job.IdentityThreshold - value) < 0.001)
return;
Job.IdentityThreshold = value;
OnPropertyChanged();
Task.Run(CreatePreview);
}
}
public string? Mask
{
get => Job.Mask;

View File

@ -54,14 +54,14 @@ public partial class MainViewModel : ViewModelBase
_cancellationTokenSource?.Cancel();
}
public async Task Start()
public Task Start() => Task.Run(async () =>
{
_cancellationTokenSource = new CancellationTokenSource();
try
{
StatusBar.StatusText = "Processing…";
StatusBar.Percent = 0;
TransformMode = true;
StatusBar.Percent = 0;
TransformMode = true;
var files = FileList.Files.ToList();
var jobs = new List<SingleTask>();
@ -84,11 +84,11 @@ public partial class MainViewModel : ViewModelBase
finally
{
StatusBar.StatusText = "Ready…";
StatusBar.Percent = 0;
TransformMode = false;
StatusBar.Percent = 0;
TransformMode = false;
_cancellationTokenSource?.Dispose();
}
}
});
}

View File

@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
@ -26,7 +27,7 @@ public partial class ProgressViewModel : ObservableObject
_mainModel = mainModel;
}
public void ClearProgress(string name, int progressLine)
public void ClearProgress(string name, int progressLine) => Dispatch(() =>
{
lock (_lock)
{
@ -36,8 +37,9 @@ public partial class ProgressViewModel : ObservableObject
NumberOfProcesses -= 1;
Processes[progressLine] = new ProgressInfo("", progressLine, 0, TimeSpan.Zero, 0);
}
}
public void DrawProgress(string name, int progressLine, double progress, TimeSpan eta, double speed)
});
public void DrawProgress(string name, int progressLine, double progress, TimeSpan eta, double speed) => Dispatch(() =>
{
lock (_lock)
{
@ -53,6 +55,18 @@ public partial class ProgressViewModel : ObservableObject
NumberOfProcesses += 1;
Processes[progressLine] = new ProgressInfo(name, progressLine, progress, eta, speed);
}
});
private void Dispatch(Action action)
{
if (Dispatcher.UIThread.CheckAccess())
{
action();
}
else
{
Dispatcher.UIThread.Post(() => action());
}
}
}

View File

@ -12,7 +12,7 @@ x:DataType="vm:InspectorPaneViewModel">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right"
Spacing="8"
Margin="0,10,0,0">
Margin="0,0,10,0">
<Button Content="Apply to Selected"
Command="{Binding ApplyOverridesCommand}"/>
@ -103,7 +103,7 @@ x:DataType="vm:InspectorPaneViewModel">
<!-- ScoreThreshold -->
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="Score Threshold" Width="120"/>
<TextBlock Text="Score threshold" Width="120"/>
<StackPanel Orientation="Vertical" Spacing="4" Width="260">
<Slider Minimum="0"
@ -119,6 +119,25 @@ x:DataType="vm:InspectorPaneViewModel">
HorizontalAlignment="Right"/>
</StackPanel>
</StackPanel>
<!-- ScoreThreshold -->
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="Identity matching threshold" Width="120"/>
<StackPanel Orientation="Vertical" Spacing="4" Width="260">
<Slider Minimum="0"
Maximum="1"
SmallChange="0.01"
LargeChange="0.1"
TickFrequency="0.05"
IsSnapToTickEnabled="False"
Value="{Binding Selected.IdentityThreshold, Mode=TwoWay}"/>
<TextBlock Text="{Binding Selected.IdentityThreshold, StringFormat='0.00'}"
FontSize="10"
HorizontalAlignment="Right"/>
</StackPanel>
</StackPanel>
<!-- DetectAbove -->
<StackPanel Orientation="Horizontal" Spacing="8">

View File

@ -47,6 +47,10 @@
</Grid>
<Grid ColumnDefinitions="*"
IsVisible="{Binding TransformMode}">
<views:ProgressView DataContext="{Binding Progress}"/>
</Grid>
</DockPanel>
</Window>

View File

@ -49,6 +49,10 @@ public class SingleJob
/// </summary>
public float ScoreThreshold { get; set; } = 0.25f;
/// <summary>
/// Identity matching confidence threshold. This is a value between 0.0 and 1.0 that sets the minimum confidence
/// </summary>
public float IdentityThreshold { get; set; } = 0.25f;
/// <summary>
/// Face or human detectors should only report detections if their upper bound starts below this threshold.
/// This is a value between 0.0 and 1.0 mapped to 0..Height.
/// </summary>
@ -144,6 +148,7 @@ public class SingleJob
target.Debug = Debug;
target.Detect = Detect;
target.ScoreThreshold = ScoreThreshold;
target.IdentityThreshold = IdentityThreshold;
target.DetectAbove = DetectAbove;
target.DetectId = DetectId;
target.OverrideTargetDuration = OverrideTargetDuration;

View File

@ -9,17 +9,16 @@ public sealed class IdentityCache
private sealed class Identity
{
public ulong Id;
public float[] Embedding; // EMA
public float[] Embedding = null!; // EMA
public int Samples;
}
private readonly List<Identity> _ids = new();
private ulong _nextId = 1;
private const float Threshold = 0.35f; // good for OSNet
private const float EmaAlpha = 0.2f;
private const float _emaAlpha = 0.2f;
public ulong ResolveId(float[] embedding)
public ulong ResolveId(float[] embedding, float threshold)
{
if (_ids.Count == 0)
return CreateNew(embedding);
@ -37,7 +36,7 @@ public sealed class IdentityCache
}
}
if (bestDist <= Threshold)
if (bestDist <= threshold)
{
UpdateEma(_ids[bestIndex].Embedding, embedding);
_ids[bestIndex].Samples++;
@ -73,6 +72,6 @@ public sealed class IdentityCache
private static void UpdateEma(float[] ema, float[] v)
{
for (int i = 0; i < ema.Length; i++)
ema[i] = ema[i] * (1 - EmaAlpha) + v[i] * EmaAlpha;
ema[i] = ema[i] * (1 - _emaAlpha) + v[i] * _emaAlpha;
}
}

View File

@ -26,7 +26,7 @@ public class ObjectTracker(IObjectDetector _detector, IEmbeddingExtractor _embed
rect.Height = Math.Clamp(rect.Height, 1, frameMat.Height - rect.Y);
var embedding = _embeddingExtractor.Extract(frameMat, rect).ToArray(); // make a copy of the embedding array
p.Id = _identityCache.ResolveId(embedding);
p.Id = _identityCache.ResolveId(embedding, job.Job.IdentityThreshold);
objects[i] = p;
}