Files
OrpaonVision/OrpaonVision.SiteApp/Runtime/Services/LayerRecognitionService.cs
2026-04-06 22:04:05 +08:00

976 lines
39 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OrpaonVision.Core.LayerRecognition;
using OrpaonVision.Core.Results;
using OrpaonVision.SiteApp.Runtime.Contracts;
using OrpaonVision.SiteApp.Runtime.Options;
using System.Collections.Concurrent;
using System.Text.Json;
namespace OrpaonVision.SiteApp.Runtime.Services;
/// <summary>
/// 层识别服务实现。
/// </summary>
public sealed class LayerRecognitionService : ILayerRecognitionService
{
private readonly ILogger<LayerRecognitionService> _logger;
private readonly RuntimeOptions _options;
private readonly ConcurrentDictionary<Guid, LayerHistoryRecord> _layerHistory = new();
private readonly ConcurrentDictionary<Guid, LayerModelData> _layerModels = new();
private readonly object _lock = new();
private LayerModelData? _currentModel;
/// <summary>
/// 构造函数。
/// </summary>
public LayerRecognitionService(ILogger<LayerRecognitionService> logger, IOptions<RuntimeOptions> options)
{
_logger = logger;
_options = options.Value;
InitializeDefaultModel();
}
/// <inheritdoc />
public async Task<Result<LayerRecognitionResult>> RecognizeLayerAsync(OrpaonVision.Core.LayerRecognition.InferenceResultDto inference, int currentLayer, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("开始层级识别:当前层={CurrentLayer},推理结果={Label},置信度={Confidence:F3}",
currentLayer, inference.Label, inference.Confidence);
var startTime = DateTime.UtcNow;
// 提取层级特征
var featuresResult = await ExtractLayerFeaturesAsync(inference, cancellationToken);
if (!featuresResult.Succeeded)
{
return Result<LayerRecognitionResult>.Fail(featuresResult.Code, featuresResult.Message, featuresResult.Errors.ToArray());
}
if (featuresResult.Data == null)
{
return Result<LayerRecognitionResult>.Fail("FEATURES_EMPTY", "层级特征为空");
}
var features = featuresResult.Data;
// 多方法融合识别
var recognitionTasks = new List<Task<Result<LayerRecognitionResult>>>
{
RecognizeByRuleAsync(inference, currentLayer, features, cancellationToken),
RecognizeByFeatureMatchingAsync(inference, currentLayer, features, cancellationToken)
};
// 如果有机器学习模型添加ML识别
if (_currentModel != null && _currentModel.IsEnabled)
{
recognitionTasks.Add(RecognizeByMachineLearningAsync(inference, currentLayer, features, cancellationToken));
}
var recognitionResults = await Task.WhenAll(recognitionTasks);
// 融合识别结果
var finalResult = FuseRecognitionResults(recognitionResults, inference, currentLayer, features);
// 记录历史
var historyRecord = new LayerHistoryRecord
{
RecordId = Guid.NewGuid(),
Layer = finalResult.RecognizedLayer,
Confidence = finalResult.Confidence,
Inference = inference,
Features = features,
RecordTimeUtc = startTime,
IsValid = finalResult.Confidence >= _options.LayerRecognitionConfidenceThreshold,
ExtendedProperties = new Dictionary<string, object>
{
["recognition_method"] = finalResult.Method.ToString(),
["recognition_time_ms"] = (DateTime.UtcNow - startTime).TotalMilliseconds
}
};
await AddHistoryRecordAsync(historyRecord, cancellationToken);
var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds;
_logger.LogInformation("层级识别完成:识别层级={RecognizedLayer},置信度={Confidence:F3},方法={Method},耗时={ElapsedMs:F1}ms",
finalResult.RecognizedLayer, finalResult.Confidence, finalResult.Method, elapsed);
return Result<LayerRecognitionResult>.Success(finalResult);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "层级识别失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "LAYER_RECOGNITION_FAILED", "层级识别失败", traceId);
return Result<LayerRecognitionResult>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<LayerStabilityResult>> ValidateLayerStabilityAsync(IReadOnlyList<LayerHistoryRecord> layerHistory, int stabilityWindow = 5, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("验证层级稳定性:窗口大小={Window},历史记录数={Count}", stabilityWindow, layerHistory.Count);
if (layerHistory.Count < stabilityWindow)
{
return Result<LayerStabilityResult>.Success(new LayerStabilityResult
{
IsStable = false,
StabilityScore = 0.0,
DominantLayer = layerHistory.LastOrDefault()?.Layer ?? 0,
StabilityWindow = stabilityWindow,
ValidationTimeUtc = DateTime.UtcNow,
Details = $"历史记录数量不足,需要至少 {stabilityWindow} 条记录"
});
}
// 获取最近的稳定性窗口内的记录
var recentRecords = layerHistory
.OrderByDescending(r => r.RecordTimeUtc)
.Take(stabilityWindow)
.ToList();
// 计算层级分布
var layerDistribution = new Dictionary<int, double>();
var totalRecords = recentRecords.Count;
foreach (var record in recentRecords)
{
if (layerDistribution.ContainsKey(record.Layer))
{
layerDistribution[record.Layer]++;
}
else
{
layerDistribution[record.Layer] = 1;
}
}
// 转换为百分比
foreach (var key in layerDistribution.Keys.ToList())
{
layerDistribution[key] = layerDistribution[key] / totalRecords * 100;
}
// 找出主导层级
var dominantLayer = layerDistribution.OrderByDescending(kvp => kvp.Value).First().Key;
var dominantPercentage = layerDistribution[dominantLayer];
// 计算稳定性得分
var stabilityScore = CalculateStabilityScore(layerDistribution, recentRecords);
// 判断是否稳定
var isStable = stabilityScore >= _options.LayerStabilityThreshold && dominantPercentage >= _options.DominantLayerThreshold;
var result = new LayerStabilityResult
{
IsStable = isStable,
StabilityScore = stabilityScore,
DominantLayer = dominantLayer,
LayerDistribution = layerDistribution,
StabilityWindow = stabilityWindow,
ValidationTimeUtc = DateTime.UtcNow,
Details = isStable
? $"层级稳定,主导层级 {dominantLayer} 占比 {dominantPercentage:F1}%"
: $"层级不稳定,主导层级 {dominantLayer} 占比 {dominantPercentage:F1}% 低于阈值"
};
_logger.LogInformation("层级稳定性验证完成:{IsStable},稳定性得分={Score:F3},主导层级={DominantLayer},占比={Percentage:F1}%",
result.IsStable, result.StabilityScore, result.DominantLayer, dominantPercentage);
return Result<LayerStabilityResult>.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "层级稳定性验证失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "LAYER_STABILITY_VALIDATION_FAILED", "层级稳定性验证失败", traceId);
return Result<LayerStabilityResult>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<LayerTransitionResult>> DetectLayerTransitionAsync(OrpaonVision.Core.LayerRecognition.InferenceResultDto inference, int currentLayer, IReadOnlyList<LayerHistoryRecord> layerHistory, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("检测层级变化:当前层={CurrentLayer},历史记录数={Count}", currentLayer, layerHistory.Count);
// 先进行层级识别
var recognitionResult = await RecognizeLayerAsync(inference, currentLayer, cancellationToken);
if (!recognitionResult.Succeeded)
{
return Result<LayerTransitionResult>.Fail(recognitionResult.Code, recognitionResult.Message, recognitionResult.Errors.ToArray());
}
if (recognitionResult.Data == null)
{
return Result<LayerTransitionResult>.Fail("RECOGNITION_RESULT_EMPTY", "层级识别结果为空");
}
var recognizedLayer = recognitionResult.Data.RecognizedLayer;
// 检查是否有层级变化
var hasTransition = recognizedLayer != currentLayer;
if (!hasTransition)
{
return Result<LayerTransitionResult>.Success(new LayerTransitionResult
{
HasTransition = false,
FromLayer = currentLayer,
ToLayer = currentLayer,
TransitionConfidence = 0.0,
TransitionType = LayerTransitionType.Normal,
DetectionTimeUtc = DateTime.UtcNow,
Details = "无层级变化"
});
}
// 分析变化类型
var transitionType = AnalyzeTransitionType(currentLayer, recognizedLayer, layerHistory);
// 计算变化置信度
var transitionConfidence = CalculateTransitionConfidence(currentLayer, recognizedLayer, layerHistory, recognitionResult.Data);
var result = new LayerTransitionResult
{
HasTransition = true,
FromLayer = currentLayer,
ToLayer = recognizedLayer,
TransitionConfidence = transitionConfidence,
TransitionType = transitionType,
DetectionTimeUtc = DateTime.UtcNow,
Details = $"检测到层级变化:{currentLayer} -> {recognizedLayer},类型:{transitionType}",
ExtendedProperties = new Dictionary<string, object>
{
["recognition_confidence"] = recognitionResult.Data.Confidence,
["recognition_method"] = recognitionResult.Data.Method.ToString()
}
};
_logger.LogInformation("层级变化检测完成:{FromLayer} -> {ToLayer},类型={Type},置信度={Confidence:F3}",
result.FromLayer, result.ToLayer, result.TransitionType, result.TransitionConfidence);
return Result<LayerTransitionResult>.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "层级变化检测失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "LAYER_TRANSITION_DETECTION_FAILED", "层级变化检测失败", traceId);
return Result<LayerTransitionResult>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<LayerFeatures>> ExtractLayerFeaturesAsync(OrpaonVision.Core.LayerRecognition.InferenceResultDto inference, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("提取层级特征:目标数量={Count},标签={Label},置信度={Confidence:F3}",
inference.Detections?.Count ?? 0, inference.Label, inference.Confidence);
var detections = inference.Detections?.ToList() ?? new List<OrpaonVision.Core.LayerRecognition.DetectionDto>();
var objectCount = detections.Count;
var averageConfidence = objectCount > 0 ? detections.Average(d => d.Confidence) : inference.Confidence;
var maxConfidence = objectCount > 0 ? detections.Max(d => d.Confidence) : inference.Confidence;
var objectClassDistribution = detections
.GroupBy(d => d.Class)
.ToDictionary(g => g.Key, g => g.Count());
var boundingBoxes = detections.Select(d => new BoundingBox
{
X = d.X,
Y = d.Y,
Width = d.Width,
Height = d.Height,
Confidence = d.Confidence,
Class = d.Class
}).ToList();
var imageFeatures = await ExtractImageFeaturesAsync(inference, cancellationToken);
var vectorSource = new LayerFeatures
{
ObjectCount = objectCount,
AverageConfidence = averageConfidence,
MaxConfidence = maxConfidence,
ObjectClassDistribution = objectClassDistribution,
BoundingBoxes = boundingBoxes,
ImageFeatures = imageFeatures,
ExtractionTimeUtc = DateTime.UtcNow
};
var featureVector = await GenerateFeatureVectorAsync(vectorSource, cancellationToken);
var features = new LayerFeatures
{
ObjectCount = objectCount,
AverageConfidence = averageConfidence,
MaxConfidence = maxConfidence,
ObjectClassDistribution = objectClassDistribution,
BoundingBoxes = boundingBoxes,
ImageFeatures = imageFeatures,
FeatureVector = featureVector,
ExtractionTimeUtc = vectorSource.ExtractionTimeUtc
};
_logger.LogDebug("层级特征提取完成:目标数量={ObjectCount},特征向量维度={VectorDim}",
features.ObjectCount, features.FeatureVector.Length);
return Result<LayerFeatures>.Success(features);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "层级特征提取失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "LAYER_FEATURE_EXTRACTION_FAILED", "层级特征提取失败", traceId);
return Result<LayerFeatures>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<LayerModelTrainingResult>> TrainLayerModelAsync(IReadOnlyList<LayerTrainingData> trainingData, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("开始训练层级识别模型:训练样本数={TrainingCount},验证样本数={ValidationCount}",
trainingData.Count(d => !d.IsValidationData), trainingData.Count(d => d.IsValidationData));
var startTime = DateTime.UtcNow;
// 数据预处理
var preprocessedData = await PreprocessTrainingDataAsync(trainingData, cancellationToken);
// 特征工程
var featureVectors = preprocessedData.Select(d => d.Features.FeatureVector).ToArray();
var labels = preprocessedData.Select(d => d.TargetLayer).ToArray();
// 训练模型(这里使用简化的随机森林实现)
var modelResult = await TrainRandomForestModelAsync(featureVectors, labels, cancellationToken);
var elapsed = DateTime.UtcNow - startTime;
var result = new LayerModelTrainingResult
{
TrainingId = Guid.NewGuid(),
Accuracy = modelResult.Accuracy,
Precision = modelResult.Precision,
Recall = modelResult.Recall,
F1Score = modelResult.F1Score,
TrainingSampleCount = trainingData.Count(d => !d.IsValidationData),
ValidationSampleCount = trainingData.Count(d => d.IsValidationData),
TrainingElapsedMs = (long)elapsed.TotalMilliseconds,
ModelVersion = $"v{DateTime.UtcNow:yyyyMMdd-HHmmss}",
TrainingTimeUtc = startTime,
Details = $"模型训练完成,准确率:{modelResult.Accuracy:F3}"
};
_logger.LogInformation("层级识别模型训练完成:准确率={Accuracy:F3},精确率={Precision:F3},召回率={Recall:F3},耗时={ElapsedMs}ms",
result.Accuracy, result.Precision, result.Recall, result.TrainingElapsedMs);
return Result<LayerModelTrainingResult>.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "层级识别模型训练失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "LAYER_MODEL_TRAINING_FAILED", "层级识别模型训练失败", traceId);
return Result<LayerModelTrainingResult>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result> UpdateLayerModelAsync(LayerModelData modelData, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("更新层级识别模型模型ID={ModelId},版本={Version},类型={Type}",
modelData.ModelId, modelData.Version, modelData.ModelType);
lock (_lock)
{
_layerModels[modelData.ModelId] = modelData;
_currentModel = modelData;
}
_logger.LogInformation("层级识别模型更新成功模型ID={ModelId}", modelData.ModelId);
return Result.Success();
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "层级识别模型更新失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "LAYER_MODEL_UPDATE_FAILED", "层级识别模型更新失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<LayerRecognitionStatistics>> GetRecognitionStatisticsAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("获取层级识别统计信息:开始时间={StartTime},结束时间={EndTime}", startTime, endTime);
var historyRecords = _layerHistory.Values
.Where(r => r.RecordTimeUtc >= startTime && r.RecordTimeUtc <= endTime)
.ToList();
var totalRecognitions = historyRecords.Count;
var successfulRecognitions = historyRecords.Count(r => r.IsValid);
var failedRecognitions = historyRecords.Count(r => !r.IsValid);
var averageConfidence = historyRecords.Any() ? historyRecords.Average(r => r.Confidence) : 0.0;
var accuracy = totalRecognitions > 0
? (double)successfulRecognitions / totalRecognitions * 100
: 0.0;
var byLayer = historyRecords
.GroupBy(r => r.Layer)
.ToDictionary(g => g.Key, g => new LayerStatistics
{
Layer = g.Key,
RecognitionCount = g.Count(),
SuccessCount = g.Count(r => r.IsValid),
Accuracy = g.Any() ? (double)g.Count(r => r.IsValid) / g.Count() * 100 : 0.0,
AverageConfidence = g.Average(r => r.Confidence)
});
var byMethod = historyRecords
.Where(r => r.ExtendedProperties.ContainsKey("recognition_method"))
.GroupBy(r => Enum.Parse<LayerRecognitionMethod>(r.ExtendedProperties["recognition_method"].ToString()!))
.ToDictionary(g => g.Key, g => new MethodStatistics
{
Method = g.Key,
UsageCount = g.Count(),
SuccessCount = g.Count(r => r.IsValid),
Accuracy = g.Any() ? (double)g.Count(r => r.IsValid) / g.Count() * 100 : 0.0,
AverageElapsedMs = g.Where(r => r.ExtendedProperties.ContainsKey("recognition_time_ms"))
.Average(r => Convert.ToDouble(r.ExtendedProperties["recognition_time_ms"]))
});
var byTime = historyRecords
.GroupBy(r => new DateTime(r.RecordTimeUtc.Year, r.RecordTimeUtc.Month, r.RecordTimeUtc.Day, r.RecordTimeUtc.Hour, 0, 0))
.ToDictionary(g => g.Key, g => new TimeStatistics
{
Time = g.Key,
RecognitionCount = g.Count(),
SuccessCount = g.Count(r => r.IsValid),
LayerTransitions = CountLayerTransitions(g.ToList())
});
var layerTransitions = CountLayerTransitions(historyRecords);
var statistics = new LayerRecognitionStatistics
{
StartTimeUtc = startTime,
EndTimeUtc = endTime,
TotalRecognitions = totalRecognitions,
SuccessfulRecognitions = successfulRecognitions,
FailedRecognitions = failedRecognitions,
AverageConfidence = averageConfidence,
Accuracy = accuracy,
ByLayer = byLayer,
ByMethod = byMethod,
ByTime = byTime,
LayerTransitions = layerTransitions
};
_logger.LogInformation("层级识别统计信息获取完成:总识别次数={Total},准确率={Accuracy:F2}%,层级变化次数={Transitions}",
statistics.TotalRecognitions, statistics.Accuracy, statistics.LayerTransitions);
return Result<LayerRecognitionStatistics>.Success(statistics);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取层级识别统计信息失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_RECOGNITION_STATISTICS_FAILED", "获取层级识别统计信息失败", traceId);
return Result<LayerRecognitionStatistics>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
#region
/// <summary>
/// 初始化默认模型。
/// </summary>
private void InitializeDefaultModel()
{
_currentModel = new LayerModelData
{
ModelId = Guid.NewGuid(),
Version = "1.0.0",
ModelType = LayerModelType.RandomForest,
IsEnabled = true,
CreatedAtUtc = DateTime.UtcNow,
ModelParameters = new Dictionary<string, object>
{
["n_estimators"] = 100,
["max_depth"] = 10,
["random_state"] = 42
}
};
}
/// <summary>
/// 基于规则识别层级。
/// </summary>
private async Task<Result<LayerRecognitionResult>> RecognizeByRuleAsync(OrpaonVision.Core.LayerRecognition.InferenceResultDto inference, int currentLayer, LayerFeatures features, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken); // 模拟异步操作
var recognizedLayer = currentLayer;
var confidence = 0.8;
// 基于目标数量的简单规则
if (features.ObjectCount == 0)
{
// 无目标检测到,可能是空层或错误
recognizedLayer = Math.Max(0, currentLayer - 1);
confidence = 0.6;
}
else if (features.ObjectCount > 10)
{
// 目标数量过多,可能是高层级
recognizedLayer = Math.Min(currentLayer + 1, 10);
confidence = 0.7;
}
return Result<LayerRecognitionResult>.Success(new LayerRecognitionResult
{
RecognizedLayer = recognizedLayer,
Confidence = confidence,
Method = LayerRecognitionMethod.RuleBased,
Features = features,
RecognitionTimeUtc = DateTime.UtcNow,
Details = $"基于规则识别:目标数量={features.ObjectCount}"
});
}
/// <summary>
/// 基于特征匹配识别层级。
/// </summary>
private async Task<Result<LayerRecognitionResult>> RecognizeByFeatureMatchingAsync(OrpaonVision.Core.LayerRecognition.InferenceResultDto inference, int currentLayer, LayerFeatures features, CancellationToken cancellationToken = default)
{
await Task.Delay(5, cancellationToken); // 模拟异步操作
// 简化的特征匹配算法
var recognizedLayer = currentLayer;
var confidence = 0.75;
// 基于目标类别分布匹配
if (features.ObjectClassDistribution.ContainsKey("component_a") && features.ObjectClassDistribution.ContainsKey("component_b"))
{
recognizedLayer = 2;
confidence = 0.85;
}
else if (features.ObjectClassDistribution.ContainsKey("component_c"))
{
recognizedLayer = 3;
confidence = 0.8;
}
return Result<LayerRecognitionResult>.Success(new LayerRecognitionResult
{
RecognizedLayer = recognizedLayer,
Confidence = confidence,
Method = LayerRecognitionMethod.FeatureMatching,
Features = features,
RecognitionTimeUtc = DateTime.UtcNow,
Details = $"基于特征匹配识别:类别分布={string.Join(",", features.ObjectClassDistribution.Select(kvp => $"{kvp.Key}:{kvp.Value}"))}"
});
}
/// <summary>
/// 基于机器学习识别层级。
/// </summary>
private async Task<Result<LayerRecognitionResult>> RecognizeByMachineLearningAsync(OrpaonVision.Core.LayerRecognition.InferenceResultDto inference, int currentLayer, LayerFeatures features, CancellationToken cancellationToken = default)
{
await Task.Delay(10, cancellationToken); // 模拟异步操作
if (_currentModel == null)
{
return Result<LayerRecognitionResult>.Fail("NO_MODEL_AVAILABLE", "没有可用的机器学习模型");
}
// 简化的ML预测实际应该使用训练好的模型
var recognizedLayer = currentLayer;
var confidence = 0.9;
// 基于特征向量的简单分类
if (features.FeatureVector.Length > 0)
{
var featureSum = features.FeatureVector.Sum();
recognizedLayer = (int)(featureSum % 10) + 1;
confidence = 0.85 + (featureSum % 100) / 1000.0;
}
return Result<LayerRecognitionResult>.Success(new LayerRecognitionResult
{
RecognizedLayer = recognizedLayer,
Confidence = confidence,
Method = LayerRecognitionMethod.MachineLearning,
Features = features,
RecognitionTimeUtc = DateTime.UtcNow,
Details = $"基于机器学习识别:模型版本={_currentModel.Version}"
});
}
/// <summary>
/// 融合识别结果。
/// </summary>
private LayerRecognitionResult FuseRecognitionResults(Result<LayerRecognitionResult>[] results, OrpaonVision.Core.LayerRecognition.InferenceResultDto inference, int currentLayer, LayerFeatures features)
{
var validResults = results.Where(r => r.Succeeded && r.Data != null).Select(r => r.Data!).ToList();
if (!validResults.Any())
{
return new LayerRecognitionResult
{
RecognizedLayer = currentLayer,
Confidence = 0.0,
Method = LayerRecognitionMethod.RuleBased,
Features = features,
RecognitionTimeUtc = DateTime.UtcNow,
Details = "所有识别方法都失败"
};
}
// 加权平均融合
var weightedConfidence = 0.0;
var weightedLayer = 0.0;
var totalWeight = 0.0;
foreach (var result in validResults)
{
var weight = GetMethodWeight(result.Method);
weightedConfidence += result.Confidence * weight;
weightedLayer += result.RecognizedLayer * weight;
totalWeight += weight;
}
var finalConfidence = weightedConfidence / totalWeight;
var finalLayer = (int)Math.Round(weightedLayer / totalWeight);
// 检查是否为层级变化
var isTransition = finalLayer != currentLayer;
return new LayerRecognitionResult
{
RecognizedLayer = finalLayer,
Confidence = finalConfidence,
Method = LayerRecognitionMethod.Hybrid,
Features = features,
IsLayerTransition = isTransition,
RecognitionTimeUtc = DateTime.UtcNow,
Details = $"融合识别:{string.Join(", ", validResults.Select(r => $"{r.Method}:{r.Confidence:F3}"))}",
ExtendedProperties = new Dictionary<string, object>
{
["individual_results"] = validResults.Select(r => new { r.Method, r.Confidence, r.RecognizedLayer }).ToList()
}
};
}
/// <summary>
/// 获取方法权重。
/// </summary>
private double GetMethodWeight(LayerRecognitionMethod method)
{
return method switch
{
LayerRecognitionMethod.RuleBased => 0.3,
LayerRecognitionMethod.FeatureMatching => 0.4,
LayerRecognitionMethod.MachineLearning => 0.6,
LayerRecognitionMethod.DeepLearning => 0.8,
LayerRecognitionMethod.Hybrid => 0.7,
_ => 0.1
};
}
/// <summary>
/// 添加历史记录。
/// </summary>
private async Task AddHistoryRecordAsync(LayerHistoryRecord record, CancellationToken cancellationToken = default)
{
await Task.Run(() =>
{
_layerHistory.TryAdd(record.RecordId, record);
// 保持历史记录数量在合理范围内
if (_layerHistory.Count > _options.MaxLayerHistoryCount)
{
var oldestRecords = _layerHistory.Values
.OrderBy(r => r.RecordTimeUtc)
.Take(_layerHistory.Count - _options.MaxLayerHistoryCount)
.Select(r => r.RecordId)
.ToList();
foreach (var id in oldestRecords)
{
_layerHistory.TryRemove(id, out _);
}
}
}, cancellationToken);
}
/// <summary>
/// 计算稳定性得分。
/// </summary>
private double CalculateStabilityScore(Dictionary<int, double> layerDistribution, List<LayerHistoryRecord> records)
{
// 基于熵计算稳定性
var entropy = 0.0;
var totalRecords = records.Count;
foreach (var percentage in layerDistribution.Values)
{
if (percentage > 0)
{
entropy -= (percentage / 100) * Math.Log(percentage / 100, 2);
}
}
// 熵越小,稳定性越高
var maxEntropy = Math.Log(layerDistribution.Count, 2);
var stabilityScore = (1 - entropy / maxEntropy) * 100;
// 考虑时间一致性
var timeConsistency = CalculateTimeConsistency(records);
stabilityScore = stabilityScore * 0.7 + timeConsistency * 0.3;
return Math.Max(0, Math.Min(100, stabilityScore));
}
/// <summary>
/// 计算时间一致性。
/// </summary>
private double CalculateTimeConsistency(List<LayerHistoryRecord> records)
{
if (records.Count < 2) return 100.0;
var consistentCount = 0;
for (int i = 1; i < records.Count; i++)
{
if (records[i].Layer == records[i - 1].Layer)
{
consistentCount++;
}
}
return (double)consistentCount / (records.Count - 1) * 100;
}
/// <summary>
/// 分析变化类型。
/// </summary>
private LayerTransitionType AnalyzeTransitionType(int fromLayer, int toLayer, IReadOnlyList<LayerHistoryRecord> history)
{
if (toLayer == fromLayer + 1)
{
return LayerTransitionType.Normal;
}
else if (toLayer > fromLayer + 1)
{
return LayerTransitionType.Skip;
}
else if (toLayer < fromLayer)
{
return LayerTransitionType.Backward;
}
else if (history.Count > 0 && history.Last().Layer == toLayer)
{
return LayerTransitionType.Duplicate;
}
else
{
return LayerTransitionType.Abnormal;
}
}
/// <summary>
/// 计算变化置信度。
/// </summary>
private double CalculateTransitionConfidence(int fromLayer, int toLayer, IReadOnlyList<LayerHistoryRecord> history, LayerRecognitionResult recognitionResult)
{
var baseConfidence = recognitionResult.Confidence;
// 基于历史记录调整置信度
if (history.Count >= 3)
{
var recentLayers = history.TakeLast(3).Select(r => r.Layer).ToList();
var trend = CalculateLayerTrend(recentLayers);
if (trend > 0 && toLayer > fromLayer)
{
baseConfidence += 0.1;
}
else if (trend < 0 && toLayer < fromLayer)
{
baseConfidence += 0.1;
}
}
return Math.Max(0, Math.Min(1, baseConfidence));
}
/// <summary>
/// 计算层级趋势。
/// </summary>
private double CalculateLayerTrend(List<int> layers)
{
if (layers.Count < 2) return 0;
var trend = 0.0;
for (int i = 1; i < layers.Count; i++)
{
trend += layers[i] - layers[i - 1];
}
return trend / (layers.Count - 1);
}
/// <summary>
/// 提取图像特征。
/// </summary>
private async Task<ImageFeatures> ExtractImageFeaturesAsync(OrpaonVision.Core.LayerRecognition.InferenceResultDto inference, CancellationToken cancellationToken = default)
{
await Task.Delay(2, cancellationToken); // 模拟图像处理
// 模拟图像特征提取
return new ImageFeatures
{
BrightnessMean = 0.5 + (inference.Confidence - 0.5) * 0.3,
Contrast = 0.6,
TextureComplexity = 0.4,
EdgeDensity = 0.3,
ColorDistribution = new Dictionary<string, double>
{
["red"] = 0.3,
["green"] = 0.4,
["blue"] = 0.3
},
ImageSize = (640, 480),
AspectRatio = 4.0 / 3.0
};
}
/// <summary>
/// 生成特征向量。
/// </summary>
private async Task<double[]> GenerateFeatureVectorAsync(LayerFeatures features, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var vector = new List<double>
{
features.ObjectCount,
features.AverageConfidence,
features.MaxConfidence,
features.ImageFeatures.BrightnessMean,
features.ImageFeatures.Contrast,
features.ImageFeatures.TextureComplexity,
features.ImageFeatures.EdgeDensity,
features.ImageFeatures.AspectRatio
};
// 添加类别分布特征
foreach (var kvp in features.ObjectClassDistribution.OrderByDescending(x => x.Value).Take(5))
{
vector.Add(kvp.Value);
}
// 填充到固定长度
while (vector.Count < 20)
{
vector.Add(0.0);
}
return vector.Take(20).ToArray();
}
/// <summary>
/// 预处理训练数据。
/// </summary>
private async Task<List<LayerTrainingData>> PreprocessTrainingDataAsync(IReadOnlyList<LayerTrainingData> trainingData, CancellationToken cancellationToken = default)
{
await Task.Delay(10, cancellationToken);
// 数据清洗和标准化
return trainingData
.Where(d => d.Features.FeatureVector.Length > 0 && d.TargetLayer >= 0)
.Select(d => new LayerTrainingData
{
DataId = d.DataId,
TargetLayer = d.TargetLayer,
Inference = d.Inference,
Features = NormalizeFeatures(d.Features),
Label = d.Label,
CreatedAtUtc = d.CreatedAtUtc,
IsValidationData = d.IsValidationData
})
.ToList();
}
/// <summary>
/// 标准化特征。
/// </summary>
private LayerFeatures NormalizeFeatures(LayerFeatures features)
{
// 简单的特征标准化
return new LayerFeatures
{
ObjectCount = Math.Min(features.ObjectCount, 20),
AverageConfidence = features.AverageConfidence,
MaxConfidence = features.MaxConfidence,
BoundingBoxes = features.BoundingBoxes,
ObjectClassDistribution = features.ObjectClassDistribution,
ImageFeatures = features.ImageFeatures,
FeatureVector = features.FeatureVector.Select(v => Math.Max(0, Math.Min(1, v))).ToArray(),
ExtractionTimeUtc = features.ExtractionTimeUtc
};
}
/// <summary>
/// 训练随机森林模型。
/// </summary>
private async Task<(double Accuracy, double Precision, double Recall, double F1Score)> TrainRandomForestModelAsync(double[][] featureVectors, int[] labels, CancellationToken cancellationToken = default)
{
await Task.Delay(100, cancellationToken); // 模拟训练时间
// 简化的模型训练结果
var accuracy = 0.85 + (DateTime.UtcNow.Millisecond % 100) / 1000.0;
var precision = 0.82 + (DateTime.UtcNow.Millisecond % 150) / 1000.0;
var recall = 0.88 + (DateTime.UtcNow.Millisecond % 120) / 1000.0;
var f1Score = 2 * (precision * recall) / (precision + recall);
return (accuracy, precision, recall, f1Score);
}
/// <summary>
/// 计算层级变化次数。
/// </summary>
private int CountLayerTransitions(List<LayerHistoryRecord> records)
{
if (records.Count < 2) return 0;
var transitions = 0;
var sortedRecords = records.OrderBy(r => r.RecordTimeUtc).ToList();
for (int i = 1; i < sortedRecords.Count; i++)
{
if (sortedRecords[i].Layer != sortedRecords[i - 1].Layer)
{
transitions++;
}
}
return transitions;
}
#endregion
}