Files
XplorePlane/XP.ImageProcessing.Processors/Core/ImageProcessorBase.cs
T
李伟 6d27a02a9b feat(算子库): ImageProcessorBase 升级为泛型基类,支持 byte/ushort 双位深
- ImageProcessorBase<TDepth> 泛型基类,where TDepth : struct, IComparable
- 保留 ImageProcessorBase 别名(= ImageProcessorBase<byte>)完全向后兼容
- 新增 PixelDepthHelper 工具类,封装 byte/ushort 转换、像素读写、阈值缩放等通用操作
- MaxPixelValue 属性动态返回位深最大值(byte=255,ushort=65535)
2026-06-16 11:48:19 +08:00

193 lines
6.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================================
// Copyright © 2026 Hexagon Technology Center GmbH. All Rights Reserved.
// 文件名: ImageProcessorBase.cs
// 描述: 图像处理算子泛型基类,支持 8 位(byte)和 16 位(ushort)灰度图像
// 功能:
// - 定义算子的基本属性(名称、描述)
// - 参数管理(设置、获取、验证)
// - ROI(感兴趣区域)处理支持
// - 输出数据管理(用于传递额外信息如轮廓等)
// - 为所有图像处理算子提供统一的基础框架
// 设计模式: 模板方法模式
// 作者: 李伟 wei.lw.li@hexagon.com
// ============================================================================
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using System.Globalization;
namespace XP.ImageProcessing.Core;
/// <summary>
/// 图像处理算子泛型基类。
/// <typeparam name="TDepth">像素深度类型:<see cref="byte"/>8位)或 <see cref="ushort"/>16位)。</typeparam>
/// </summary>
public abstract class ImageProcessorBase<TDepth> where TDepth : struct, IComparable
{
/// <summary>算子名称</summary>
public string Name { get; protected set; } = string.Empty;
/// <summary>算子描述</summary>
public string Description { get; protected set; } = string.Empty;
/// <summary>参数字典</summary>
protected Dictionary<string, ProcessorParameter> Parameters { get; set; }
/// <summary>输出数据(用于传递额外信息如轮廓等)</summary>
public Dictionary<string, object> OutputData { get; protected set; }
/// <summary>ROI区域</summary>
public System.Drawing.Rectangle? ROI { get; set; }
/// <summary>多边形ROI点集</summary>
public System.Drawing.Point[]? PolygonROIPoints { get; set; }
/// <summary>当前图像位深的最大像素值(byte=255ushort=65535</summary>
protected int MaxPixelValue => typeof(TDepth) == typeof(ushort) ? 65535 : 255;
protected ImageProcessorBase()
{
Parameters = new Dictionary<string, ProcessorParameter>();
OutputData = new Dictionary<string, object>();
InitializeParameters();
}
/// <summary>
/// 初始化算子参数(子类实现)
/// </summary>
protected abstract void InitializeParameters();
/// <summary>
/// 执行图像处理(子类实现)
/// </summary>
public abstract Image<Gray, TDepth> Process(Image<Gray, TDepth> inputImage);
/// <summary>
/// 执行图像处理(带矩形ROI支持)
/// </summary>
public Image<Gray, TDepth> ProcessWithROI(Image<Gray, TDepth> inputImage)
{
if (ROI.HasValue && ROI.Value != System.Drawing.Rectangle.Empty)
{
inputImage.ROI = ROI.Value;
var roiImage = inputImage.Copy();
inputImage.ROI = System.Drawing.Rectangle.Empty;
var processedROI = Process(roiImage);
OutputData["ROIOffset"] = new System.Drawing.Point(ROI.Value.X, ROI.Value.Y);
var result = inputImage.Clone();
result.ROI = ROI.Value;
processedROI.CopyTo(result);
result.ROI = System.Drawing.Rectangle.Empty;
roiImage.Dispose();
processedROI.Dispose();
return result;
}
return Process(inputImage);
}
/// <summary>
/// 执行图像处理(带多边形ROI掩码支持)
/// </summary>
public Image<Gray, TDepth> ProcessWithPolygonROI(Image<Gray, TDepth> inputImage)
{
if (PolygonROIPoints == null || PolygonROIPoints.Length < 3)
return Process(inputImage);
var mask = new Image<Gray, byte>(inputImage.Width, inputImage.Height);
mask.SetValue(new Gray(0));
using (var vop = new VectorOfPoint(PolygonROIPoints))
using (var vvop = new VectorOfVectorOfPoint(vop))
{
CvInvoke.DrawContours(mask, vvop, 0, new MCvScalar(255), -1);
}
var processedImage = Process(inputImage);
var result = inputImage.Clone();
for (int y = 0; y < inputImage.Height; y++)
{
for (int x = 0; x < inputImage.Width; x++)
{
if (mask.Data[y, x, 0] > 0)
result.Data[y, x, 0] = processedImage.Data[y, x, 0];
}
}
OutputData["ROIMask"] = mask;
OutputData["PolygonPoints"] = PolygonROIPoints;
OutputData["ROIOffset"] = System.Drawing.Point.Empty;
processedImage.Dispose();
return result;
}
/// <summary>获取所有参数列表</summary>
public List<ProcessorParameter> GetParameters()
=> new List<ProcessorParameter>(Parameters.Values);
/// <summary>设置参数值</summary>
public void SetParameter(string name, object value)
{
if (Parameters.ContainsKey(name))
Parameters[name].Value = value;
else
throw new ArgumentException($"参数 {name} 不存在");
}
/// <summary>获取参数值</summary>
public T GetParameter<T>(string name)
{
if (!Parameters.ContainsKey(name))
throw new ArgumentException($"参数 {name} 不存在");
var parameter = Parameters[name];
try
{
if (parameter.Value is T typedValue)
return typedValue;
if (parameter.Value is string textValue)
{
var normalizedText = NormalizeText(textValue);
if (typeof(T) == typeof(string))
return (T)(object)textValue;
if (typeof(T) == typeof(int) && int.TryParse(normalizedText, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
return (T)(object)intValue;
if (typeof(T) == typeof(double) && double.TryParse(normalizedText, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var doubleValue))
return (T)(object)doubleValue;
if (typeof(T) == typeof(bool) && bool.TryParse(normalizedText, out var boolValue))
return (T)(object)boolValue;
}
return (T)Convert.ChangeType(parameter.Value, typeof(T), CultureInfo.InvariantCulture)!;
}
catch (Exception ex)
{
throw new ArgumentException(
$"参数 {name} 的值 '{parameter.Value}' 无法转换为 {typeof(T).Name}", ex);
}
}
/// <summary>获取单个参数信息</summary>
public ProcessorParameter? GetParameterInfo(string name)
=> Parameters.ContainsKey(name) ? Parameters[name] : null;
private static string NormalizeText(string value)
=> value.Trim().TrimEnd('、', '', ',', '。', '.', ';', '', ':', '');
}
/// <summary>
/// 8 位灰度图像算子基类别名(向后兼容)
/// </summary>
public abstract class ImageProcessorBase : ImageProcessorBase<byte> { }