207 lines
6.9 KiB
C#
207 lines
6.9 KiB
C#
// ============================================================================
|
|
// 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;
|
|
|
|
/// <summary>
|
|
/// 浮雕伪3D效果处理器
|
|
/// 通过方向性卷积核模拟光照产生的凹凸立体感,
|
|
/// 常用于X-ray图像的焊点、空洞等结构的可视化增强。
|
|
/// </summary>
|
|
public class EmbossProcessor : ImageProcessorBase
|
|
{
|
|
private static readonly ILogger _logger = Log.ForContext<EmbossProcessor>();
|
|
|
|
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<Gray, byte> Process(Image<Gray, byte> inputImage)
|
|
{
|
|
string direction = GetParameter<string>("Direction");
|
|
double strength = GetParameter<double>("Strength");
|
|
double blendRatio = GetParameter<double>("BlendRatio");
|
|
int grayOffset = GetParameter<int>("GrayOffset");
|
|
|
|
// 获取方向性浮雕卷积核
|
|
float[,] kernelData = GetEmbossKernel(direction, strength);
|
|
|
|
// 应用浮雕卷积
|
|
var kernel = new ConvolutionKernelF(kernelData);
|
|
var embossed = new Image<Gray, float>(inputImage.Size);
|
|
CvInvoke.Filter2D(inputImage, embossed, kernel, new Point(-1, -1));
|
|
|
|
// 加灰度偏移,使平坦区域呈中灰色
|
|
var offset = new Image<Gray, float>(inputImage.Size);
|
|
offset.SetValue(new Gray(grayOffset));
|
|
var embossedWithOffset = embossed + offset;
|
|
|
|
// 裁剪到 [0, 255] 并转为字节
|
|
var embossedByte = embossedWithOffset.Convert<Gray, byte>();
|
|
|
|
// 与原图混合实现伪3D效果
|
|
Image<Gray, byte> 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<Gray, float>();
|
|
var floatEmbossed = embossedByte.Convert<Gray, float>();
|
|
var blended = floatOriginal * blendRatio + floatEmbossed * (1.0 - blendRatio);
|
|
result = blended.Convert<Gray, byte>();
|
|
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据方向和强度生成 3x3 浮雕卷积核
|
|
/// </summary>
|
|
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 }
|
|
}
|
|
};
|
|
}
|
|
}
|