Files
XplorePlane/XP.ImageProcessing.Core/ImageProcessorBase.cs
T
2026-04-20 11:13:40 +08:00

217 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位图像处理算子基类,定义图像处理算子的通用接口和行为
// 功能:
// - 定义算子的基本属性(名称、描述)
// - 参数管理(设置、获取、验证)
// - ROI(感兴趣区域)处理支持
// - 输出数据管理(用于传递额外信息如轮廓等)
// - 为所有8位图像处理算子提供统一的基础框架
// 设计模式: 模板方法模式
// 作者: 李伟 wei.lw.li@hexagon.com
// ============================================================================
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using System.Globalization;
namespace XP.ImageProcessing.Core;
/// <summary>
/// 图像处理算子基类
/// </summary>
public abstract class ImageProcessorBase
{
/// <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; }
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, byte> Process(Image<Gray, byte> inputImage);
/// <summary>
/// 执行图像处理(带矩形ROI支持)
/// </summary>
public Image<Gray, byte> ProcessWithROI(Image<Gray, byte> 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);
// 将 ROI 偏移量保存到输出数据中,供轮廓绘制等使用
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, byte> ProcessWithPolygonROI(Image<Gray, byte> 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));
// 绘制多边形掩码(白色表示ROI区域)
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();
// 使用掩码:ROI内使用处理后的像素,ROI外保持原始像素
for (int y = 0; y < inputImage.Height; y++)
{
for (int x = 0; x < inputImage.Width; x++)
{
if (mask.Data[y, x, 0] > 0) // 在ROI内
{
result.Data[y, x, 0] = processedImage.Data[y, x, 0];
}
}
}
// 保存ROI信息
OutputData["ROIMask"] = mask;
OutputData["PolygonPoints"] = PolygonROIPoints;
OutputData["ROIOffset"] = System.Drawing.Point.Empty;
processedImage.Dispose();
return result;
}
/// <summary>
/// 获取所有参数列表
/// </summary>
public List<ProcessorParameter> GetParameters()
{
return 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);
}
}
private static string NormalizeText(string value)
{
return value.Trim().TrimEnd('、', '', ',', '。', '.', ';', '', ':', '');
}
/// <summary>
/// 获取单个参数
/// </summary>
public ProcessorParameter? GetParameterInfo(string name)
{
return Parameters.ContainsKey(name) ? Parameters[name] : null;
}
}