using Microsoft.Extensions.Logging; using OrpaonVision.Core.Results; using OrpaonVision.SiteApp.Runtime.Contracts; namespace OrpaonVision.SiteApp.Runtime.Services; /// /// 输入输出一致性检查服务。 /// public sealed class ConsistencyCheckService : IConsistencyCheckService { private readonly ILogger _logger; private readonly IHikCameraService _cameraService; private readonly IYoloInferenceService _yoloService; /// /// 构造函数。 /// public ConsistencyCheckService( ILogger logger, IHikCameraService cameraService, IYoloInferenceService yoloService) { _logger = logger; _cameraService = cameraService; _yoloService = yoloService; } /// public Result CheckCameraInferenceConsistency() { try { _logger.LogInformation("开始检查相机与推理服务一致性"); var result = new ConsistencyCheckResult { CheckTimestamp = DateTime.UtcNow, CameraConnected = _cameraService.IsConnected, YoloInitialized = _yoloService.IsInitialized }; // 检查相机连接状态 if (!result.CameraConnected) { result.Status = ConsistencyStatus.Warning; result.Message = "相机未连接"; result.Recommendations.Add("请先连接相机设备"); _logger.LogWarning("相机未连接,跳过其他一致性检查"); return Result.Success(result); } // 检查YOLO初始化状态 if (!result.YoloInitialized) { result.Status = ConsistencyStatus.Warning; result.Message = "YOLO模型未初始化"; result.Recommendations.Add("请先初始化YOLO模型"); _logger.LogWarning("YOLO模型未初始化,跳过其他一致性检查"); return Result.Success(result); } // 获取相机配置信息 var cameraDevice = _cameraService.CurrentDevice; if (cameraDevice == null) { result.Status = ConsistencyStatus.Error; result.Message = "无法获取相机设备信息"; result.Recommendations.Add("检查相机连接状态"); return Result.Success(result); } // 获取YOLO模型信息 var yoloModelInfo = _yoloService.GetModelInfo(); // 检查像素格式一致性 var pixelFormatCheck = CheckPixelFormatConsistency(cameraDevice, yoloModelInfo); result.PixelFormatConsistent = pixelFormatCheck.IsConsistent; result.PixelFormatDetails = pixelFormatCheck.Details; if (!result.PixelFormatConsistent) { result.Status = ConsistencyStatus.Error; result.Message = "像素格式不一致"; result.Recommendations.AddRange(pixelFormatCheck.Recommendations); } // 检查图像尺寸一致性 var imageSizeCheck = CheckImageSizeConsistency(cameraDevice, yoloModelInfo); result.ImageSizeConsistent = imageSizeCheck.IsConsistent; result.ImageSizeDetails = imageSizeCheck.Details; if (!result.ImageSizeConsistent) { if (result.Status == ConsistencyStatus.Ok) { result.Status = ConsistencyStatus.Warning; } result.Recommendations.AddRange(imageSizeCheck.Recommendations); } // 检查数据流完整性 var dataFlowCheck = CheckDataFlowIntegrity(); result.DataFlowIntegrity = dataFlowCheck.IsIntegrity; result.DataFlowDetails = dataFlowCheck.Details; if (!result.DataFlowIntegrity) { if (result.Status == ConsistencyStatus.Ok) { result.Status = ConsistencyStatus.Warning; } result.Recommendations.AddRange(dataFlowCheck.Recommendations); } // 如果所有检查都通过 if (result.Status == ConsistencyStatus.Ok) { result.Message = "相机与推理服务一致性检查通过"; } _logger.LogInformation("一致性检查完成,状态: {Status}, 消息: {Message}", result.Status, result.Message); return Result.Success(result); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "一致性检查失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "CONSISTENCY_CHECK_FAILED", "一致性检查失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public Result GetMinimalHealthInfo() { try { _logger.LogDebug("获取最小健康信息"); var healthResult = new HealthCheckResult { Timestamp = DateTime.UtcNow, OverallStatus = HealthStatus.Healthy }; // 检查相机健康状态 var cameraHealth = CheckCameraHealth(); healthResult.CameraHealth = cameraHealth; if (cameraHealth.Status != HealthStatus.Healthy) { healthResult.OverallStatus = HealthStatus.Degraded; } // 检查YOLO健康状态 var yoloHealth = CheckYoloHealth(); healthResult.YoloHealth = yoloHealth; if (yoloHealth.Status != HealthStatus.Healthy) { healthResult.OverallStatus = HealthStatus.Degraded; } // 检查系统资源 var systemHealth = CheckSystemHealth(); healthResult.SystemHealth = systemHealth; if (systemHealth.Status != HealthStatus.Healthy) { healthResult.OverallStatus = HealthStatus.Degraded; } // 确定整体状态 if (healthResult.CameraHealth.Status == HealthStatus.Unhealthy || healthResult.YoloHealth.Status == HealthStatus.Unhealthy || healthResult.SystemHealth.Status == HealthStatus.Unhealthy) { healthResult.OverallStatus = HealthStatus.Unhealthy; } healthResult.Summary = GenerateHealthSummary(healthResult); _logger.LogDebug("健康检查完成,整体状态: {Status}", healthResult.OverallStatus); return Result.Success(healthResult); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "健康检查失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "HEALTH_CHECK_FAILED", "健康检查失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// /// 检查像素格式一致性。 /// private PixelFormatCheckResult CheckPixelFormatConsistency(HikCameraDevice cameraDevice, YoloModelInfo modelInfo) { var result = new PixelFormatCheckResult { IsConsistent = true, Details = new List() }; // 获取相机像素格式(这里简化处理,实际应该从相机参数获取) var cameraPixelFormat = "BGR8Packed"; // 默认值,实际应该从相机获取 // YOLO通常接受RGB格式,需要检查转换兼容性 var yoloExpectedFormat = "RGB8Packed"; result.Details.Add($"相机像素格式: {cameraPixelFormat}"); result.Details.Add($"YOLO期望格式: {yoloExpectedFormat}"); // 检查格式兼容性 if (cameraPixelFormat == "BGR8Packed" || cameraPixelFormat == "RGB8Packed") { result.Details.Add("像素格式兼容,支持自动转换"); } else if (cameraPixelFormat == "MONO8") { result.IsConsistent = false; result.Recommendations.Add("相机设置为单色格式,建议改为彩色格式以获得更好的检测效果"); } else { result.IsConsistent = false; result.Recommendations.Add($"不支持的像素格式: {cameraPixelFormat},建议使用BGR8Packed或RGB8Packed"); } return result; } /// /// 检查图像尺寸一致性。 /// private ImageSizeCheckResult CheckImageSizeConsistency(HikCameraDevice cameraDevice, YoloModelInfo modelInfo) { var result = new ImageSizeCheckResult { IsConsistent = true, Details = new List() }; // 获取相机输出尺寸(这里简化处理,实际应该从相机参数获取) var cameraSize = (1920, 1080); // 默认值,实际应该从相机获取 var yoloInputSize = modelInfo.InputSize; result.Details.Add($"相机输出尺寸: {cameraSize.Item1}x{cameraSize.Item2}"); result.Details.Add($"YOLO输入尺寸: {yoloInputSize.Item1}x{yoloInputSize.Item2}"); // 检查尺寸比例 var cameraRatio = (double)cameraSize.Item1 / cameraSize.Item2; var yoloRatio = (double)yoloInputSize.Item1 / yoloInputSize.Item2; var ratioDiff = Math.Abs(cameraRatio - yoloRatio); if (ratioDiff < 0.1) // 比例差异小于10% { result.Details.Add("图像尺寸比例基本一致"); } else { result.IsConsistent = false; result.Recommendations.Add("相机输出尺寸与YOLO输入尺寸比例差异较大,可能影响检测精度"); result.Recommendations.Add("建议调整相机分辨率或使用图像预处理调整尺寸"); } // 检查分辨率是否过小 if (cameraSize.Item1 < 640 || cameraSize.Item2 < 480) { result.IsConsistent = false; result.Recommendations.Add("相机分辨率过低,建议至少使用640x480分辨率"); } return result; } /// /// 检查数据流完整性。 /// private DataFlowCheckResult CheckDataFlowIntegrity() { var result = new DataFlowCheckResult { IsIntegrity = true, Details = new List() }; try { // 检查相机是否能获取帧 var frameResult = _cameraService.GetLatestFrame(); if (!frameResult.Succeeded) { result.IsIntegrity = false; result.Details.Add("无法从相机获取图像帧"); result.Recommendations.Add("检查相机是否正常采集图像"); return result; } var frameData = frameResult.Data; result.Details.Add($"成功获取图像帧,大小: {frameData.Length} bytes"); // 检查帧数据完整性 if (frameData.Length == 0) { result.IsIntegrity = false; result.Details.Add("图像帧数据为空"); result.Recommendations.Add("检查相机连接和采集设置"); return result; } // 检查YOLO推理是否能正常工作 var testImage = new byte[640 * 480 * 3]; // 模拟测试图像 var inferenceResult = _yoloService.Predict(testImage, 640, 480); if (!inferenceResult.Succeeded) { result.IsIntegrity = false; result.Details.Add("YOLO推理失败"); result.Recommendations.Add("检查YOLO模型状态和配置"); return result; } result.Details.Add("YOLO推理测试通过"); result.Details.Add("数据流完整性检查通过"); } catch (Exception ex) { result.IsIntegrity = false; result.Details.Add($"数据流检查异常: {ex.Message}"); result.Recommendations.Add("检查系统运行状态和依赖项"); } return result; } /// /// 检查相机健康状态。 /// private ComponentHealth CheckCameraHealth() { var health = new ComponentHealth { ComponentName = "Camera", Status = HealthStatus.Healthy, Details = new List(), Metrics = new Dictionary() }; try { if (!_cameraService.IsConnected) { health.Status = HealthStatus.Unhealthy; health.Details.Add("相机未连接"); return health; } var device = _cameraService.CurrentDevice; if (device != null) { health.Details.Add($"设备名称: {device.DeviceName}"); health.Details.Add($"序列号: {device.SerialNumber}"); health.Details.Add($"IP地址: {device.IpAddress}"); if (device.ConnectedAt.HasValue) { var uptime = DateTime.UtcNow - device.ConnectedAt.Value; health.Metrics["UptimeSeconds"] = uptime.TotalSeconds; health.Details.Add($"连接时长: {uptime:h\\h\\ m\\m\\ s\\s}"); } } // 测试获取帧 var frameResult = _cameraService.GetLatestFrame(); if (frameResult.Succeeded) { health.Metrics["LastFrameSize"] = frameResult.Data.Length; health.Details.Add("图像帧获取正常"); } else { health.Status = HealthStatus.Degraded; health.Details.Add($"图像帧获取失败: {frameResult.Message}"); } health.Metrics["IsConnected"] = _cameraService.IsConnected; } catch (Exception ex) { health.Status = HealthStatus.Unhealthy; health.Details.Add($"相机健康检查异常: {ex.Message}"); } return health; } /// /// 检查YOLO健康状态。 /// private ComponentHealth CheckYoloHealth() { var health = new ComponentHealth { ComponentName = "YOLO", Status = HealthStatus.Healthy, Details = new List(), Metrics = new Dictionary() }; try { if (!_yoloService.IsInitialized) { health.Status = HealthStatus.Unhealthy; health.Details.Add("YOLO模型未初始化"); return health; } var modelInfo = _yoloService.GetModelInfo(); health.Details.Add($"模型名称: {modelInfo.ModelName}"); health.Details.Add($"模型版本: {modelInfo.ModelVersion}"); health.Details.Add($"输入尺寸: {modelInfo.InputSize.Item1}x{modelInfo.InputSize.Item2}"); health.Details.Add($"类别数量: {modelInfo.ClassCount}"); health.Details.Add($"使用GPU: {modelInfo.UseGpu}"); health.Metrics["ModelFileSize"] = modelInfo.ModelFileSize; health.Metrics["ClassCount"] = modelInfo.ClassCount; health.Metrics["UseGpu"] = modelInfo.UseGpu; // 测试推理 var testImage = new byte[640 * 480 * 3]; var inferenceResult = _yoloService.Predict(testImage, 640, 480); if (inferenceResult.Succeeded) { health.Metrics["InferenceResultCount"] = inferenceResult.Data.Count; health.Details.Add("推理测试通过"); } else { health.Status = HealthStatus.Degraded; health.Details.Add($"推理测试失败: {inferenceResult.Message}"); } health.Metrics["IsInitialized"] = _yoloService.IsInitialized; } catch (Exception ex) { health.Status = HealthStatus.Unhealthy; health.Details.Add($"YOLO健康检查异常: {ex.Message}"); } return health; } /// /// 检查系统健康状态。 /// private ComponentHealth CheckSystemHealth() { var health = new ComponentHealth { ComponentName = "System", Status = HealthStatus.Healthy, Details = new List(), Metrics = new Dictionary() }; try { // 检查内存使用情况 var workingSet = Environment.WorkingSet; var workingSetMB = workingSet / (1024 * 1024); health.Metrics["WorkingSetMB"] = workingSetMB; health.Details.Add($"工作集内存: {workingSetMB} MB"); if (workingSetMB > 1024) // 超过1GB { health.Status = HealthStatus.Degraded; health.Details.Add("内存使用量较高"); } // 检查处理器数量 var processorCount = Environment.ProcessorCount; health.Metrics["ProcessorCount"] = processorCount; health.Details.Add($"处理器核心数: {processorCount}"); // 检查GC状态 var totalMemory = GC.GetTotalMemory(false); var totalMemoryMB = totalMemory / (1024 * 1024); health.Metrics["ManagedMemoryMB"] = totalMemoryMB; health.Details.Add($"托管内存: {totalMemoryMB} MB"); if (totalMemoryMB > 512) // 超过512MB托管内存 { if (health.Status == HealthStatus.Healthy) { health.Status = HealthStatus.Degraded; } health.Details.Add("托管内存使用量较高"); } health.Details.Add("系统资源检查完成"); } catch (Exception ex) { health.Status = HealthStatus.Unhealthy; health.Details.Add($"系统健康检查异常: {ex.Message}"); } return health; } /// /// 生成健康检查摘要。 /// private string GenerateHealthSummary(HealthCheckResult healthResult) { var summary = new List(); summary.Add($"整体状态: {healthResult.OverallStatus}"); if (healthResult.CameraHealth.Status != HealthStatus.Healthy) { summary.Add($"相机状态: {healthResult.CameraHealth.Status}"); } if (healthResult.YoloHealth.Status != HealthStatus.Healthy) { summary.Add($"YOLO状态: {healthResult.YoloHealth.Status}"); } if (healthResult.SystemHealth.Status != HealthStatus.Healthy) { summary.Add($"系统状态: {healthResult.SystemHealth.Status}"); } return string.Join("; ", summary); } }