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);
}
}