Files
XplorePlane/XP.ImageProcessing.Processors/边缘检测/SobelEdgeProcessor.cs
T
2026-04-13 14:36:18 +08:00

135 lines
4.5 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.
// ============================================================================
// 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 Serilog;
using XP.ImageProcessing.Core;
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;
}
}