using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OrpaonVision.Core.Results;
using OrpaonVision.SiteApp.Runtime.Contracts;
using OrpaonVision.SiteApp.Runtime.Services;
using System.IO;
namespace OrpaonVision.SiteApp.Runtime.Services;
///
/// YOLO推理服务模拟实现。
///
#if DISABLED_LEGACY_MOCK_YOLO_SERVICE
public sealed class MockYoloInferenceService : IYoloInferenceService, IDisposable
{
private readonly ILogger _logger;
private readonly YoloInferenceOptions _options;
private readonly object _lockObject = new();
private bool _isInitialized;
private readonly List _classNames = new();
private readonly Random _random = new();
private YoloModelInfo _modelInfo = new();
///
/// 构造函数。
///
public MockYoloInferenceService(ILogger logger, IOptions options)
{
_logger = logger;
_options = options.Value;
_logger.LogInformation("YOLO推理服务已初始化(模拟模式)");
}
#endif
///
/// YOLO推理服务模拟实现(最小可编译版本)。
///
public sealed class MockYoloInferenceService : IYoloInferenceService, IDisposable
{
private readonly ILogger _logger;
private readonly YoloInferenceOptions _options;
private bool _initialized;
private readonly IReadOnlyList _classNames = Array.Empty();
public MockYoloInferenceService(ILogger logger, IOptions options)
{
_logger = logger;
_options = options.Value;
}
public bool IsInitialized => _initialized;
public Result Initialize()
{
_initialized = true;
return Result.Success(message: "YOLO模型初始化成功(模拟)。");
}
public Result> Predict(byte[] imageData, int width, int height, string pixelFormat = "BGR8Packed")
{
IReadOnlyList detections = Array.Empty();
return Result>.Success(detections);
}
public Result>> PredictBatch(IReadOnlyList imageBatch, IReadOnlyList<(int width, int height)> dimensions, string pixelFormat = "BGR8Packed")
{
var batchResults = new List>(imageBatch.Count);
for (var i = 0; i < imageBatch.Count; i++)
{
batchResults.Add(Array.Empty());
}
return Result>>.Success(batchResults);
}
public IReadOnlyList GetSupportedClasses()
{
return _classNames;
}
public YoloModelInfo GetModelInfo()
{
return new YoloModelInfo
{
ModelName = Path.GetFileNameWithoutExtension(_options.ModelPath),
ModelVersion = _options.ModelVersion,
InputSize = (_options.InputWidth, _options.InputHeight),
ClassCount = _classNames.Count,
ClassNames = _classNames,
UseGpu = false,
InferenceTimeMs = 0,
ModelFileSize = 0,
LoadTimeMs = 0
};
}
public Result Warmup(int warmupCount = 3)
{
_logger.LogDebug("执行YOLO模型预热(模拟),次数={WarmupCount}", warmupCount);
return Result.Success(message: "YOLO模型预热完成(模拟)。");
}
public void Dispose()
{
_initialized = false;
}
}
#if DISABLED_LEGACY_MOCK_YOLO_SERVICE_REMAINDER
///
public Result Initialize()
{
lock (_lockObject)
{
try
{
if (_isInitialized)
{
return Result.Success(message: "YOLO模型已初始化(模拟)。");
}
_logger.LogInformation("正在初始化YOLO模型(模拟): {ModelPath}", _options.ModelPath);
// 模拟初始化过程
Thread.Sleep(200); // 模拟加载时间
// 初始化模拟类别名称
_classNames.AddRange(new[]
{
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck",
"boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench",
"bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra",
"giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
"skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove",
"skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup",
"fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange",
"broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
"potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse",
"remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink",
"refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier",
"toothbrush"
});
// 设置模拟模型信息
_modelInfo = new YoloModelInfo
{
ModelPath = _options.ModelPath,
ModelType = "Mock",
InputWidth = _options.InputWidth,
InputHeight = _options.InputHeight,
ClassCount = _classNames.Count,
Version = "mock-v1.0",
IsInitialized = true
};
_isInitialized = true;
_logger.LogInformation("YOLO推理服务初始化成功(模拟),类别数量: {ClassCount}", _classNames.Count);
return Result.Success(message: "YOLO推理服务初始化成功(模拟)。");
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "初始化YOLO推理服务失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_INIT_FAILED", "初始化YOLO推理服务失败。", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
}
///
public Result Inference(byte[] imageData, int width, int height, string pixelFormat = "BGR8Packed")
{
try
{
if (!_isInitialized)
{
return Result.Fail("YOLO_NOT_INITIALIZED", "YOLO推理服务未初始化。");
}
_logger.LogDebug("开始YOLO推理(模拟),图像尺寸: {Width}x{Height}, 像素格式: {PixelFormat}", width, height, pixelFormat);
// 模拟推理过程
Thread.Sleep(_random.Next(50, 150)); // 模拟推理时间
// 生成模拟检测结果
var detections = new List();
var detectionCount = _random.Next(0, 5); // 随机生成0-4个检测结果
for (int i = 0; i < detectionCount; i++)
{
var classId = _random.Next(0, _classNames.Count);
var confidence = (float)(_random.NextDouble() * 0.4 + 0.6); // 0.6-1.0之间的置信度
// 过滤低于置信度阈值的检测结果
if (confidence < _options.ConfidenceThreshold)
{
continue;
}
var detection = new DetectionDto
{
ClassId = classId,
ClassName = _classNames[classId],
Confidence = confidence,
X = (int)(_random.NextDouble() * width * 0.8),
Y = (int)(_random.NextDouble() * height * 0.8),
Width = (int)(_random.NextDouble() * width * 0.3 + 20),
Height = (int)(_random.NextDouble() * height * 0.3 + 20)
};
detections.Add(detection);
}
// 应用NMS(非极大值抑制)的简单模拟
detections = ApplyMockNms(detections);
var result = new InferenceResultDto
{
Timestamp = DateTime.UtcNow,
ImageWidth = width,
ImageHeight = height,
Detections = detections,
InferenceTimeMs = _random.Next(50, 200), // 50-200ms推理时间
ModelVersion = _modelInfo.Version,
Success = true
};
_logger.LogDebug("YOLO推理完成(模拟),检测到 {Count} 个目标", detections.Count);
return Result.Success(result, message: "YOLO推理完成(模拟)。");
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "YOLO推理失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_INFERENCE_FAILED", "YOLO推理失败。", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public Result InferenceWithImage(byte[] imageData, int width, int height, string pixelFormat = "BGR8Packed")
{
var inferenceResult = Inference(imageData, width, height, pixelFormat);
if (!inferenceResult.Succeeded)
{
return inferenceResult;
}
// 在模拟模式中,可以添加一些可视化的模拟数据
// 实际实现中,这里应该生成带有检测框的图像
return inferenceResult;
}
///
public Result> GetClassNames()
{
try
{
if (!_isInitialized)
{
return Result>.Fail("YOLO_NOT_INITIALIZED", "YOLO推理服务未初始化。");
}
return Result>.Success(_classNames.ToList(), message: "获取类别名称成功(模拟)。");
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取YOLO类别名称失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_GET_CLASSES_FAILED", "获取YOLO类别名称失败。", traceId);
return Result>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public Result GetModelInfo()
{
try
{
if (!_isInitialized)
{
return Result.Fail("YOLO_NOT_INITIALIZED", "YOLO推理服务未初始化。");
}
return Result.Success(_modelInfo, message: "获取模型信息成功(模拟)。");
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取YOLO模型信息失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_GET_MODEL_INFO_FAILED", "获取YOLO模型信息失败。", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public Result SetConfidenceThreshold(float threshold)
{
try
{
if (threshold < 0 || threshold > 1)
{
return Result.Fail("INVALID_THRESHOLD", "置信度阈值必须在0-1之间。");
}
_options.ConfidenceThreshold = threshold;
_logger.LogInformation("YOLO置信度阈值已更新为: {Threshold}(模拟)", threshold);
return Result.Success(message: "置信度阈值更新成功(模拟)。");
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "设置YOLO置信度阈值失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_SET_THRESHOLD_FAILED", "设置置信度阈值失败。", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public Result SetNmsThreshold(float threshold)
{
try
{
if (threshold < 0 || threshold > 1)
{
return Result.Fail("INVALID_THRESHOLD", "NMS阈值必须在0-1之间。");
}
_options.NmsThreshold = threshold;
_logger.LogInformation("YOLO NMS阈值已更新为: {Threshold}(模拟)", threshold);
return Result.Success(message: "NMS阈值更新成功(模拟)。");
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "设置YOLO NMS阈值失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_SET_NMS_FAILED", "设置NMS阈值失败。", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
/// 应用模拟的NMS(非极大值抑制)。
///
private List ApplyMockNms(List detections)
{
if (detections.Count <= 1)
{
return detections;
}
var filteredDetections = new List();
// 按置信度降序排序
var sortedDetections = detections.OrderByDescending(d => d.Confidence).ToList();
foreach (var detection in sortedDetections)
{
bool shouldKeep = true;
// 检查与已保留检测的重叠度
foreach (var kept in filteredDetections)
{
var iou = CalculateMockIoU(detection, kept);
if (iou > _options.NmsThreshold)
{
shouldKeep = false;
break;
}
}
if (shouldKeep)
{
filteredDetections.Add(detection);
}
}
return filteredDetections;
}
///
/// 计算模拟的IoU(交并比)。
///
private float CalculateMockIoU(DetectionDto box1, DetectionDto box2)
{
// 计算交集区域
var x1 = Math.Max(box1.X, box2.X);
var y1 = Math.Max(box1.Y, box2.Y);
var x2 = Math.Min(box1.X + box1.Width, box2.X + box2.Width);
var y2 = Math.Min(box1.Y + box1.Height, box2.Y + box2.Height);
if (x2 <= x1 || y2 <= y1)
{
return 0f;
}
var intersection = (x2 - x1) * (y2 - y1);
// 计算并集区域
var area1 = box1.Width * box1.Height;
var area2 = box2.Width * box2.Height;
var union = area1 + area2 - intersection;
return (float)(intersection / union);
}
///
public Result GetModelInfo()
{
if (!_isInitialized)
{
return Result.Fail("YOLO_NOT_INITIALIZED", "YOLO模型未初始化。");
}
try
{
var modelInfo = new YoloModelInfo
{
ModelName = Path.GetFileNameWithoutExtension(_options.ModelPath),
ModelVersion = _options.ModelVersion,
ClassNames = _classNames.ToArray(),
InputSize = new Size(_options.InputWidth, _options.InputHeight),
LoadTimeMs = 200 // 模拟加载时间
};
_logger.LogDebug("获取YOLO模型信息(模拟): {ModelName}", modelInfo.ModelName);
return Result.Success(modelInfo);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取YOLO模型信息失败(模拟)。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_MODEL_INFO_FAILED", "获取YOLO模型信息失败。", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public Result> Predict(byte[] imageData, int width, int height, string pixelFormat = "BGR8Packed")
{
try
{
if (!_isInitialized)
{
return Result.Fail>("YOLO_NOT_INITIALIZED", "YOLO模型未初始化。");
}
var inferenceResult = Inference(imageData, width, height, pixelFormat);
if (!inferenceResult.Succeeded)
{
return Result.Fail>(inferenceResult.Code, inferenceResult.Message, inferenceResult.Errors.ToArray());
}
// 转换为YoloDetectionResult格式
var results = new List();
foreach (var detection in inferenceResult.Data.Detections)
{
var result = new YoloDetectionResult
{
ClassId = detection.ClassId,
ClassName = detection.ClassName ?? $"Class_{detection.ClassId}",
Confidence = detection.Confidence,
X = detection.X,
Y = detection.Y,
Width = detection.Width,
Height = detection.Height
};
results.Add(result);
}
return Result.Success>(results);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "YOLO推理失败(模拟)。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_PREDICT_FAILED", "YOLO推理失败。", traceId);
return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public Result> PredictBatch(IReadOnlyList imageDataList, IReadOnlyList<(int width, int height)> dimensions, string pixelFormat = "BGR8Packed")
{
try
{
if (!_isInitialized)
{
return Result.Fail>("YOLO_NOT_INITIALIZED", "YOLO模型未初始化。");
}
var batchResults = new List();
for (int i = 0; i < imageDataList.Count; i++)
{
var imageData = imageDataList[i];
var (width, height) = dimensions[i];
var singleResult = Predict(imageData, width, height, pixelFormat);
if (singleResult.Succeeded)
{
batchResults.Add(singleResult.Data.ToArray());
}
else
{
batchResults.Add(Array.Empty());
}
}
return Result.Success>(batchResults);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "YOLO批量推理失败(模拟)。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_BATCH_PREDICT_FAILED", "YOLO批量推理失败。", traceId);
return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public Result> GetSupportedClasses()
{
try
{
if (!_isInitialized)
{
return Result.Fail>("YOLO_NOT_INITIALIZED", "YOLO模型未初始化。");
}
return Result.Success>(_classNames.ToList());
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取YOLO支持类别失败(模拟)。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_GET_CLASSES_FAILED", "获取YOLO支持类别失败。", traceId);
return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public bool IsInitialized => _isInitialized;
///
public Result Warmup(int iterations = 10)
{
try
{
if (!_isInitialized)
{
return Result.Fail("YOLO_NOT_INITIALIZED", "YOLO模型未初始化。");
}
_logger.LogInformation("正在执行YOLO模型预热(模拟),迭代次数: {Iterations}", iterations);
// 创建一个小的测试图像进行预热
var testImageData = new byte[640 * 640 * 3]; // 640x640 BGR图像
for (int i = 0; i < iterations; i++)
{
var warmupResult = Predict(testImageData, 640, 640);
if (!warmupResult.Succeeded)
{
_logger.LogWarning("YOLO预热第{Iteration}次迭代失败(模拟): {Error}", i + 1, warmupResult.Message);
}
}
_logger.LogInformation("YOLO模型预热完成(模拟)");
return Result.Success(message: "YOLO模型预热完成(模拟)。");
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "YOLO模型预热失败(模拟)。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "YOLO_WARMUP_FAILED", "YOLO模型预热失败。", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
/// 释放资源。
///
public void Dispose()
{
try
{
_isInitialized = false;
_classNames.Clear();
_logger.LogInformation("YOLO推理服务资源已释放(模拟)");
}
catch (Exception ex)
{
_logger.LogError(ex, "释放YOLO推理服务资源时发生异常");
}
}
}
#endif