forked from amkovkov/GranuSightSoftware2
feat: quality property
This commit is contained in:
Generated
+131
@@ -0,0 +1,131 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using GSS2.Core.Analysis.AmineContent.Database.Results;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GSS2.Core.Analysis.AmineContent.Database.Results.Migrations
|
||||
{
|
||||
[DbContext(typeof(ResultsContext))]
|
||||
[Migration("20260608053836_Results1")]
|
||||
partial class Results1
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.0");
|
||||
|
||||
modelBuilder.Entity("GSS2.Core.Analysis.AmineContent.Database.Results.ResultRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasComment("Уникальный идентификатор");
|
||||
|
||||
b.Property<string>("Image")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Изображение");
|
||||
|
||||
b.Property<string>("MaskImage")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Маска");
|
||||
|
||||
b.Property<double>("MaxValue")
|
||||
.HasColumnType("REAL")
|
||||
.HasComment("Максимальное значение");
|
||||
|
||||
b.Property<double?>("MeanQuality")
|
||||
.HasColumnType("REAL")
|
||||
.HasComment("Среднее качество обработки");
|
||||
|
||||
b.Property<double>("MeanValue")
|
||||
.HasColumnType("REAL")
|
||||
.HasComment("Среднее значение");
|
||||
|
||||
b.PrimitiveCollection<string>("MeanValues")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Средние значения");
|
||||
|
||||
b.Property<double>("MeanVariance")
|
||||
.HasColumnType("REAL")
|
||||
.HasComment("Средняя дисперсия");
|
||||
|
||||
b.Property<double>("MinValue")
|
||||
.HasColumnType("REAL")
|
||||
.HasComment("Минимальное значение");
|
||||
|
||||
b.Property<int>("ParticlesCount")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasComment("Количество частиц");
|
||||
|
||||
b.PrimitiveCollection<string>("Qualities")
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Качества обработки");
|
||||
|
||||
b.Property<string>("ResultImage")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Изображение результата");
|
||||
|
||||
b.Property<string>("SampleBrand")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Марка пробы");
|
||||
|
||||
b.Property<string>("SampleComment")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Дополнительная информация о пробе");
|
||||
|
||||
b.Property<string>("SampleName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Название пробы");
|
||||
|
||||
b.Property<DateTime>("SamplingDateTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Дата и время отбора пробы");
|
||||
|
||||
b.Property<string>("SamplingPlace")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Место отбора пробы");
|
||||
|
||||
b.Property<string>("SeparatorType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Тип сепаратора");
|
||||
|
||||
b.Property<double>("VarianceOfMean")
|
||||
.HasColumnType("REAL")
|
||||
.HasComment("Дисперсия среднего");
|
||||
|
||||
b.PrimitiveCollection<string>("Variances")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Дисперсии");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ResultRecords");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GSS2.Core.Analysis.AmineContent.Database.Results.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Results1 : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<double>(
|
||||
name: "MeanQuality",
|
||||
table: "ResultRecords",
|
||||
type: "REAL",
|
||||
nullable: true,
|
||||
comment: "Среднее качество обработки");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Qualities",
|
||||
table: "ResultRecords",
|
||||
type: "TEXT",
|
||||
nullable: true,
|
||||
comment: "Качества обработки");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MeanQuality",
|
||||
table: "ResultRecords");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Qualities",
|
||||
table: "ResultRecords");
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -40,6 +40,10 @@ namespace GSS2.Core.Analysis.AmineContent.Database.Results.Migrations
|
||||
.HasColumnType("REAL")
|
||||
.HasComment("Максимальное значение");
|
||||
|
||||
b.Property<double?>("MeanQuality")
|
||||
.HasColumnType("REAL")
|
||||
.HasComment("Среднее качество обработки");
|
||||
|
||||
b.Property<double>("MeanValue")
|
||||
.HasColumnType("REAL")
|
||||
.HasComment("Среднее значение");
|
||||
@@ -61,6 +65,10 @@ namespace GSS2.Core.Analysis.AmineContent.Database.Results.Migrations
|
||||
.HasColumnType("INTEGER")
|
||||
.HasComment("Количество частиц");
|
||||
|
||||
b.PrimitiveCollection<string>("Qualities")
|
||||
.HasColumnType("TEXT")
|
||||
.HasComment("Качества обработки");
|
||||
|
||||
b.Property<string>("ResultImage")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
|
||||
@@ -46,8 +46,12 @@ public class ResultRecord
|
||||
public required double MeanVariance { get; set; }
|
||||
[Comment("Дисперсия среднего")]
|
||||
public required double VarianceOfMean { get; set; }
|
||||
[Comment("Среднее качество обработки")]
|
||||
public required double? MeanQuality { get; set; }
|
||||
[Comment("Средние значения")]
|
||||
public required double[] MeanValues { get; set; }
|
||||
[Comment("Дисперсии")]
|
||||
public required double[] Variances { get; set; }
|
||||
[Comment("Качества обработки")]
|
||||
public required double[]? Qualities { get; set; }
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -192,6 +192,8 @@
|
||||
<RowDefinition Height="Auto" /> <!-- Количество частиц (поле) / Среднее значение (поле) -->
|
||||
<RowDefinition Height="Auto" /> <!-- Средняя дисперсия (подпись) / Дисперсия среднего (подпись) -->
|
||||
<RowDefinition Height="Auto" /> <!-- Средняя дисперсия (поле) / Дисперсия среднего (поле)-->
|
||||
<RowDefinition Height="Auto" /> <!-- Среднее качество (подпись) -->
|
||||
<RowDefinition Height="Auto" /> <!-- Среднее качество (поле) -->
|
||||
<RowDefinition Height="*" /> <!-- Пустое пространство -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
@@ -233,7 +235,10 @@
|
||||
<TextBlock Grid.Row="6" Grid.Column="1" Classes="mini" Text="Дисперсия среднего:" />
|
||||
<!-- Дисперсия среднего (поле) -->
|
||||
<TextBox Grid.Row="7" Grid.Column="1" Classes="singleline" Text="{Binding EditingRecord.VarianceOfMean, StringFormat={}{0:N4}}" PlaceholderText="Дисперсия среднего:" IsReadOnly="True" />
|
||||
|
||||
<!-- Среднее качество (подпись) -->
|
||||
<TextBlock Grid.Row="8" Grid.Column="0" Classes="mini" Text="Среднее качество обработки:" Grid.ColumnSpan="2" />
|
||||
<!-- Среднее качество (поле) -->
|
||||
<TextBox Grid.Row="9" Grid.Column="0" Classes="singleline" Text="{Binding EditingRecord.MeanQuality, StringFormat={}{0:N4}}" PlaceholderText="Среднее качество обработки:" IsReadOnly="True" Grid.ColumnSpan="2" />
|
||||
</Grid>
|
||||
|
||||
<!-- Изображения -->
|
||||
@@ -344,6 +349,14 @@
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- Гистограмма качества обработки -->
|
||||
<lvc:CartesianChart x:Name="QualitiesChart"
|
||||
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
|
||||
LegendTextPaint="{Binding LegendTextPaint, Mode=OneWay}"
|
||||
Series="{Binding QualitiesHistogram, Mode=OneWay}"
|
||||
XAxes="{Binding QualitiesXAxis, Mode=OneWay}"
|
||||
YAxes="{Binding QualitiesYAxis, Mode=OneWay}" />
|
||||
|
||||
<!-- Гистограмма средних значений -->
|
||||
<lvc:CartesianChart x:Name="MeanValuesChart"
|
||||
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
|
||||
|
||||
@@ -18,5 +18,6 @@ public partial class AnalysisView : UserControl
|
||||
{
|
||||
MeanValuesChart.CoreChart.Update();
|
||||
VariancesChart.CoreChart.Update();
|
||||
QualitiesChart.CoreChart.Update();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user