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 TargetCountOptions { get; } = new ObservableCollection { 0, 1, 2, 3, 4 }; public ObservableCollection TargetTypeOptions { get; } = new ObservableCollection { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; public ObservableCollection JudgmentPoints { get; set; } = new ObservableCollection(); 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(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 TargetConditions { get; } = new ObservableCollection(); 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 Points { get; set; } public static JudgmentConfiguration FromViewModel(ResultJudgeViewModel viewModel) { var config = new JudgmentConfiguration { Points = new List() }; foreach (var point in viewModel.JudgmentPoints) { var pointData = new JudgmentPointData { PointNumber = point.PointNumber, TargetCount = point.TargetCount, Conditions = new List() }; 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 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(ref T field, T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) { if (EqualityComparer.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 _canExecute; public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public RelayCommand(Action execute, Func 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(); } } }