using TeamAAS_VP.Enums; using TeamAAS_VP.Models; using OpenCvSharp; using System; namespace TeamAAS_VP.Services { /// /// 图像分析服务 /// public class ImageAnalysisService { /// /// 分析图像清晰度和对比度 /// public AnalysisResult AnalyzeImage(Mat image, FocusMethod method, Rect? roi = null) { var result = new AnalysisResult { Timestamp = DateTime.Now }; if (image == null || image.Empty()) { result.Message = "图像为空"; return result; } try { Mat analyzeMat = image; // 如果指定了ROI,则裁剪图像 if (roi.HasValue && roi.Value.Width > 0 && roi.Value.Height > 0) { var roiRect = roi.Value; // 确保ROI在图像范围内 roiRect.X = Math.Max(0, Math.Min(roiRect.X, image.Width - 1)); roiRect.Y = Math.Max(0, Math.Min(roiRect.Y, image.Height - 1)); roiRect.Width = Math.Min(roiRect.Width, image.Width - roiRect.X); roiRect.Height = Math.Min(roiRect.Height, image.Height - roiRect.Y); if (roiRect.Width > 0 && roiRect.Height > 0) { analyzeMat = new Mat(image, roiRect); } } // 转换为灰度图 Mat gray = new Mat(); if (analyzeMat.Channels() == 3) { Cv2.CvtColor(analyzeMat, gray, ColorConversionCodes.BGR2GRAY); } else { gray = analyzeMat.Clone(); } // 计算清晰度 result.Sharpness = CalculateSharpness(gray, method); // 计算对比度 result.Contrast = CalculateContrast(gray); // 计算质量评分 (0-100) result.QualityScore = CalculateQualityScore(result.Sharpness, result.Contrast, method); result.Message = "分析完成"; gray?.Dispose(); if (roi.HasValue && analyzeMat != image) { analyzeMat?.Dispose(); } } catch (Exception ex) { result.Message = $"分析错误: {ex.Message}"; } return result; } /// /// 计算清晰度 /// private double CalculateSharpness(Mat gray, FocusMethod method) { switch (method) { case FocusMethod.Laplacian: return CalculateLaplacianVariance(gray); case FocusMethod.Sobel: return CalculateSobelVariance(gray); case FocusMethod.Variance: return CalculateImageVariance(gray); case FocusMethod.Tenengrad: return CalculateTenengrad(gray); case FocusMethod.FrequencyDomain: return CalculateFrequencyDomain(gray); default: return CalculateLaplacianVariance(gray); } } /// /// Laplacian方差法 /// private double CalculateLaplacianVariance(Mat gray) { using (var laplacian = new Mat()) { Cv2.Laplacian(gray, laplacian, MatType.CV_64F); Cv2.MeanStdDev(laplacian, out _, out Scalar stddev); return stddev.Val0 * stddev.Val0; } } /// /// Sobel方差法 /// private double CalculateSobelVariance(Mat gray) { using (var sobelX = new Mat()) using (var sobelY = new Mat()) using (var sobel = new Mat()) { Cv2.Sobel(gray, sobelX, MatType.CV_64F, 1, 0, 3); Cv2.Sobel(gray, sobelY, MatType.CV_64F, 0, 1, 3); Cv2.Magnitude(sobelX, sobelY, sobel); return Cv2.Mean(sobel).Val0; } } /// /// 图像方差法 /// private double CalculateImageVariance(Mat gray) { Cv2.MeanStdDev(gray, out _, out Scalar stddev); return stddev.Val0 * stddev.Val0; } /// /// Tenengrad算子 /// private double CalculateTenengrad(Mat gray) { using (var sobelX = new Mat()) using (var sobelY = new Mat()) { Cv2.Sobel(gray, sobelX, MatType.CV_64F, 1, 0, 3); Cv2.Sobel(gray, sobelY, MatType.CV_64F, 0, 1, 3); double sum = 0; for (int y = 0; y < gray.Rows; y++) { for (int x = 0; x < gray.Cols; x++) { double gx = sobelX.At(y, x); double gy = sobelY.At(y, x); double magnitude = Math.Sqrt(gx * gx + gy * gy); // 只计算超过阈值的梯度 if (magnitude > 50) { sum += magnitude * magnitude; } } } return sum / (gray.Rows * gray.Cols); } } /// /// 频域分析法 /// private double CalculateFrequencyDomain(Mat gray) { try { // 转换为浮点型 Mat floatMat = new Mat(); gray.ConvertTo(floatMat, MatType.CV_32F); // 执行DFT Mat dft = new Mat(); Cv2.Dft(floatMat, dft, DftFlags.ComplexOutput); // 计算幅度谱 Mat[] planes = Cv2.Split(dft); Mat magnitude = new Mat(); Cv2.Magnitude(planes[0], planes[1], magnitude); // 计算高频能量占比 int centerX = magnitude.Cols / 2; int centerY = magnitude.Rows / 2; int radius = Math.Min(centerX, centerY) / 3; double totalEnergy = Cv2.Sum(magnitude).Val0; // 屏蔽低频区域 Cv2.Circle(magnitude, new Point(centerX, centerY), radius, Scalar.All(0), -1); double highFreqEnergy = Cv2.Sum(magnitude).Val0; floatMat?.Dispose(); dft?.Dispose(); foreach (var plane in planes) plane?.Dispose(); magnitude?.Dispose(); return totalEnergy > 0 ? (highFreqEnergy / totalEnergy) * 100 : 0; } catch { return 0; } } /// /// 计算对比度 /// private double CalculateContrast(Mat gray) { try { // 使用标准差作为对比度指标 Cv2.MeanStdDev(gray, out Scalar mean, out Scalar stddev); // 归一化对比度 (0-100) double contrast = (stddev.Val0 / 128.0) * 100; return Math.Min(100, contrast); } catch { return 0; } } /// /// 计算质量评分 /// private double CalculateQualityScore(double sharpness, double contrast, FocusMethod method) { // 根据不同的算法,设置不同的归一化参数 double normalizedSharpness = 0; switch (method) { case FocusMethod.Laplacian: normalizedSharpness = Math.Min(100, (sharpness / 50.0) * 100); break; case FocusMethod.Sobel: normalizedSharpness = Math.Min(100, (sharpness / 30.0) * 100); break; case FocusMethod.Variance: normalizedSharpness = Math.Min(100, (sharpness / 5000.0) * 100); break; case FocusMethod.Tenengrad: normalizedSharpness = Math.Min(100, (sharpness / 1000.0) * 100); break; case FocusMethod.FrequencyDomain: normalizedSharpness = sharpness; break; } // 综合清晰度和对比度 double score = (normalizedSharpness * 0.7 + contrast * 0.3); return Math.Min(100, Math.Max(0, score)); } /// /// 获取ROI区域图像 /// public Mat GetRoiImage(Mat image, Rect roi) { if (image == null || image.Empty()) return null; try { // 确保ROI在图像范围内 roi.X = Math.Max(0, Math.Min(roi.X, image.Width - 1)); roi.Y = Math.Max(0, Math.Min(roi.Y, image.Height - 1)); roi.Width = Math.Min(roi.Width, image.Width - roi.X); roi.Height = Math.Min(roi.Height, image.Height - roi.Y); if (roi.Width > 0 && roi.Height > 0) { return new Mat(image, roi).Clone(); } } catch (Exception ex) { Console.WriteLine($"获取ROI图像错误: {ex.Message}"); } return null; } } }