Files
XplorePlane/XP.ImageProcessing.Processors/图像增强/ContrastProcessor.cs
T
wei.lw.li 7768c086ea feat: 图像增强/变换算子标记高级参数+默认值优化
高级参数标记:Contrast(Contrast,Brightness,UseCLAHE,ClipLimit)、
Gamma(Gain)、Sharpen(Method,KernelSize)、Emboss(BlendRatio,GrayOffset)、
HistogramEq(Method,TileSize)、HDR(Method,Saturation,SigmaSpace,SigmaColor,Bias)、
Hierarchical(BaseGain,ClipLimit)、Retinex(Method,Sigma1/2/3,Offset)、
Rotate(ExpandCanvas,BackgroundValue,Interpolation)

默认值优化(适配平面CT DR图像):
- Sharpen: Laplacian→UnsharpMask(对噪声更温和)
- HistogramEq: Global→CLAHE(局部对比度更优)
- Contrast: AutoContrast默认开启
2026-08-12 09:25:34 +08:00

137 lines
5.3 KiB
C#

// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件名: ContrastProcessor.cs
// 描述: 对比度调整算子,用于增强图像对比度
// 功能:
// - 线性对比度和亮度调整
// - 自动对比度拉伸
// - CLAHE(对比度受限自适应直方图均衡化)
// - 支持多种对比度增强方法
// 算法: 线性变换、直方图均衡化、CLAHE
// 作者: 李伟 wei.lw.li@hexagon.com
// ============================================================================
using Emgu.CV;
using Emgu.CV.Structure;
using XP.ImageProcessing.Core;
using Serilog;
using System.Drawing;
namespace XP.ImageProcessing.Processors;
/// <summary>
/// 对比度调整算子(支持 8 位和 16 位灰度图像)
/// </summary>
public class ContrastProcessor<TDepth> : ImageProcessorBase<TDepth>
where TDepth : struct, IComparable
{
private static readonly ILogger _logger = Log.ForContext<ContrastProcessor<TDepth>>();
public ContrastProcessor()
{
Name = LocalizationHelper.GetString("ContrastProcessor_Name");
Description = LocalizationHelper.GetString("ContrastProcessor_Description");
}
protected override void InitializeParameters()
{
Parameters.Add("Contrast", new ProcessorParameter(
"Contrast",
LocalizationHelper.GetString("ContrastProcessor_Contrast"),
typeof(double),
1.0,
0.1,
3.0,
LocalizationHelper.GetString("ContrastProcessor_Contrast_Desc")) { IsAdvanced = true });
Parameters.Add("Brightness", new ProcessorParameter(
"Brightness",
LocalizationHelper.GetString("ContrastProcessor_Brightness"),
typeof(int),
0,
-100,
100,
LocalizationHelper.GetString("ContrastProcessor_Brightness_Desc")) { IsAdvanced = true });
Parameters.Add("AutoContrast", new ProcessorParameter(
"AutoContrast",
LocalizationHelper.GetString("ContrastProcessor_AutoContrast"),
typeof(bool),
true,
null,
null,
LocalizationHelper.GetString("ContrastProcessor_AutoContrast_Desc")));
Parameters.Add("UseCLAHE", new ProcessorParameter(
"UseCLAHE",
LocalizationHelper.GetString("ContrastProcessor_UseCLAHE"),
typeof(bool),
false,
null,
null,
LocalizationHelper.GetString("ContrastProcessor_UseCLAHE_Desc")) { IsAdvanced = true });
Parameters.Add("ClipLimit", new ProcessorParameter(
"ClipLimit",
LocalizationHelper.GetString("ContrastProcessor_ClipLimit"),
typeof(double),
2.0,
1.0,
10.0,
LocalizationHelper.GetString("ContrastProcessor_ClipLimit_Desc")) { IsAdvanced = true });
_logger.Debug("InitializeParameters");
}
public override Image<Gray, TDepth> Process(Image<Gray, TDepth> inputImage)
{
double contrast = GetParameter<double>("Contrast");
int brightness = GetParameter<int>("Brightness");
bool autoContrast = GetParameter<bool>("AutoContrast");
bool useCLAHE = GetParameter<bool>("UseCLAHE");
double clipLimit = GetParameter<double>("ClipLimit");
// 16 位时 brightness 按比例放大
if (typeof(TDepth) == typeof(ushort)) brightness *= 256;
if (useCLAHE)
{
// OpenCV CLAHE 原生支持 CV_8UC1 和 CV_16UC1,直接按位深处理,无需降位
var result = new Image<Gray, TDepth>(inputImage.Size);
CvInvoke.CLAHE(inputImage, clipLimit, new Size(8, 8), result);
_logger.Debug("Process (CLAHE native {Depth}bit): ClipLimit={ClipLimit}",
typeof(TDepth) == typeof(ushort) ? 16 : 8, clipLimit);
return result;
}
else if (autoContrast)
{
return AutoContrastStretch(inputImage);
}
else
{
// 线性对比度:result = input * contrast + brightness
var floatImg = inputImage.Convert<Gray, float>();
var result = floatImg * contrast;
if (brightness != 0) result = result + brightness;
floatImg.Dispose();
var r = PixelDepthHelper.FromFloatImageClamped<TDepth>(result);
result.Dispose();
_logger.Debug("Process: Contrast={C}, Brightness={B}", contrast, brightness);
return r;
}
}
private Image<Gray, TDepth> AutoContrastStretch(Image<Gray, TDepth> inputImage)
{
var floatImage = inputImage.Convert<Gray, float>();
double minVal = 0, maxVal = 0;
System.Drawing.Point minLoc = new System.Drawing.Point(), maxLoc = new System.Drawing.Point();
CvInvoke.MinMaxLoc(floatImage, ref minVal, ref maxVal, ref minLoc, ref maxLoc);
if (maxVal > minVal)
floatImage = (floatImage - minVal) * ((double)MaxPixelValue / (maxVal - minVal));
_logger.Debug("AutoContrastStretch: min={Min}, max={Max}", minVal, maxVal);
return PixelDepthHelper.FromFloatImage<TDepth>(floatImage);
}
}