forked from amkovkov/GranuSightSoftware2
feat: quality property
This commit is contained in:
@@ -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)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user