135 lines
4.5 KiB
C#
135 lines
4.5 KiB
C#
// ============================================================================
|
|
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
|
|
// 文件名: SobelEdgeProcessor.cs
|
|
// 描述: Sobel边缘检测算子,用于检测图像边缘
|
|
// 功能:
|
|
// - Sobel算子边缘检测
|
|
// - 支持X方向、Y方向和组合检测
|
|
// - 可调节核大小
|
|
// - 输出边缘强度图
|
|
// 算法: Sobel算子
|
|
// 作者: 李伟 wei.lw.li@hexagon.com
|
|
// ============================================================================
|
|
|
|
using Emgu.CV;
|
|
using Emgu.CV.CvEnum;
|
|
using Emgu.CV.Structure;
|
|
using XP.ImageProcessing.Core;
|
|
using Serilog;
|
|
|
|
namespace XP.ImageProcessing.Processors;
|
|
|
|
/// <summary>
|
|
/// Sobel边缘检测算子
|
|
/// </summary>
|
|
public class SobelEdgeProcessor : ImageProcessorBase
|
|
{
|
|
private static readonly ILogger _logger = Log.ForContext<SobelEdgeProcessor>();
|
|
|
|
public SobelEdgeProcessor()
|
|
{
|
|
Name = LocalizationHelper.GetString("SobelEdgeProcessor_Name");
|
|
Description = LocalizationHelper.GetString("SobelEdgeProcessor_Description");
|
|
}
|
|
|
|
protected override void InitializeParameters()
|
|
{
|
|
Parameters.Add("Direction", new ProcessorParameter(
|
|
"Direction",
|
|
LocalizationHelper.GetString("SobelEdgeProcessor_Direction"),
|
|
typeof(string),
|
|
"Both",
|
|
null,
|
|
null,
|
|
LocalizationHelper.GetString("SobelEdgeProcessor_Direction_Desc"),
|
|
new string[] { "Both", "Horizontal", "Vertical" }));
|
|
|
|
Parameters.Add("KernelSize", new ProcessorParameter(
|
|
"KernelSize",
|
|
LocalizationHelper.GetString("SobelEdgeProcessor_KernelSize"),
|
|
typeof(int),
|
|
3,
|
|
1,
|
|
7,
|
|
LocalizationHelper.GetString("SobelEdgeProcessor_KernelSize_Desc")));
|
|
|
|
Parameters.Add("Scale", new ProcessorParameter(
|
|
"Scale",
|
|
LocalizationHelper.GetString("SobelEdgeProcessor_Scale"),
|
|
typeof(double),
|
|
1.0,
|
|
0.1,
|
|
5.0,
|
|
LocalizationHelper.GetString("SobelEdgeProcessor_Scale_Desc")));
|
|
_logger.Debug("InitializeParameters");
|
|
}
|
|
|
|
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
|
|
{
|
|
string direction = GetParameter<string>("Direction");
|
|
int kernelSize = GetParameter<int>("KernelSize");
|
|
double scale = GetParameter<double>("Scale");
|
|
|
|
// 确保核大小为奇数
|
|
if (kernelSize % 2 == 0) kernelSize++;
|
|
if (kernelSize > 7) kernelSize = 7;
|
|
if (kernelSize < 1) kernelSize = 1;
|
|
|
|
Image<Gray, float> sobelX = new Image<Gray, float>(inputImage.Size);
|
|
Image<Gray, float> sobelY = new Image<Gray, float>(inputImage.Size);
|
|
Image<Gray, byte> result = new Image<Gray, byte>(inputImage.Size);
|
|
|
|
if (direction == "Horizontal" || direction == "Both")
|
|
{
|
|
// X方向(水平边缘)
|
|
CvInvoke.Sobel(inputImage, sobelX, DepthType.Cv32F, 1, 0, kernelSize);
|
|
}
|
|
|
|
if (direction == "Vertical" || direction == "Both")
|
|
{
|
|
// Y方向(垂直边缘)
|
|
CvInvoke.Sobel(inputImage, sobelY, DepthType.Cv32F, 0, 1, kernelSize);
|
|
}
|
|
|
|
if (direction == "Both")
|
|
{
|
|
// 计算梯度幅值:sqrt(Gx^2 + Gy^2)
|
|
Image<Gray, float> magnitude = new Image<Gray, float>(inputImage.Size);
|
|
|
|
// 手动计算幅值
|
|
for (int y = 0; y < inputImage.Height; y++)
|
|
{
|
|
for (int x = 0; x < inputImage.Width; x++)
|
|
{
|
|
float gx = sobelX.Data[y, x, 0];
|
|
float gy = sobelY.Data[y, x, 0];
|
|
magnitude.Data[y, x, 0] = (float)Math.Sqrt(gx * gx + gy * gy);
|
|
}
|
|
}
|
|
|
|
// 应用缩放并转换为字节类型
|
|
var scaled = magnitude * scale;
|
|
result = scaled.Convert<Gray, byte>();
|
|
|
|
magnitude.Dispose();
|
|
scaled.Dispose();
|
|
}
|
|
else if (direction == "Horizontal")
|
|
{
|
|
// 只使用X方向
|
|
CvInvoke.ConvertScaleAbs(sobelX, result, scale, 0);
|
|
}
|
|
else // Vertical
|
|
{
|
|
// 只使用Y方向
|
|
CvInvoke.ConvertScaleAbs(sobelY, result, scale, 0);
|
|
}
|
|
|
|
sobelX.Dispose();
|
|
sobelY.Dispose();
|
|
|
|
_logger.Debug("Process: Direction = {Direction}, KernelSize = {KernelSize}, Scale = {Scale}",
|
|
direction, kernelSize, scale);
|
|
return result;
|
|
}
|
|
} |