规范类名及命名空间名称

This commit is contained in:
李伟
2026-04-13 14:35:37 +08:00
parent c430ec229b
commit ace1c70ddf
217 changed files with 1271 additions and 1384 deletions
@@ -0,0 +1,197 @@
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? BandPassFilterProcessor.cs
// æè¿°: 带通滤波器算å­ï¼Œç”¨äºŽé¢‘域图åƒå¤„ç?
// 功能:
// - 在频域中ä¿ç•™ç‰¹å®šé¢‘率范围的信å?
// - 支æŒç†æƒ³ã€å·´ç‰¹æ²ƒæ–¯ã€é«˜æ–¯ä¸‰ç§æ»¤æ³¢å™¨ç±»åž‹
// - å¯è°ƒèŠ‚ä½Žé¢‘å’Œé«˜é¢‘æˆªæ­¢é¢‘çŽ‡
// - 通过FFT实现频域滤波
// 算法: 基于离散傅里å¶å˜æ¢ï¼ˆDFT)的频域滤波
// 作è€? æŽä¼Ÿ wei.lw.li@hexagon.com
// ============================================================================
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Serilog;
using System.Drawing;
using XP.ImageProcessing.Core;
namespace XP.ImageProcessing.Processors;
/// <summary>
/// 带通滤波器算å­
/// </summary>
public class BandPassFilterProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<BandPassFilterProcessor>();
public BandPassFilterProcessor()
{
Name = LocalizationHelper.GetString("BandPassFilterProcessor_Name");
Description = LocalizationHelper.GetString("BandPassFilterProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("LowCutoff", new ProcessorParameter(
"LowCutoff",
LocalizationHelper.GetString("BandPassFilterProcessor_LowCutoff"),
typeof(int),
10,
1,
200,
LocalizationHelper.GetString("BandPassFilterProcessor_LowCutoff_Desc")));
Parameters.Add("HighCutoff", new ProcessorParameter(
"HighCutoff",
LocalizationHelper.GetString("BandPassFilterProcessor_HighCutoff"),
typeof(int),
50,
2,
500,
LocalizationHelper.GetString("BandPassFilterProcessor_HighCutoff_Desc")));
Parameters.Add("FilterType", new ProcessorParameter(
"FilterType",
LocalizationHelper.GetString("BandPassFilterProcessor_FilterType"),
typeof(string),
"Ideal",
null,
null,
LocalizationHelper.GetString("BandPassFilterProcessor_FilterType_Desc"),
new string[] { "Ideal", "Butterworth", "Gaussian" }));
Parameters.Add("Order", new ProcessorParameter(
"Order",
LocalizationHelper.GetString("BandPassFilterProcessor_Order"),
typeof(int),
2,
1,
10,
LocalizationHelper.GetString("BandPassFilterProcessor_Order_Desc")));
_logger.Debug("InitializeParameters");
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
int lowCutoff = GetParameter<int>("LowCutoff");
int highCutoff = GetParameter<int>("HighCutoff");
string filterType = GetParameter<string>("FilterType");
int order = GetParameter<int>("Order");
if (highCutoff <= lowCutoff)
{
highCutoff = lowCutoff + 10;
}
var floatImage = inputImage.Convert<Gray, float>();
var imaginaryImage = new Image<Gray, float>(floatImage.Size);
imaginaryImage.SetZero();
using (var planes = new Emgu.CV.Util.VectorOfMat())
{
planes.Push(floatImage.Mat);
planes.Push(imaginaryImage.Mat);
Mat complexMat = new Mat();
CvInvoke.Merge(planes, complexMat);
Mat dftMat = new Mat();
CvInvoke.Dft(complexMat, dftMat, DxtType.Forward, 0);
var mask = CreateBandPassMask(floatImage.Size, lowCutoff, highCutoff, filterType, order);
using (var dftPlanes = new Emgu.CV.Util.VectorOfMat())
{
CvInvoke.Split(dftMat, dftPlanes);
Mat real = dftPlanes[0];
Mat imag = dftPlanes[1];
CvInvoke.Multiply(real, mask.Mat, real);
CvInvoke.Multiply(imag, mask.Mat, imag);
using (var filteredPlanes = new Emgu.CV.Util.VectorOfMat())
{
filteredPlanes.Push(real);
filteredPlanes.Push(imag);
Mat filteredDft = new Mat();
CvInvoke.Merge(filteredPlanes, filteredDft);
Mat idftMat = new Mat();
CvInvoke.Dft(filteredDft, idftMat, DxtType.Inverse | DxtType.Scale, 0);
using (var idftPlanes = new Emgu.CV.Util.VectorOfMat())
{
CvInvoke.Split(idftMat, idftPlanes);
var result = new Image<Gray, float>(floatImage.Size);
idftPlanes[0].CopyTo(result);
double minVal = 0, maxVal = 0;
Point minLoc = new Point();
Point maxLoc = new Point();
CvInvoke.MinMaxLoc(result, ref minVal, ref maxVal, ref minLoc, ref maxLoc);
if (maxVal > minVal)
{
result = (result - minVal) * (255.0 / (maxVal - minVal));
}
complexMat.Dispose();
dftMat.Dispose();
filteredDft.Dispose();
idftMat.Dispose();
_logger.Debug("Process: LowCutoff = {0}, HighCutoff = {1}, FilterType = {2}, Order = {3}", lowCutoff, highCutoff, filterType, order);
return result.Convert<Gray, byte>();
}
}
}
}
}
private Image<Gray, float> CreateBandPassMask(Size size, int lowCutoff, int highCutoff, string filterType, int order)
{
var mask = new Image<Gray, float>(size);
int cx = size.Width / 2;
int cy = size.Height / 2;
for (int y = 0; y < size.Height; y++)
{
for (int x = 0; x < size.Width; x++)
{
double dx = x - cx;
double dy = y - cy;
double distance = Math.Sqrt(dx * dx + dy * dy);
float value = 0;
switch (filterType)
{
case †æƒ³":
value = (distance >= lowCutoff && distance <= highCutoff) ? 1.0f : 0.0f;
break;
case "巴特沃斯":
double highPass = 1.0 / (1.0 + Math.Pow(lowCutoff / (distance + 0.001), 2 * order));
double lowPass = 1.0 / (1.0 + Math.Pow(distance / (highCutoff + 0.001), 2 * order));
value = (float)(highPass * lowPass);
break;
case "高斯":
double highPassGaussian = 1.0 - Math.Exp(-distance * distance / (2.0 * lowCutoff * lowCutoff));
double lowPassGaussian = Math.Exp(-distance * distance / (2.0 * highCutoff * highCutoff));
value = (float)(highPassGaussian * lowPassGaussian);
break;
}
mask.Data[y, x, 0] = value;
}
}
return mask;
}
}
@@ -0,0 +1,78 @@
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? BilateralFilterProcessor.cs
// æè¿°: åŒè¾¹æ»¤æ³¢ç®—å­ï¼Œç”¨äºŽä¿è¾¹é™å™?
// 功能:
// - åŒè¾¹æ»¤æ³¢
// - ä¿æŒè¾¹ç¼˜æ¸…æ™°çš„åŒæ—¶å¹³æ»‘图åƒ?
// - å¯è°ƒèŠ‚æ ¸å¤§å°å’Œæ ‡å‡†å·®
// 算法: åŒè¾¹æ»¤æ³¢
// 作è€? æŽä¼Ÿ wei.lw.li@hexagon.com
// ============================================================================
using Emgu.CV;
using Emgu.CV.Structure;
using Serilog;
using XP.ImageProcessing.Core;
namespace XP.ImageProcessing.Processors;
/// <summary>
/// åŒè¾¹æ»¤æ³¢ç®—å­
/// </summary>
public class BilateralFilterProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<BilateralFilterProcessor>();
public BilateralFilterProcessor()
{
Name = LocalizationHelper.GetString("BilateralFilterProcessor_Name");
Description = LocalizationHelper.GetString("BilateralFilterProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("Diameter", new ProcessorParameter(
"Diameter",
LocalizationHelper.GetString("BilateralFilterProcessor_Diameter"),
typeof(int),
9,
1,
31,
LocalizationHelper.GetString("BilateralFilterProcessor_Diameter_Desc")));
Parameters.Add("SigmaColor", new ProcessorParameter(
"SigmaColor",
LocalizationHelper.GetString("BilateralFilterProcessor_SigmaColor"),
typeof(double),
75.0,
1.0,
200.0,
LocalizationHelper.GetString("BilateralFilterProcessor_SigmaColor_Desc")));
Parameters.Add("SigmaSpace", new ProcessorParameter(
"SigmaSpace",
LocalizationHelper.GetString("BilateralFilterProcessor_SigmaSpace"),
typeof(double),
75.0,
1.0,
200.0,
LocalizationHelper.GetString("BilateralFilterProcessor_SigmaSpace_Desc")));
_logger.Debug("InitializeParameters");
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
int diameter = GetParameter<int>("Diameter");
double sigmaColor = GetParameter<double>("SigmaColor");
double sigmaSpace = GetParameter<double>("SigmaSpace");
var result = inputImage.Clone();
CvInvoke.BilateralFilter(inputImage, result, diameter, sigmaColor, sigmaSpace);
_logger.Debug("Process: Diameter = {Diameter}, SigmaColor = {SigmaColor}, SigmaSpace = {SigmaSpace}",
diameter, sigmaColor, sigmaSpace);
return result;
}
}
@@ -0,0 +1,69 @@
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? GaussianBlurProcessor.cs
// æè¿°: 高斯模糊算å­ï¼Œç”¨äºŽå›¾åƒå¹³æ»‘å’Œé™å™ª
// 功能:
// - 高斯核å·ç§¯å¹³æ»?
// - å¯è°ƒèŠ‚æ ¸å¤§å°å’Œæ ‡å‡†å·®
// - 有效去除高斯噪声
// - ä¿æŒè¾¹ç¼˜ç›¸å¯¹æ¸…æ™°
// 算法: 高斯滤波器å·ç§?
// 作è€? æŽä¼Ÿ wei.lw.li@hexagon.com
// ============================================================================
using Emgu.CV;
using Emgu.CV.Structure;
using Serilog;
using XP.ImageProcessing.Core;
namespace XP.ImageProcessing.Processors;
/// <summary>
/// 高斯模糊算å­
/// </summary>
public class GaussianBlurProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<GammaProcessor>();
public GaussianBlurProcessor()
{
Name = LocalizationHelper.GetString("GaussianBlurProcessor_Name");
Description = LocalizationHelper.GetString("GaussianBlurProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("KernelSize", new ProcessorParameter(
"KernelSize",
LocalizationHelper.GetString("GaussianBlurProcessor_KernelSize"),
typeof(int),
5,
1,
31,
LocalizationHelper.GetString("GaussianBlurProcessor_KernelSize_Desc")));
Parameters.Add("Sigma", new ProcessorParameter(
"Sigma",
LocalizationHelper.GetString("GaussianBlurProcessor_Sigma"),
typeof(double),
1.5,
0.1,
10.0,
LocalizationHelper.GetString("GaussianBlurProcessor_Sigma_Desc")));
_logger.Debug("InitializeParameters");
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
int kernelSize = GetParameter<int>("KernelSize");
double sigma = GetParameter<double>("Sigma");
if (kernelSize % 2 == 0) kernelSize++;
var result = inputImage.Clone();
CvInvoke.GaussianBlur(inputImage, result,
new System.Drawing.Size(kernelSize, kernelSize), sigma);
_logger.Debug("Process: KernelSize = {KernelSize}, Sigma = {Sigma}", kernelSize, sigma);
return result;
}
}
@@ -0,0 +1,148 @@
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? HighPassFilterProcessor.cs
// æè¿°: 高通滤波算å­ï¼Œç”¨äºŽè¾¹ç¼˜å¢žå¼º
// 功能:
// - 高通滤波(频域�
// - 边缘增强
// - 去除低频信æ¯
// - å¯è°ƒèŠ‚æˆªæ­¢é¢‘çŽ?
// 算法: 高斯高通滤波器(频域)
// 作è€? æŽä¼Ÿ 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>
/// 高通滤波算�
/// </summary>
public class HighPassFilterProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<HighPassFilterProcessor>();
public HighPassFilterProcessor()
{
Name = LocalizationHelper.GetString("HighPassFilterProcessor_Name");
Description = LocalizationHelper.GetString("HighPassFilterProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("CutoffFrequency", new ProcessorParameter(
"CutoffFrequency",
LocalizationHelper.GetString("HighPassFilterProcessor_CutoffFrequency"),
typeof(double),
30.0,
1.0,
200.0,
LocalizationHelper.GetString("HighPassFilterProcessor_CutoffFrequency_Desc")));
_logger.Debug("InitializeParameters");
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
double cutoffFrequency = GetParameter<double>("CutoffFrequency");
int rows = inputImage.Rows;
int cols = inputImage.Cols;
// 转æ¢ä¸ºæµ®ç‚¹åž‹
Image<Gray, float> floatImage = inputImage.Convert<Gray, float>();
// åˆ›å»ºå¤æ•°å›¾åƒç”¨äºŽFFT
Mat complexImage = new Mat();
using (var planes = new Emgu.CV.Util.VectorOfMat())
{
planes.Push(floatImage.Mat);
planes.Push(Mat.Zeros(rows, cols, DepthType.Cv32F, 1));
CvInvoke.Merge(planes, complexImage);
}
// 执行DFT
Mat dftImage = new Mat();
CvInvoke.Dft(complexImage, dftImage, DxtType.Forward);
// 分离实部和虚�
using (var dftPlanes = new Emgu.CV.Util.VectorOfMat())
{
CvInvoke.Split(dftImage, dftPlanes);
Mat real = dftPlanes[0];
Mat imag = dftPlanes[1];
// 创建高通滤波器
Mat filter = CreateHighPassFilter(rows, cols, cutoffFrequency);
// 应用滤波�
CvInvoke.Multiply(real, filter, real);
CvInvoke.Multiply(imag, filter, imag);
// åˆå¹¶å¹¶æ‰§è¡Œé€†DFT
using (var filteredPlanes = new Emgu.CV.Util.VectorOfMat())
{
filteredPlanes.Push(real);
filteredPlanes.Push(imag);
Mat filteredDft = new Mat();
CvInvoke.Merge(filteredPlanes, filteredDft);
Mat ifftImage = new Mat();
CvInvoke.Dft(filteredDft, ifftImage, DxtType.Inverse | DxtType.Scale);
// 分离实部
using (var ifftPlanes = new Emgu.CV.Util.VectorOfMat())
{
CvInvoke.Split(ifftImage, ifftPlanes);
// 转æ¢å›žbyte类型
Mat resultMat = new Mat();
ifftPlanes[0].ConvertTo(resultMat, DepthType.Cv8U);
Image<Gray, byte> result = resultMat.ToImage<Gray, byte>();
// 释放资æº
floatImage.Dispose();
complexImage.Dispose();
dftImage.Dispose();
filter.Dispose();
filteredDft.Dispose();
ifftImage.Dispose();
resultMat.Dispose();
_logger.Debug("Process: CutoffFrequency = {CutoffFrequency}", cutoffFrequency);
return result;
}
}
}
}
/// <summary>
/// 创建高斯高通滤波器
/// </summary>
private Mat CreateHighPassFilter(int rows, int cols, double d0)
{
var filter = new Image<Gray, float>(cols, rows);
int centerX = cols / 2;
int centerY = rows / 2;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
double distance = Math.Sqrt(Math.Pow(i - centerY, 2) + Math.Pow(j - centerX, 2));
float value = (float)(1 - Math.Exp(-(distance * distance) / (2 * d0 * d0)));
filter.Data[i, j, 0] = value;
}
}
return filter.Mat;
}
}
@@ -0,0 +1,148 @@
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? LowPassFilterProcessor.cs
// æè¿°: 低通滤波算å­ï¼Œç”¨äºŽåŽ»é™¤é«˜é¢‘å™ªå£°
// 功能:
// - 低通滤波(频域�
// - 去除高频噪声
// - 平滑图åƒ
// - å¯è°ƒèŠ‚æˆªæ­¢é¢‘çŽ?
// 算法: 高斯低通滤波器(频域)
// 作è€? æŽä¼Ÿ 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>
/// 低通滤波算�
/// </summary>
public class LowPassFilterProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<LowPassFilterProcessor>();
public LowPassFilterProcessor()
{
Name = LocalizationHelper.GetString("LowPassFilterProcessor_Name");
Description = LocalizationHelper.GetString("LowPassFilterProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("CutoffFrequency", new ProcessorParameter(
"CutoffFrequency",
LocalizationHelper.GetString("LowPassFilterProcessor_CutoffFrequency"),
typeof(double),
30.0,
1.0,
200.0,
LocalizationHelper.GetString("LowPassFilterProcessor_CutoffFrequency_Desc")));
_logger.Debug("InitializeParameters");
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
double cutoffFrequency = GetParameter<double>("CutoffFrequency");
int rows = inputImage.Rows;
int cols = inputImage.Cols;
// 转æ¢ä¸ºæµ®ç‚¹åž‹
Image<Gray, float> floatImage = inputImage.Convert<Gray, float>();
// åˆ›å»ºå¤æ•°å›¾åƒç”¨äºŽFFT
Mat complexImage = new Mat();
using (var planes = new Emgu.CV.Util.VectorOfMat())
{
planes.Push(floatImage.Mat);
planes.Push(Mat.Zeros(rows, cols, DepthType.Cv32F, 1));
CvInvoke.Merge(planes, complexImage);
}
// 执行DFT
Mat dftImage = new Mat();
CvInvoke.Dft(complexImage, dftImage, DxtType.Forward);
// 分离实部和虚�
using (var dftPlanes = new Emgu.CV.Util.VectorOfMat())
{
CvInvoke.Split(dftImage, dftPlanes);
Mat real = dftPlanes[0];
Mat imag = dftPlanes[1];
// 创建低通滤波器
Mat filter = CreateLowPassFilter(rows, cols, cutoffFrequency);
// 应用滤波�
CvInvoke.Multiply(real, filter, real);
CvInvoke.Multiply(imag, filter, imag);
// åˆå¹¶å¹¶æ‰§è¡Œé€†DFT
using (var filteredPlanes = new Emgu.CV.Util.VectorOfMat())
{
filteredPlanes.Push(real);
filteredPlanes.Push(imag);
Mat filteredDft = new Mat();
CvInvoke.Merge(filteredPlanes, filteredDft);
Mat ifftImage = new Mat();
CvInvoke.Dft(filteredDft, ifftImage, DxtType.Inverse | DxtType.Scale);
// 分离实部
using (var ifftPlanes = new Emgu.CV.Util.VectorOfMat())
{
CvInvoke.Split(ifftImage, ifftPlanes);
// 转æ¢å›žbyte类型
Mat resultMat = new Mat();
ifftPlanes[0].ConvertTo(resultMat, DepthType.Cv8U);
Image<Gray, byte> result = resultMat.ToImage<Gray, byte>();
// 释放资æº
floatImage.Dispose();
complexImage.Dispose();
dftImage.Dispose();
filter.Dispose();
filteredDft.Dispose();
ifftImage.Dispose();
resultMat.Dispose();
_logger.Debug("Process: CutoffFrequency = {CutoffFrequency}", cutoffFrequency);
return result;
}
}
}
}
/// <summary>
/// 创建高斯低通滤波器
/// </summary>
private Mat CreateLowPassFilter(int rows, int cols, double d0)
{
var filter = new Image<Gray, float>(cols, rows);
int centerX = cols / 2;
int centerY = rows / 2;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
double distance = Math.Sqrt(Math.Pow(i - centerY, 2) + Math.Pow(j - centerX, 2));
float value = (float)Math.Exp(-(distance * distance) / (2 * d0 * d0));
filter.Data[i, j, 0] = value;
}
}
return filter.Mat;
}
}
@@ -0,0 +1,61 @@
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? MeanFilterProcessor.cs
// æè¿°: å‡å€¼æ»¤æ³¢ç®—å­ï¼Œç”¨äºŽå›¾åƒå¹³æ»‘
// 功能:
// - å‡å€¼æ»¤æ³?
// - 简å•快速的平滑方法
// - å¯è°ƒèŠ‚æ ¸å¤§å°
// 算法: å‡å€¼æ»¤æ³?
// 作è€? æŽä¼Ÿ wei.lw.li@hexagon.com
// ============================================================================
using Emgu.CV;
using Emgu.CV.Structure;
using Serilog;
using System.Drawing;
using XP.ImageProcessing.Core;
namespace XP.ImageProcessing.Processors;
/// <summary>
/// å‡å€¼æ»¤æ³¢ç®—å­?
/// </summary>
public class MeanFilterProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<MeanFilterProcessor>();
public MeanFilterProcessor()
{
Name = LocalizationHelper.GetString("MeanFilterProcessor_Name");
Description = LocalizationHelper.GetString("MeanFilterProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("KernelSize", new ProcessorParameter(
"KernelSize",
LocalizationHelper.GetString("MeanFilterProcessor_KernelSize"),
typeof(int),
5,
1,
31,
LocalizationHelper.GetString("MeanFilterProcessor_KernelSize_Desc")));
_logger.Debug("InitializeParameters");
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
int kernelSize = GetParameter<int>("KernelSize");
// ç¡®ä¿æ ¸å¤§å°ä¸ºå¥‡æ•°
if (kernelSize % 2 == 0) kernelSize++;
var result = inputImage.Clone();
CvInvoke.Blur(inputImage, result, new Size(kernelSize, kernelSize), new Point(-1, -1));
_logger.Debug("Process: KernelSize = {KernelSize}", kernelSize);
return result;
}
}
@@ -0,0 +1,61 @@
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? MedianFilterProcessor.cs
// æè¿°: 中值滤波算å­ï¼Œç”¨äºŽåŽ»é™¤æ¤’ç›å™ªå£°
// 功能:
// - 中值滤�
// - 有效去除椒ç›å™ªå£°
// - ä¿æŒè¾¹ç¼˜æ¸…æ™°
// - å¯è°ƒèŠ‚æ ¸å¤§å°
// 算法: 中值滤�
// 作è€? æŽä¼Ÿ wei.lw.li@hexagon.com
// ============================================================================
using Emgu.CV;
using Emgu.CV.Structure;
using Serilog;
using XP.ImageProcessing.Core;
namespace XP.ImageProcessing.Processors;
/// <summary>
/// 中值滤波算�
/// </summary>
public class MedianFilterProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<MedianFilterProcessor>();
public MedianFilterProcessor()
{
Name = LocalizationHelper.GetString("MedianFilterProcessor_Name");
Description = LocalizationHelper.GetString("MedianFilterProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("KernelSize", new ProcessorParameter(
"KernelSize",
LocalizationHelper.GetString("MedianFilterProcessor_KernelSize"),
typeof(int),
5,
1,
31,
LocalizationHelper.GetString("MedianFilterProcessor_KernelSize_Desc")));
_logger.Debug("InitializeParameters");
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
int kernelSize = GetParameter<int>("KernelSize");
// ç¡®ä¿æ ¸å¤§å°ä¸ºå¥‡æ•°
if (kernelSize % 2 == 0) kernelSize++;
var result = inputImage.Clone();
CvInvoke.MedianBlur(inputImage, result, kernelSize);
_logger.Debug("Process: KernelSize = {KernelSize}", kernelSize);
return result;
}
}
@@ -0,0 +1,123 @@
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? ShockFilterProcessor.cs
// æè¿°: 冲击滤波算å­ï¼Œç”¨äºŽå›¾åƒé”化和边缘增强
// 功能:
// - 基于PDE的图åƒé”åŒ?
// - å¢žå¼ºè¾¹ç¼˜åŒæ—¶ä¿æŒå¹³æ»‘区域
// - å¯è°ƒèŠ‚è¿­ä»£æ¬¡æ•°å’Œæ»¤æ³¢å¼ºåº¦
// - 适用于模糊图åƒçš„æ¢å¤
// 算法: 冲击滤波器(Shock Filter)基于å微分方程
// 作è€? æŽä¼Ÿ wei.lw.li@hexagon.com
// ============================================================================
using Emgu.CV;
using Emgu.CV.Structure;
using Serilog;
using XP.ImageProcessing.Core;
namespace XP.ImageProcessing.Processors;
/// <summary>
/// 冲击滤波算å­
/// </summary>
public class ShockFilterProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<ShockFilterProcessor>();
public ShockFilterProcessor()
{
Name = LocalizationHelper.GetString("ShockFilterProcessor_Name");
Description = LocalizationHelper.GetString("ShockFilterProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("Iterations", new ProcessorParameter(
"Iterations",
LocalizationHelper.GetString("ShockFilterProcessor_Iterations"),
typeof(int),
5,
1,
20,
LocalizationHelper.GetString("ShockFilterProcessor_Iterations_Desc")));
Parameters.Add("Theta", new ProcessorParameter(
"Theta",
LocalizationHelper.GetString("ShockFilterProcessor_Theta"),
typeof(double),
0.5,
0.0,
2.0,
LocalizationHelper.GetString("ShockFilterProcessor_Theta_Desc")));
Parameters.Add("Dt", new ProcessorParameter(
"Dt",
LocalizationHelper.GetString("ShockFilterProcessor_Dt"),
typeof(double),
0.25,
0.1,
1.0,
LocalizationHelper.GetString("ShockFilterProcessor_Dt_Desc")));
_logger.Debug("InitializeParameters");
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
int iterations = GetParameter<int>("Iterations");
double theta = GetParameter<double>("Theta");
double dt = GetParameter<double>("Dt");
var result = inputImage.Convert<Gray, float>();
for (int iter = 0; iter < iterations; iter++)
{
result = ShockFilterIteration(result, theta, dt);
}
_logger.Debug("Process: Iterations = {Iterations}, Theta = {Theta}, Dt = {Dt}", iterations, theta, dt);
return result.Convert<Gray, byte>();
}
private Image<Gray, float> ShockFilterIteration(Image<Gray, float> input, double theta, double dt)
{
int width = input.Width;
int height = input.Height;
var output = new Image<Gray, float>(width, height);
for (int y = 1; y < height - 1; y++)
{
for (int x = 1; x < width - 1; x++)
{
float dx = (input.Data[y, x + 1, 0] - input.Data[y, x - 1, 0]) / 2.0f;
float dy = (input.Data[y + 1, x, 0] - input.Data[y - 1, x, 0]) / 2.0f;
float gradMag = (float)Math.Sqrt(dx * dx + dy * dy);
float dxx = input.Data[y, x + 1, 0] - 2 * input.Data[y, x, 0] + input.Data[y, x - 1, 0];
float dyy = input.Data[y + 1, x, 0] - 2 * input.Data[y, x, 0] + input.Data[y - 1, x, 0];
float laplacian = dxx + dyy;
float sign = laplacian > 0 ? 1.0f : -1.0f;
if (gradMag > theta)
{
output.Data[y, x, 0] = input.Data[y, x, 0] - (float)(dt * sign * gradMag);
}
else
{
output.Data[y, x, 0] = input.Data[y, x, 0];
}
}
}
for (int x = 0; x < width; x++)
{
output.Data[0, x, 0] = input.Data[0, x, 0];
output.Data[height - 1, x, 0] = input.Data[height - 1, x, 0];
}
for (int y = 0; y < height; y++)
{
output.Data[y, 0, 0] = input.Data[y, 0, 0];
output.Data[y, width - 1, 0] = input.Data[y, width - 1, 0];
}
return output;
}
}