规范类名及命名空间名称
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user