using System;
|
using System.Linq;
|
using System.Windows;
|
using System.IO;
|
using System.Collections.ObjectModel;
|
using System.Windows.Input;
|
using System.Collections.Generic;
|
using Newtonsoft.Json;
|
using SmartScanner.OperateLog;
|
|
namespace SmartScanner
|
{
|
public partial class ResultJudge : Window
|
{
|
public static class AppSettings
|
{
|
private static readonly string SettingsKey = "LastConfigFilePath";
|
|
public static string LastConfigFilePath
|
{
|
get => Properties.Settings.Default.LastConfigFilePath ?? string.Empty;
|
set
|
{
|
Properties.Settings.Default.LastConfigFilePath = value;
|
Properties.Settings.Default.Save();
|
}
|
}
|
|
private static readonly string SettingsKey_Proj = "LastConfigFilePath_Proj";
|
|
public static string LastConfigFilePath_Proj
|
{
|
get => Properties.Settings.Default.LastConfigFilePath_Proj ?? string.Empty;
|
set
|
{
|
Properties.Settings.Default.LastConfigFilePath_Proj = value;
|
Properties.Settings.Default.Save();
|
}
|
}
|
}
|
public ResultJudgeViewModel ViewModel { get; set; }
|
|
public ResultJudge()
|
{
|
InitializeComponent();
|
ViewModel = new ResultJudgeViewModel();
|
DataContext = ViewModel;
|
}
|
|
public void SetControlsEnabled(bool isEnabled)
|
{
|
SaveConfig_RJ.IsEnabled = isEnabled;
|
}
|
|
public class ResultJudgeViewModel : BaseViewModel
|
{
|
public ObservableCollection<int> TargetCountOptions { get; } = new ObservableCollection<int> { 0, 1, 2, 3, 4 };
|
public ObservableCollection<int> TargetTypeOptions { get; } = new ObservableCollection<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
|
|
public ObservableCollection<JudgmentPoint> JudgmentPoints { get; set; } = new ObservableCollection<JudgmentPoint>();
|
|
public ICommand SaveCommand { get; }
|
public ICommand LoadCommand { get; }
|
|
public ResultJudgeViewModel()
|
{
|
// 初始化20个点位
|
for (int i = 1; i <= 20; i++)
|
{
|
JudgmentPoints.Add(new JudgmentPoint(i, this));
|
}
|
|
SaveCommand = new RelayCommand(SaveConfiguration);
|
LoadCommand = new RelayCommand(LoadConfiguration);
|
}
|
|
private void SaveConfiguration()
|
{
|
try
|
{
|
var config = JudgmentConfiguration.FromViewModel(this);
|
var json = JsonConvert.SerializeObject(config, Formatting.Indented);
|
|
var saveFileDialog = new Microsoft.Win32.SaveFileDialog
|
{
|
Filter = "JSON 文件 (*.json)|*.json|所有文件 (*.*)|*.*",
|
DefaultExt = ".json",
|
AddExtension = true,
|
Title = "保存配置文件",
|
FileName = Properties.Settings.Default.LastConfigFilePath
|
};
|
|
if (saveFileDialog.ShowDialog() == true)
|
{
|
File.WriteAllText(saveFileDialog.FileName, json);
|
Properties.Settings.Default.LastConfigFilePath = saveFileDialog.FileName;
|
Properties.Settings.Default.Save();
|
MessageBox.Show($"配置已成功保存到: {saveFileDialog.FileName}", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
OperateLogService.LogOperation("检测方案修改", $"检测方案修改为: {saveFileDialog.FileName}", null);
|
}
|
}
|
catch (Exception ex)
|
{
|
MessageBox.Show($"保存配置时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
}
|
}
|
|
private void LoadConfiguration()
|
{
|
try
|
{
|
var openFileDialog = new Microsoft.Win32.OpenFileDialog
|
{
|
Filter = "JSON 文件 (*.json)|*.json|所有文件 (*.*)|*.*",
|
DefaultExt = ".json",
|
Title = "加载配置文件",
|
FileName = AppSettings.LastConfigFilePath
|
};
|
|
if (openFileDialog.ShowDialog() == true)
|
{
|
var json = File.ReadAllText(openFileDialog.FileName);
|
AppSettings.LastConfigFilePath = openFileDialog.FileName;
|
var config = JsonConvert.DeserializeObject<JudgmentConfiguration>(json);
|
|
// 使用修改后的ToViewModel方法
|
JudgmentConfiguration.ToViewModel(config, this);
|
|
MessageBox.Show($"配置已成功从 {openFileDialog.FileName} 加载", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
}
|
}
|
catch (Exception ex)
|
{
|
MessageBox.Show($"加载配置时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
}
|
}
|
}
|
|
public class JudgmentPoint : BaseViewModel
|
{
|
private readonly ResultJudgeViewModel _parent;
|
public int PointNumber { get; }
|
|
private int _targetCount;
|
public int TargetCount
|
{
|
get => _targetCount;
|
set
|
{
|
if (SetProperty(ref _targetCount, value))
|
{
|
UpdateTargetConditions();
|
}
|
}
|
}
|
|
private int _scoreThreshold;
|
public int ScoreThreshold
|
{
|
get => _scoreThreshold;
|
set
|
{
|
if (SetProperty(ref _scoreThreshold, value))
|
{
|
foreach (var condition in TargetConditions)
|
{
|
condition.ScoreThreshold = value;
|
}
|
}
|
}
|
}
|
|
public ObservableCollection<TargetCondition> TargetConditions { get; } = new ObservableCollection<TargetCondition>();
|
|
public JudgmentPoint(int pointNumber, ResultJudgeViewModel parent)
|
{
|
PointNumber = pointNumber;
|
_parent = parent;
|
TargetCount = 0;
|
}
|
|
private void UpdateTargetConditions()
|
{
|
// 只添加缺少的条件,不删除已有条件
|
int currentCount = TargetConditions.Count;
|
if (currentCount < TargetCount)
|
{
|
for (int i = currentCount; i < TargetCount; i++)
|
{
|
TargetConditions.Add(new TargetCondition
|
{
|
ScoreThreshold = this.ScoreThreshold
|
});
|
}
|
}
|
else if (currentCount > TargetCount)
|
{
|
// 只移除多余的条件
|
for (int i = currentCount - 1; i >= TargetCount; i--)
|
{
|
TargetConditions.RemoveAt(i);
|
}
|
}
|
}
|
}
|
|
public class TargetCondition : BaseViewModel
|
{
|
private int _targetType;
|
public int TargetType
|
{
|
get => _targetType;
|
set => SetProperty(ref _targetType, value);
|
}
|
|
[JsonIgnore]
|
public int ScoreThreshold { get; set; }
|
}
|
|
public class JudgmentConfiguration
|
{
|
public List<JudgmentPointData> Points { get; set; }
|
|
public static JudgmentConfiguration FromViewModel(ResultJudgeViewModel viewModel)
|
{
|
var config = new JudgmentConfiguration
|
{
|
Points = new List<JudgmentPointData>()
|
};
|
|
foreach (var point in viewModel.JudgmentPoints)
|
{
|
var pointData = new JudgmentPointData
|
{
|
PointNumber = point.PointNumber,
|
TargetCount = point.TargetCount,
|
Conditions = new List<TargetConditionData>()
|
};
|
|
foreach (var condition in point.TargetConditions)
|
{
|
pointData.Conditions.Add(new TargetConditionData
|
{
|
TargetType = condition.TargetType,
|
ScoreThreshold = point.ScoreThreshold
|
});
|
}
|
config.Points.Add(pointData);
|
}
|
return config;
|
}
|
|
public static void ToViewModel(JudgmentConfiguration config, ResultJudgeViewModel viewModel)
|
{
|
// 先清空所有点位
|
viewModel.JudgmentPoints.Clear();
|
|
// 重新创建点位并加载配置
|
for (int i = 1; i <= 20; i++)
|
{
|
var pointData = config.Points.FirstOrDefault(p => p.PointNumber == i);
|
var point = new JudgmentPoint(i, viewModel);
|
|
if (pointData != null)
|
{
|
point.TargetCount = pointData.TargetCount;
|
point.ScoreThreshold = pointData.Conditions.FirstOrDefault()?.ScoreThreshold ?? 0;
|
|
// 清除自动生成的条件
|
point.TargetConditions.Clear();
|
|
// 添加配置中的条件
|
foreach (var conditionData in pointData.Conditions)
|
{
|
point.TargetConditions.Add(new TargetCondition
|
{
|
TargetType = conditionData.TargetType,
|
ScoreThreshold = point.ScoreThreshold
|
});
|
}
|
}
|
|
viewModel.JudgmentPoints.Add(point);
|
}
|
}
|
|
public int JudgeDetectionResult(int pointNumber, int[] numBoxes, int[] classIds, float[] prob)
|
{
|
var pointConfig = Points.FirstOrDefault(p => p.PointNumber == pointNumber);
|
if (pointConfig == null) return 0;
|
|
// 第一层判断:目标数量
|
if (numBoxes[0] < pointConfig.TargetCount)
|
{
|
return 0;
|
}
|
|
// 第二层判断:目标类型
|
bool typeMatch = true;
|
switch (pointConfig.TargetCount)
|
{
|
case 0:
|
return 1;
|
case 1:
|
typeMatch = classIds.Contains(pointConfig.Conditions[0].TargetType);
|
break;
|
case 2:
|
typeMatch = classIds.Contains(pointConfig.Conditions[0].TargetType) &&
|
classIds.Contains(pointConfig.Conditions[1].TargetType);
|
break;
|
case 3:
|
typeMatch = classIds.Contains(pointConfig.Conditions[0].TargetType) &&
|
classIds.Contains(pointConfig.Conditions[1].TargetType) &&
|
classIds.Contains(pointConfig.Conditions[2].TargetType);
|
break;
|
case 4:
|
typeMatch = classIds.Contains(pointConfig.Conditions[0].TargetType) &&
|
classIds.Contains(pointConfig.Conditions[1].TargetType) &&
|
classIds.Contains(pointConfig.Conditions[2].TargetType) &&
|
classIds.Contains(pointConfig.Conditions[3].TargetType);
|
break;
|
}
|
|
if (!typeMatch)
|
{
|
return 0;
|
}
|
|
// 第三层判断:得分阈值(使用第一个条件的阈值)
|
float threshold = pointConfig.Conditions[0].ScoreThreshold / 100f;
|
return prob.Take(pointConfig.TargetCount).All(p => p >= threshold) ? 1 : 0;
|
}
|
}
|
|
public class JudgmentPointData
|
{
|
public int PointNumber { get; set; }
|
public int TargetCount { get; set; }
|
public List<TargetConditionData> Conditions { get; set; }
|
}
|
|
public class TargetConditionData
|
{
|
public int TargetType { get; set; }
|
public int ScoreThreshold { get; set; }
|
}
|
|
public class BaseViewModel : System.ComponentModel.INotifyPropertyChanged
|
{
|
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
|
|
protected bool SetProperty<T>(ref T field, T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
|
{
|
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
|
field = value;
|
PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
|
return true;
|
}
|
}
|
|
public class RelayCommand : ICommand
|
{
|
private readonly Action _execute;
|
private readonly Func<bool> _canExecute;
|
|
public event EventHandler CanExecuteChanged
|
{
|
add { CommandManager.RequerySuggested += value; }
|
remove { CommandManager.RequerySuggested -= value; }
|
}
|
|
public RelayCommand(Action execute, Func<bool> canExecute = null)
|
{
|
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
|
_canExecute = canExecute;
|
}
|
|
public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
|
|
public void Execute(object parameter) => _execute();
|
}
|
}
|
}
|