规范类名及命名空间名称

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,196 @@
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? FilmEffectProcessor.cs
// æè¿°: 电å­èƒ¶ç‰‡æ•ˆæžœç®—å­ï¼Œæ¨¡æ‹Ÿä¼ ç»ŸX射线胶片的显示效æž?
// 功能:
// - 窗宽窗ä½ï¼ˆWindow/Level)调æ•?
// - 胶片å转(正ç‰?负片ï¼?
// - 多ç§èƒ¶ç‰‡ç‰¹æ€§æ›²çº¿ï¼ˆçº¿æ€§ã€S曲线ã€å¯¹æ•°ã€æŒ‡æ•°ï¼‰
// - 边缘增强(模拟胶片é”化效果)
// - 使用查找表(LUT)加速处ç?
// 算法: çª—å®½çª—ä½æ˜ å°„ + ç‰¹æ€§æ›²çº¿å˜æ?
// 作è€? æŽä¼Ÿ 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 FilmEffectProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<FilmEffectProcessor>();
private byte[] _lut = new byte[256];
public FilmEffectProcessor()
{
Name = LocalizationHelper.GetString("FilmEffectProcessor_Name");
Description = LocalizationHelper.GetString("FilmEffectProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("WindowCenter", new ProcessorParameter(
"WindowCenter",
LocalizationHelper.GetString("FilmEffectProcessor_WindowCenter"),
typeof(int),
128,
0,
255,
LocalizationHelper.GetString("FilmEffectProcessor_WindowCenter_Desc")));
Parameters.Add("WindowWidth", new ProcessorParameter(
"WindowWidth",
LocalizationHelper.GetString("FilmEffectProcessor_WindowWidth"),
typeof(int),
255,
1,
255,
LocalizationHelper.GetString("FilmEffectProcessor_WindowWidth_Desc")));
Parameters.Add("Invert", new ProcessorParameter(
"Invert",
LocalizationHelper.GetString("FilmEffectProcessor_Invert"),
typeof(bool),
false,
null,
null,
LocalizationHelper.GetString("FilmEffectProcessor_Invert_Desc")));
Parameters.Add("Curve", new ProcessorParameter(
"Curve",
LocalizationHelper.GetString("FilmEffectProcessor_Curve"),
typeof(string),
"Linear",
null,
null,
LocalizationHelper.GetString("FilmEffectProcessor_Curve_Desc"),
new string[] { "Linear", "Sigmoid", "Logarithmic", "Exponential" }));
Parameters.Add("CurveStrength", new ProcessorParameter(
"CurveStrength",
LocalizationHelper.GetString("FilmEffectProcessor_CurveStrength"),
typeof(double),
1.0,
0.1,
5.0,
LocalizationHelper.GetString("FilmEffectProcessor_CurveStrength_Desc")));
Parameters.Add("EdgeEnhance", new ProcessorParameter(
"EdgeEnhance",
LocalizationHelper.GetString("FilmEffectProcessor_EdgeEnhance"),
typeof(double),
0.0,
0.0,
3.0,
LocalizationHelper.GetString("FilmEffectProcessor_EdgeEnhance_Desc")));
_logger.Debug("InitializeParameters");
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
int windowCenter = GetParameter<int>("WindowCenter");
int windowWidth = GetParameter<int>("WindowWidth");
bool invert = GetParameter<bool>("Invert");
string curve = GetParameter<string>("Curve");
double curveStrength = GetParameter<double>("CurveStrength");
double edgeEnhance = GetParameter<double>("EdgeEnhance");
// 构建查找�
BuildLUT(windowCenter, windowWidth, invert, curve, curveStrength);
// 应用 LUT
var result = inputImage.Clone();
int width = result.Width;
int height = result.Height;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
result.Data[y, x, 0] = _lut[result.Data[y, x, 0]];
}
}
// 边缘增强(模拟胶片é”化)
if (edgeEnhance > 0.01)
{
using var blurred = inputImage.SmoothGaussian(3);
using var detail = new Image<Gray, float>(width, height);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
float diff = inputImage.Data[y, x, 0] - blurred.Data[y, x, 0];
float enhanced = result.Data[y, x, 0] + (float)(diff * edgeEnhance);
result.Data[y, x, 0] = (byte)Math.Clamp((int)enhanced, 0, 255);
}
}
}
_logger.Debug("Process: WC={WC}, WW={WW}, Invert={Inv}, Curve={Curve}, Strength={Str}, Edge={Edge}",
windowCenter, windowWidth, invert, curve, curveStrength, edgeEnhance);
return result;
}
private void BuildLUT(int wc, int ww, bool invert, string curve, double strength)
{
double halfW = ww / 2.0;
double low = wc - halfW;
double high = wc + halfW;
for (int i = 0; i < 256; i++)
{
// çª—å®½çª—ä½æ˜ å°„åˆ?[0, 1]
double normalized;
if (ww <= 1)
normalized = i >= wc ? 1.0 : 0.0;
else
normalized = Math.Clamp((i - low) / (high - low), 0.0, 1.0);
// 应用特性曲�
double mapped = curve switch
{
"Sigmoid" => ApplySigmoid(normalized, strength),
"Logarithmic" => ApplyLogarithmic(normalized, strength),
"Exponential" => ApplyExponential(normalized, strength),
_ => normalized // Linear
};
// å转(负片效果)
if (invert)
mapped = 1.0 - mapped;
_lut[i] = (byte)Math.Clamp((int)(mapped * 255.0), 0, 255);
}
}
/// <summary>S曲线(Sigmoid):增强中间调对比度</summary>
private static double ApplySigmoid(double x, double strength)
{
double k = strength * 10.0;
return 1.0 / (1.0 + Math.Exp(-k * (x - 0.5)));
}
/// <summary>对数曲线:æäº®æš—部,压缩亮部</summary>
private static double ApplyLogarithmic(double x, double strength)
{
double c = strength;
return Math.Log(1.0 + c * x) / Math.Log(1.0 + c);
}
/// <summary>指数曲线:压缩暗部,增强亮部</summary>
private static double ApplyExponential(double x, double strength)
{
double c = strength;
return (Math.Exp(c * x) - 1.0) / (Math.Exp(c) - 1.0);
}
}
@@ -0,0 +1,149 @@
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件å? PseudoColorProcessor.cs
// æè¿°: 伪色彩渲染算å­ï¼Œå°†ç°åº¦å›¾åƒæ˜ å°„为彩色图åƒ
// 功能:
// - 支æŒå¤šç§ OpenCV 内置色彩映射表(Jetã€Hotã€Coolã€Rainbow 等)
// - å¯é€‰ç°åº¦èŒƒå›´è£å‰ªï¼Œçªå‡ºæ„Ÿå…´è¶£çš„ç°åº¦åŒºé—´
// - å¯é€‰å转色彩映射方å?
// 算法: 查找表(LUT)色彩映�
// 作è€? æŽä¼Ÿ 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 PseudoColorProcessor : ImageProcessorBase
{
private static readonly ILogger _logger = Log.ForContext<PseudoColorProcessor>();
public PseudoColorProcessor()
{
Name = LocalizationHelper.GetString("PseudoColorProcessor_Name");
Description = LocalizationHelper.GetString("PseudoColorProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("ColorMap", new ProcessorParameter(
"ColorMap",
LocalizationHelper.GetString("PseudoColorProcessor_ColorMap"),
typeof(string),
"Jet",
null,
null,
LocalizationHelper.GetString("PseudoColorProcessor_ColorMap_Desc"),
new string[] { "Jet", "Hot", "Cool", "Rainbow", "HSV", "Turbo", "Inferno", "Magma", "Plasma", "Bone", "Ocean", "Spring", "Summer", "Autumn", "Winter" }));
Parameters.Add("MinValue", new ProcessorParameter(
"MinValue",
LocalizationHelper.GetString("PseudoColorProcessor_MinValue"),
typeof(int),
0,
0,
255,
LocalizationHelper.GetString("PseudoColorProcessor_MinValue_Desc")));
Parameters.Add("MaxValue", new ProcessorParameter(
"MaxValue",
LocalizationHelper.GetString("PseudoColorProcessor_MaxValue"),
typeof(int),
255,
0,
255,
LocalizationHelper.GetString("PseudoColorProcessor_MaxValue_Desc")));
Parameters.Add("InvertMap", new ProcessorParameter(
"InvertMap",
LocalizationHelper.GetString("PseudoColorProcessor_InvertMap"),
typeof(bool),
false,
null,
null,
LocalizationHelper.GetString("PseudoColorProcessor_InvertMap_Desc")));
_logger.Debug("InitializeParameters");
}
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
{
string colorMapName = GetParameter<string>("ColorMap");
int minValue = GetParameter<int>("MinValue");
int maxValue = GetParameter<int>("MaxValue");
bool invertMap = GetParameter<bool>("InvertMap");
OutputData.Clear();
// ç°åº¦èŒƒå›´è£å‰ªä¸Žå½’一åŒ?
Image<Gray, byte> normalized;
if (minValue > 0 || maxValue < 255)
{
// �[minValue, maxValue] 映射�[0, 255]
normalized = inputImage.Clone();
double scale = 255.0 / Math.Max(maxValue - minValue, 1);
for (int y = 0; y < normalized.Height; y++)
{
for (int x = 0; x < normalized.Width; x++)
{
int val = normalized.Data[y, x, 0];
val = Math.Clamp(val, minValue, maxValue);
normalized.Data[y, x, 0] = (byte)((val - minValue) * scale);
}
}
}
else
{
normalized = inputImage.Clone();
}
// å转ç°åº¦ï¼ˆå转色彩映射方å‘)
if (invertMap)
{
CvInvoke.BitwiseNot(normalized, normalized);
}
// 应用色彩映射
ColorMapType cmType = colorMapName switch
{
"Hot" => ColorMapType.Hot,
"Cool" => ColorMapType.Cool,
"Rainbow" => ColorMapType.Rainbow,
"HSV" => ColorMapType.Hsv,
"Turbo" => ColorMapType.Turbo,
"Inferno" => ColorMapType.Inferno,
"Magma" => ColorMapType.Magma,
"Plasma" => ColorMapType.Plasma,
"Bone" => ColorMapType.Bone,
"Ocean" => ColorMapType.Ocean,
"Spring" => ColorMapType.Spring,
"Summer" => ColorMapType.Summer,
"Autumn" => ColorMapType.Autumn,
"Winter" => ColorMapType.Winter,
_ => ColorMapType.Jet
};
using var colorMat = new Mat();
CvInvoke.ApplyColorMap(normalized.Mat, colorMat, cmType);
var colorImage = colorMat.ToImage<Bgr, byte>();
// 将彩色图åƒå­˜å…?OutputData,供 UI 显示
OutputData["PseudoColorImage"] = colorImage;
_logger.Debug("Process: ColorMap={ColorMap}, MinValue={Min}, MaxValue={Max}, InvertMap={Invert}",
colorMapName, minValue, maxValue, invertMap);
normalized.Dispose();
// 返回原始ç°åº¦å›¾åƒï¼ˆå½©è‰²å›¾åƒé€šè¿‡ OutputData 传递)
return inputImage.Clone();
}
}