合并图像处理库,删除图像lib库
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 ImageProcessing.Core;
|
||||
using Serilog;
|
||||
using System.Drawing;
|
||||
|
||||
namespace 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 ImageProcessing.Core;
|
||||
using Serilog;
|
||||
|
||||
namespace 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 ImageProcessing.Core;
|
||||
using Serilog;
|
||||
|
||||
namespace 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 ImageProcessing.Core;
|
||||
using Serilog;
|
||||
|
||||
namespace 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 ImageProcessing.Core;
|
||||
using Serilog;
|
||||
|
||||
namespace 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 ImageProcessing.Core;
|
||||
using Serilog;
|
||||
using System.Drawing;
|
||||
|
||||
namespace 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 ImageProcessing.Core;
|
||||
using Serilog;
|
||||
|
||||
namespace 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 ImageProcessing.Core;
|
||||
using Serilog;
|
||||
|
||||
namespace 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