199 lines
6.3 KiB
C#
199 lines
6.3 KiB
C#
// ============================================================================
|
|
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
|
|
// 文件名: HorizontalEdgeProcessor.cs
|
|
// 描述: 水平边缘检测算子,专门用于检测水平方向的边缘
|
|
// 功能:
|
|
// - 检测水平边缘
|
|
// - 支持Prewitt和Sobel算子
|
|
// - 可调节检测灵敏度
|
|
// - 适用于检测水平线条和纹理
|
|
// 算法: Prewitt/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>
|
|
/// 水平边缘检测算子
|
|
/// </summary>
|
|
public class HorizontalEdgeProcessor : ImageProcessorBase
|
|
{
|
|
private static readonly ILogger _logger = Log.ForContext<HorizontalEdgeProcessor>();
|
|
|
|
public HorizontalEdgeProcessor()
|
|
{
|
|
Name = LocalizationHelper.GetString("HorizontalEdgeProcessor_Name");
|
|
Description = LocalizationHelper.GetString("HorizontalEdgeProcessor_Description");
|
|
}
|
|
|
|
protected override void InitializeParameters()
|
|
{
|
|
Parameters.Add("Method", new ProcessorParameter(
|
|
"Method",
|
|
LocalizationHelper.GetString("HorizontalEdgeProcessor_Method"),
|
|
typeof(string),
|
|
"Sobel",
|
|
null,
|
|
null,
|
|
LocalizationHelper.GetString("HorizontalEdgeProcessor_Method_Desc"),
|
|
new string[] { "Sobel", "Prewitt", "Simple" }));
|
|
|
|
Parameters.Add("Sensitivity", new ProcessorParameter(
|
|
"Sensitivity",
|
|
LocalizationHelper.GetString("HorizontalEdgeProcessor_Sensitivity"),
|
|
typeof(double),
|
|
1.0,
|
|
0.1,
|
|
5.0,
|
|
LocalizationHelper.GetString("HorizontalEdgeProcessor_Sensitivity_Desc")));
|
|
|
|
Parameters.Add("Threshold", new ProcessorParameter(
|
|
"Threshold",
|
|
LocalizationHelper.GetString("HorizontalEdgeProcessor_Threshold"),
|
|
typeof(int),
|
|
20,
|
|
0,
|
|
255,
|
|
LocalizationHelper.GetString("HorizontalEdgeProcessor_Threshold_Desc")));
|
|
_logger.Debug("InitializeParameters");
|
|
}
|
|
|
|
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
|
|
{
|
|
string method = GetParameter<string>("Method");
|
|
double sensitivity = GetParameter<double>("Sensitivity");
|
|
int threshold = GetParameter<int>("Threshold");
|
|
|
|
Image<Gray, byte> result;
|
|
|
|
if (method == "Sobel")
|
|
{
|
|
result = ApplySobel(inputImage, sensitivity, threshold);
|
|
}
|
|
else if (method == "Prewitt")
|
|
{
|
|
result = ApplyPrewitt(inputImage, sensitivity, threshold);
|
|
}
|
|
else // Simple
|
|
{
|
|
result = ApplySimple(inputImage, sensitivity, threshold);
|
|
}
|
|
|
|
_logger.Debug("Process: Method = {Method}, Sensitivity = {Sensitivity}, Threshold = {Threshold}",
|
|
method, sensitivity, threshold);
|
|
return result;
|
|
}
|
|
|
|
private Image<Gray, byte> ApplySobel(Image<Gray, byte> inputImage, double sensitivity, int threshold)
|
|
{
|
|
// 使用Sobel算子检测水平边缘(Y方向导数)
|
|
Image<Gray, float> sobelY = new Image<Gray, float>(inputImage.Size);
|
|
CvInvoke.Sobel(inputImage, sobelY, DepthType.Cv32F, 0, 1, 3);
|
|
|
|
// 转换为绝对值并应用灵敏度
|
|
Image<Gray, byte> result = new Image<Gray, byte>(inputImage.Size);
|
|
CvInvoke.ConvertScaleAbs(sobelY, result, sensitivity, 0);
|
|
|
|
// 应用阈值
|
|
if (threshold > 0)
|
|
{
|
|
CvInvoke.Threshold(result, result, threshold, 255, ThresholdType.Binary);
|
|
CvInvoke.Threshold(result, result, 0, 255, ThresholdType.ToZero);
|
|
}
|
|
|
|
sobelY.Dispose();
|
|
return result;
|
|
}
|
|
|
|
private Image<Gray, byte> ApplyPrewitt(Image<Gray, byte> inputImage, double sensitivity, int threshold)
|
|
{
|
|
// Prewitt水平算子
|
|
// [ 1 1 1]
|
|
// [ 0 0 0]
|
|
// [-1 -1 -1]
|
|
|
|
int width = inputImage.Width;
|
|
int height = inputImage.Height;
|
|
byte[,,] inputData = inputImage.Data;
|
|
|
|
Image<Gray, byte> result = new Image<Gray, byte>(width, height);
|
|
byte[,,] outputData = result.Data;
|
|
|
|
for (int y = 1; y < height - 1; y++)
|
|
{
|
|
for (int x = 1; x < width - 1; x++)
|
|
{
|
|
int sum = 0;
|
|
|
|
// 上行
|
|
sum += inputData[y - 1, x - 1, 0];
|
|
sum += inputData[y - 1, x, 0];
|
|
sum += inputData[y - 1, x + 1, 0];
|
|
|
|
// 下行
|
|
sum -= inputData[y + 1, x - 1, 0];
|
|
sum -= inputData[y + 1, x, 0];
|
|
sum -= inputData[y + 1, x + 1, 0];
|
|
|
|
// 取绝对值并应用灵敏度
|
|
int value = (int)(Math.Abs(sum) * sensitivity);
|
|
|
|
// 应用阈值
|
|
if (value > threshold)
|
|
{
|
|
outputData[y, x, 0] = (byte)Math.Min(255, value);
|
|
}
|
|
else
|
|
{
|
|
outputData[y, x, 0] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private Image<Gray, byte> ApplySimple(Image<Gray, byte> inputImage, double sensitivity, int threshold)
|
|
{
|
|
// 简单差分算子
|
|
// [ 1 1 1]
|
|
// [ 0 0 0]
|
|
// [-1 -1 -1]
|
|
// 但权重更简单
|
|
|
|
int width = inputImage.Width;
|
|
int height = inputImage.Height;
|
|
byte[,,] inputData = inputImage.Data;
|
|
|
|
Image<Gray, byte> result = new Image<Gray, byte>(width, height);
|
|
byte[,,] outputData = result.Data;
|
|
|
|
for (int y = 1; y < height - 1; y++)
|
|
{
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
// 简单的上下差分
|
|
int diff = inputData[y - 1, x, 0] - inputData[y + 1, x, 0];
|
|
int value = (int)(Math.Abs(diff) * sensitivity);
|
|
|
|
// 应用阈值
|
|
if (value > threshold)
|
|
{
|
|
outputData[y, x, 0] = (byte)Math.Min(255, value);
|
|
}
|
|
else
|
|
{
|
|
outputData[y, x, 0] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
} |