feat: quality property

This commit is contained in:
2026-06-08 09:47:52 +03:00
parent 226d35f5d5
commit 0849a0ae67
7 changed files with 267 additions and 5 deletions
@@ -21,11 +21,16 @@ using LiveChartsCore.SkiaSharpView.Painting;
using SkiaSharp;
using LiveChartsCore.SkiaSharpView.Painting.Effects;
using GSS2.UI.Core.Services;
using GSS2.Core.Hardware;
namespace GSS2.ViewModels.AmineContent;
public partial class AnalysisViewModel : ViewModelBase
{
const double QUALITY_MIN_MEAN = 2.0;
const double QUALITY_ALPHA = 0.7;
const double QUALITY_BETA = 0.3;
public event EventHandler? UpdateCharts;
private readonly ILogger<AnalysisViewModel> _logger;
@@ -35,6 +40,7 @@ public partial class AnalysisViewModel : ViewModelBase
private readonly AnalyzerService _analyzer;
private readonly DependencyInjectionViewLocator _viewLocator;
private readonly NavigationService _navigation;
private readonly LightsService _lights;
private CancellationTokenSource? _captureImagesTaskCts = null;
@@ -81,6 +87,10 @@ public partial class AnalysisViewModel : ViewModelBase
[ObservableProperty] public partial Axis[] VariancesXAxis { get; set; } = [new Axis()];
[ObservableProperty] public partial Axis[] VariancesYAxis { get; set; } = [new Axis()];
[ObservableProperty] public partial ISeries[] QualitiesHistogram { get; set; } = [];
[ObservableProperty] public partial Axis[] QualitiesXAxis { get; set; } = [new Axis()];
[ObservableProperty] public partial Axis[] QualitiesYAxis { get; set; } = [new Axis()];
public AnalysisViewModel(
ILogger<AnalysisViewModel> logger,
ResultsContext context,
@@ -88,7 +98,8 @@ public partial class AnalysisViewModel : ViewModelBase
ImageStorageService imageStorage,
AnalyzerService analyzer,
DependencyInjectionViewLocator viewLocator,
NavigationService navigation
NavigationService navigation,
LightsService lights
)
{
_logger = logger;
@@ -98,6 +109,7 @@ public partial class AnalysisViewModel : ViewModelBase
_analyzer = analyzer;
_viewLocator = viewLocator;
_navigation = navigation;
_lights = lights;
_logger.LogInformation("Инициализация");
// Получаем записи из базы данных
@@ -125,7 +137,9 @@ public partial class AnalysisViewModel : ViewModelBase
MeanVariance = -1,
VarianceOfMean = -1,
MeanValues = [],
Variances = []
Variances = [],
Qualities = [],
MeanQuality = -1
};
_logger.LogInformation("Инициализировано");
@@ -159,7 +173,9 @@ public partial class AnalysisViewModel : ViewModelBase
MeanVariance = -1,
VarianceOfMean = -1,
MeanValues = [],
Variances = []
Variances = [],
Qualities = [],
MeanQuality = -1
};
}
else
@@ -224,6 +240,13 @@ public partial class AnalysisViewModel : ViewModelBase
leftText: "Количество частиц",
bottomText: "Дисперсия"
);
(QualitiesHistogram, QualitiesXAxis, QualitiesYAxis) = BuildHistogram(
value.Qualities ?? [],
0,
100,
leftText: "Количество частиц",
bottomText: "Качество обработки"
);
}
catch (Exception ex)
{
@@ -338,6 +361,8 @@ public partial class AnalysisViewModel : ViewModelBase
SelectedRecord.MeanValue = EditingRecord.MeanValue;
SelectedRecord.MeanVariance = EditingRecord.MeanVariance;
SelectedRecord.VarianceOfMean = EditingRecord.VarianceOfMean;
SelectedRecord.Qualities = EditingRecord.Qualities;
SelectedRecord.MeanQuality = EditingRecord.MeanQuality;
// Если записи нет в базе данных
if (_context.Entry(SelectedRecord).State is EntityState.Detached)
@@ -496,6 +521,7 @@ public partial class AnalysisViewModel : ViewModelBase
// Вычисляем среднее и дисперсию каждого контура
var means = new List<double>();
var variances = new List<double>();
var qualities = new List<double>();
// Создаём временную маску для каждого контура
var contourMask = new OpenCvSharp.Mat(
@@ -520,6 +546,7 @@ public partial class AnalysisViewModel : ViewModelBase
// Добавляем значения в лист
means.Add(mean.Val0);
variances.Add(Math.Pow(stdDev.Val0, 2));
qualities.Add(CalculateQuality(mean.Val0, Math.Pow(stdDev.Val0, 2)));
}
contourMask.Release();
@@ -581,21 +608,48 @@ public partial class AnalysisViewModel : ViewModelBase
EditingRecord.VarianceOfMean = varianceOfMean;
EditingRecord.MeanValues = means.ToArray();
EditingRecord.Variances = variances.ToArray();
EditingRecord.MeanQuality = qualities.Average();
EditingRecord.Qualities = qualities.ToArray();
// Обновляем данные в редактируемой записи
// Так же Dispatcher.UIThread.Invoke нужен потому-что этот метод может (и скорее всего будет) вызван в другом потоке,
// а изменения данных в интерфейсе могут быть вызваны только из потока в котором интерфейс был создан
_ = Dispatcher.UIThread.InvokeAsync(() => EditingRecord = CopyRecord(EditingRecord));
// Если ошибок не было, то мигаем светодиодами зелёным
_ = Task.Run(async () =>
{
await Task.Delay(1000);
_lights.Flash(1, 1, System.Drawing.Color.Green);
await Task.Delay(3000);
_lights.Disconnect();
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Исключение во время анализа");
// Если была ошибка, то мигаем светодиодами красным
_ = Task.Run(async () =>
{
await Task.Delay(1000);
_lights.Flash(1, 1, System.Drawing.Color.Red);
await Task.Delay(3000);
_lights.Disconnect();
});
}
}
else
{
_logger.LogError("Ошибка при выполнении анализа");
// Если была ошибка, то мигаем светодиодами красным
_ = Task.Run(async () =>
{
await Task.Delay(1000);
_lights.Flash(1, 1, System.Drawing.Color.Red);
await Task.Delay(3000);
_lights.Disconnect();
});
}
}, cancellationToken);
@@ -666,7 +720,15 @@ public partial class AnalysisViewModel : ViewModelBase
MeanVariance = source.MeanVariance,
VarianceOfMean = source.VarianceOfMean,
MeanValues = source.MeanValues,
Variances = source.Variances
Variances = source.Variances,
Qualities = source.Qualities ??
Enumerable.Zip(source.MeanValues, source.Variances)
.Select((pair) => CalculateQuality(pair.First, pair.Second))
.ToArray(),
MeanQuality = source.MeanQuality ??
Enumerable.Zip(source.MeanValues, source.Variances)
.Select((pair) => CalculateQuality(pair.First, pair.Second))
.Average(),
};
}
@@ -785,4 +847,7 @@ public partial class AnalysisViewModel : ViewModelBase
}
private static (ISeries[] Series, Axis[] XAxes, Axis[] YAxes) BuildHistogram(IEnumerable<double> values, double? min = null, double? max = null, string leftText = "", string rightText = "", string bottomText = "", string barLegend = "", string lineLegend = "") =>
BuildHistogram(values.Select(v => (float)v), min, max, leftText, rightText, bottomText, barLegend, lineLegend);
private static double CalculateQuality(double mean, double variance) =>
100.0 * Math.Exp(-1 * (QUALITY_ALPHA * Math.Max(0, QUALITY_MIN_MEAN - mean) + QUALITY_BETA * Math.Pow(variance, 2)));
}