// ============================================================================
// 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;
///
/// 对比度调整算子(支持 8 位和 16 位灰度图像)
///
public class ContrastProcessor : ImageProcessorBase
where TDepth : struct, IComparable
{
private static readonly ILogger _logger = Log.ForContext>();
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 Process(Image inputImage)
{
double contrast = GetParameter("Contrast");
int brightness = GetParameter("Brightness");
bool autoContrast = GetParameter("AutoContrast");
bool useCLAHE = GetParameter("UseCLAHE");
double clipLimit = GetParameter("ClipLimit");
// 16 位时 brightness 按比例放大
if (typeof(TDepth) == typeof(ushort)) brightness *= 256;
if (useCLAHE)
{
// OpenCV CLAHE 原生支持 CV_8UC1 和 CV_16UC1,直接按位深处理,无需降位
var result = new Image(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();
var result = floatImg * contrast;
if (brightness != 0) result = result + brightness;
floatImg.Dispose();
var r = PixelDepthHelper.FromFloatImageClamped(result);
result.Dispose();
_logger.Debug("Process: Contrast={C}, Brightness={B}", contrast, brightness);
return r;
}
}
private Image AutoContrastStretch(Image inputImage)
{
var floatImage = inputImage.Convert();
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(floatImage);
}
}