142 lines
5.0 KiB
C#
142 lines
5.0 KiB
C#
// ============================================================================
|
|
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
|
|
// 文件名: HistogramEqualizationProcessor.cs
|
|
// 描述: 直方图均衡化算子,用于增强图像对比度
|
|
// 功能:
|
|
// - 全局直方图均衡化
|
|
// - 自适应直方图均衡化(CLAHE)
|
|
// - 限制对比度增强
|
|
// - 改善图像的整体对比度
|
|
// 算法: 直方图均衡化、CLAHE
|
|
// 作者: 李伟 wei.lw.li@hexagon.com
|
|
// ============================================================================
|
|
|
|
using Emgu.CV;
|
|
using Emgu.CV.Structure;
|
|
using XP.ImageProcessing.Core;
|
|
using Serilog;
|
|
|
|
namespace XP.ImageProcessing.Processors;
|
|
|
|
/// <summary>
|
|
/// 直方图均衡化算子
|
|
/// </summary>
|
|
public class HistogramEqualizationProcessor : ImageProcessorBase
|
|
{
|
|
private static readonly ILogger _logger = Log.ForContext<HistogramEqualizationProcessor>();
|
|
|
|
public HistogramEqualizationProcessor()
|
|
{
|
|
Name = LocalizationHelper.GetString("HistogramEqualizationProcessor_Name");
|
|
Description = LocalizationHelper.GetString("HistogramEqualizationProcessor_Description");
|
|
}
|
|
|
|
protected override void InitializeParameters()
|
|
{
|
|
Parameters.Add("Method", new ProcessorParameter(
|
|
"Method",
|
|
LocalizationHelper.GetString("HistogramEqualizationProcessor_Method"),
|
|
typeof(string),
|
|
"Global",
|
|
null,
|
|
null,
|
|
LocalizationHelper.GetString("HistogramEqualizationProcessor_Method_Desc"),
|
|
new string[] { "Global", "CLAHE" }));
|
|
|
|
Parameters.Add("ClipLimit", new ProcessorParameter(
|
|
"ClipLimit",
|
|
LocalizationHelper.GetString("HistogramEqualizationProcessor_ClipLimit"),
|
|
typeof(double),
|
|
2.0,
|
|
1.0,
|
|
10.0,
|
|
LocalizationHelper.GetString("HistogramEqualizationProcessor_ClipLimit_Desc")));
|
|
|
|
Parameters.Add("TileSize", new ProcessorParameter(
|
|
"TileSize",
|
|
LocalizationHelper.GetString("HistogramEqualizationProcessor_TileSize"),
|
|
typeof(int),
|
|
8,
|
|
4,
|
|
32,
|
|
LocalizationHelper.GetString("HistogramEqualizationProcessor_TileSize_Desc")));
|
|
_logger.Debug("InitializeParameters");
|
|
}
|
|
|
|
public override Image<Gray, byte> Process(Image<Gray, byte> inputImage)
|
|
{
|
|
string method = GetParameter<string>("Method");
|
|
double clipLimit = GetParameter<double>("ClipLimit");
|
|
int tileSize = GetParameter<int>("TileSize");
|
|
|
|
Image<Gray, byte> result;
|
|
|
|
if (method == "CLAHE")
|
|
{
|
|
result = ApplyCLAHE(inputImage, clipLimit, tileSize);
|
|
}
|
|
else // Global
|
|
{
|
|
result = new Image<Gray, byte>(inputImage.Size);
|
|
CvInvoke.EqualizeHist(inputImage, result);
|
|
}
|
|
|
|
_logger.Debug("Process: Method = {Method}, ClipLimit = {ClipLimit}, TileSize = {TileSize}",
|
|
method, clipLimit, tileSize);
|
|
return result;
|
|
}
|
|
|
|
private Image<Gray, byte> ApplyCLAHE(Image<Gray, byte> inputImage, double clipLimit, int tileSize)
|
|
{
|
|
int width = inputImage.Width;
|
|
int height = inputImage.Height;
|
|
|
|
int tilesX = (width + tileSize - 1) / tileSize;
|
|
int tilesY = (height + tileSize - 1) / tileSize;
|
|
|
|
var result = new Image<Gray, byte>(width, height);
|
|
|
|
// 对每个tile进行直方图均衡化
|
|
for (int ty = 0; ty < tilesY; ty++)
|
|
{
|
|
for (int tx = 0; tx < tilesX; tx++)
|
|
{
|
|
int x = tx * tileSize;
|
|
int y = ty * tileSize;
|
|
int w = Math.Min(tileSize, width - x);
|
|
int h = Math.Min(tileSize, height - y);
|
|
|
|
var roi = new System.Drawing.Rectangle(x, y, w, h);
|
|
inputImage.ROI = roi;
|
|
var tile = inputImage.Copy();
|
|
inputImage.ROI = System.Drawing.Rectangle.Empty;
|
|
|
|
// 应用直方图均衡化
|
|
var equalizedTile = new Image<Gray, byte>(tile.Size);
|
|
CvInvoke.EqualizeHist(tile, equalizedTile);
|
|
|
|
// 应用限制(简化版本)
|
|
var floatTile = tile.Convert<Gray, float>();
|
|
var floatEqualized = equalizedTile.Convert<Gray, float>();
|
|
var diff = floatEqualized - floatTile;
|
|
var limited = floatTile + diff * Math.Min(clipLimit / 10.0, 1.0);
|
|
var limitedByte = limited.Convert<Gray, byte>();
|
|
|
|
// 复制到结果图像
|
|
result.ROI = roi;
|
|
limitedByte.CopyTo(result);
|
|
result.ROI = System.Drawing.Rectangle.Empty;
|
|
|
|
tile.Dispose();
|
|
equalizedTile.Dispose();
|
|
floatTile.Dispose();
|
|
floatEqualized.Dispose();
|
|
diff.Dispose();
|
|
limited.Dispose();
|
|
limitedByte.Dispose();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
} |