// ============================================================================ // Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved. // 文件名: EmbossProcessor.cs // 描述: 浮雕伪3D效果处理器,模拟Viscom X-ray检测软件中的浮雕显示效果 // 功能: // - 方向性浮雕(8个方向可选) // - 可调节浮雕深度(强度) // - 可选灰度偏移(中灰基底) // - 支持与原图混合,实现伪3D立体感 // 算法: 方向性卷积核 + 灰度偏移 + Alpha混合 // 作者: 李伟 wei.lw.li@hexagon.com // ============================================================================ using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; using XP.ImageProcessing.Core; using Serilog; using System.Drawing; namespace XP.ImageProcessing.Processors; /// /// 浮雕伪3D效果处理器 /// 通过方向性卷积核模拟光照产生的凹凸立体感, /// 常用于X-ray图像的焊点、空洞等结构的可视化增强。 /// public class EmbossProcessor : ImageProcessorBase { private static readonly ILogger _logger = Log.ForContext(); public EmbossProcessor() { Name = LocalizationHelper.GetString("EmbossProcessor_Name"); Description = LocalizationHelper.GetString("EmbossProcessor_Description"); } protected override void InitializeParameters() { Parameters.Add("Direction", new ProcessorParameter( "Direction", LocalizationHelper.GetString("EmbossProcessor_Direction"), typeof(string), "TopLeft", null, null, LocalizationHelper.GetString("EmbossProcessor_Direction_Desc"), new string[] { "TopLeft", "Top", "TopRight", "Left", "Right", "BottomLeft", "Bottom", "BottomRight" })); Parameters.Add("Strength", new ProcessorParameter( "Strength", LocalizationHelper.GetString("EmbossProcessor_Strength"), typeof(double), 1.0, 0.1, 5.0, LocalizationHelper.GetString("EmbossProcessor_Strength_Desc"))); Parameters.Add("BlendRatio", new ProcessorParameter( "BlendRatio", LocalizationHelper.GetString("EmbossProcessor_BlendRatio"), typeof(double), 0.5, 0.0, 1.0, LocalizationHelper.GetString("EmbossProcessor_BlendRatio_Desc"))); Parameters.Add("GrayOffset", new ProcessorParameter( "GrayOffset", LocalizationHelper.GetString("EmbossProcessor_GrayOffset"), typeof(int), 128, 0, 255, LocalizationHelper.GetString("EmbossProcessor_GrayOffset_Desc"))); _logger.Debug("InitializeParameters"); } public override Image Process(Image inputImage) { string direction = GetParameter("Direction"); double strength = GetParameter("Strength"); double blendRatio = GetParameter("BlendRatio"); int grayOffset = GetParameter("GrayOffset"); // 获取方向性浮雕卷积核 float[,] kernelData = GetEmbossKernel(direction, strength); // 应用浮雕卷积 var kernel = new ConvolutionKernelF(kernelData); var embossed = new Image(inputImage.Size); CvInvoke.Filter2D(inputImage, embossed, kernel, new Point(-1, -1)); // 加灰度偏移,使平坦区域呈中灰色 var offset = new Image(inputImage.Size); offset.SetValue(new Gray(grayOffset)); var embossedWithOffset = embossed + offset; // 裁剪到 [0, 255] 并转为字节 var embossedByte = embossedWithOffset.Convert(); // 与原图混合实现伪3D效果 Image result; if (blendRatio < 0.001) { // 纯浮雕 result = embossedByte; } else if (blendRatio > 0.999) { // 纯原图 embossedByte.Dispose(); result = inputImage.Clone(); } else { // Alpha 混合: result = original * blendRatio + embossed * (1 - blendRatio) var floatOriginal = inputImage.Convert(); var floatEmbossed = embossedByte.Convert(); var blended = floatOriginal * blendRatio + floatEmbossed * (1.0 - blendRatio); result = blended.Convert(); floatOriginal.Dispose(); floatEmbossed.Dispose(); blended.Dispose(); embossedByte.Dispose(); } // 清理 kernel.Dispose(); embossed.Dispose(); offset.Dispose(); embossedWithOffset.Dispose(); _logger.Debug("Process: Direction={Direction}, Strength={Strength}, BlendRatio={BlendRatio}, GrayOffset={GrayOffset}", direction, strength, blendRatio, grayOffset); return result; } /// /// 根据方向和强度生成 3x3 浮雕卷积核 /// private static float[,] GetEmbossKernel(string direction, double strength) { float s = (float)strength; return direction switch { "TopLeft" => new float[,] { { -2 * s, -1 * s, 0 }, { -1 * s, 1, 1 * s }, { 0, 1 * s, 2 * s } }, "Top" => new float[,] { { -1 * s, -1 * s, -1 * s }, { 0, 1, 0 }, { 1 * s, 1 * s, 1 * s } }, "TopRight" => new float[,] { { 0, -1 * s, -2 * s }, { 1 * s, 1, -1 * s }, { 2 * s, 1 * s, 0 } }, "Left" => new float[,] { { -1 * s, 0, 1 * s }, { -1 * s, 1, 1 * s }, { -1 * s, 0, 1 * s } }, "Right" => new float[,] { { 1 * s, 0, -1 * s }, { 1 * s, 1, -1 * s }, { 1 * s, 0, -1 * s } }, "BottomLeft" => new float[,] { { 0, 1 * s, 2 * s }, { -1 * s, 1, 1 * s }, { -2 * s, -1 * s, 0 } }, "Bottom" => new float[,] { { 1 * s, 1 * s, 1 * s }, { 0, 1, 0 }, { -1 * s, -1 * s, -1 * s } }, "BottomRight" => new float[,] { { 2 * s, 1 * s, 0 }, { 1 * s, 1, -1 * s }, { 0, -1 * s, -2 * s } }, _ => new float[,] { { -2 * s, -1 * s, 0 }, { -1 * s, 1, 1 * s }, { 0, 1 * s, 2 * s } } }; } }