using TeamAAS_VP.Enums;
using TeamAAS_VP.Models;
using OpenCvSharp;
using System;
using TeamAAS_VP.Resources.Languages;
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 = Lang.图像为空;
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 = Lang.分析完成;
gray?.Dispose();
if (roi.HasValue && analyzeMat != image)
{
analyzeMat?.Dispose();
}
}
catch (Exception ex)
{
result.Message = string.Format(Lang.分析错误0,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(string.Format(Lang.获取ROI图像错误0,ex.Message));
}
return null;
}
}
}