Files
OrpaonVision/OrpaonVision.SiteApp/Runtime/Services/ConsistencyCheckService.cs
2026-04-12 22:34:46 +08:00

546 lines
20 KiB
C#
Raw 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 OrpaonVision.Core.Results;
using OrpaonVision.SiteApp.Runtime.Contracts;
namespace OrpaonVision.SiteApp.Runtime.Services;
/// <summary>
/// 输入输出一致性检查服务。
/// </summary>
public sealed class ConsistencyCheckService : IConsistencyCheckService
{
private readonly ILogger<ConsistencyCheckService> _logger;
private readonly IHikCameraService _cameraService;
private readonly IYoloInferenceService _yoloService;
/// <summary>
/// 构造函数。
/// </summary>
public ConsistencyCheckService(
ILogger<ConsistencyCheckService> logger,
IHikCameraService cameraService,
IYoloInferenceService yoloService)
{
_logger = logger;
_cameraService = cameraService;
_yoloService = yoloService;
}
/// <inheritdoc />
public Result<ConsistencyCheckResult> 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<ConsistencyCheckResult>.Success(result);
}
// 检查YOLO初始化状态
if (!result.YoloInitialized)
{
result.Status = ConsistencyStatus.Warning;
result.Message = "YOLO模型未初始化";
result.Recommendations.Add("请先初始化YOLO模型");
_logger.LogWarning("YOLO模型未初始化跳过其他一致性检查");
return Result<ConsistencyCheckResult>.Success(result);
}
// 获取相机配置信息
var cameraDevice = _cameraService.CurrentDevice;
if (cameraDevice == null)
{
result.Status = ConsistencyStatus.Error;
result.Message = "无法获取相机设备信息";
result.Recommendations.Add("检查相机连接状态");
return Result<ConsistencyCheckResult>.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<ConsistencyCheckResult>.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<ConsistencyCheckResult>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public Result<HealthCheckResult> 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<HealthCheckResult>.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<HealthCheckResult>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <summary>
/// 检查像素格式一致性。
/// </summary>
private PixelFormatCheckResult CheckPixelFormatConsistency(HikCameraDevice cameraDevice, YoloModelInfo modelInfo)
{
var result = new PixelFormatCheckResult
{
IsConsistent = true,
Details = new List<string>()
};
// 获取相机像素格式(这里简化处理,实际应该从相机参数获取)
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;
}
/// <summary>
/// 检查图像尺寸一致性。
/// </summary>
private ImageSizeCheckResult CheckImageSizeConsistency(HikCameraDevice cameraDevice, YoloModelInfo modelInfo)
{
var result = new ImageSizeCheckResult
{
IsConsistent = true,
Details = new List<string>()
};
// 获取相机输出尺寸(这里简化处理,实际应该从相机参数获取)
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;
}
/// <summary>
/// 检查数据流完整性。
/// </summary>
private DataFlowCheckResult CheckDataFlowIntegrity()
{
var result = new DataFlowCheckResult
{
IsIntegrity = true,
Details = new List<string>()
};
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;
}
/// <summary>
/// 检查相机健康状态。
/// </summary>
private ComponentHealth CheckCameraHealth()
{
var health = new ComponentHealth
{
ComponentName = "Camera",
Status = HealthStatus.Healthy,
Details = new List<string>(),
Metrics = new Dictionary<string, object>()
};
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;
}
/// <summary>
/// 检查YOLO健康状态。
/// </summary>
private ComponentHealth CheckYoloHealth()
{
var health = new ComponentHealth
{
ComponentName = "YOLO",
Status = HealthStatus.Healthy,
Details = new List<string>(),
Metrics = new Dictionary<string, object>()
};
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;
}
/// <summary>
/// 检查系统健康状态。
/// </summary>
private ComponentHealth CheckSystemHealth()
{
var health = new ComponentHealth
{
ComponentName = "System",
Status = HealthStatus.Healthy,
Details = new List<string>(),
Metrics = new Dictionary<string, object>()
};
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;
}
/// <summary>
/// 生成健康检查摘要。
/// </summary>
private string GenerateHealthSummary(HealthCheckResult healthResult)
{
var summary = new List<string>();
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);
}
}