// ============================================================================ // 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); } }