// ============================================================================ // TemplateMatchNative.cs // C++ DLL P/Invoke 封装层 // 提供对 TemplateMatchLib.dll 的托管调用接口 // ============================================================================ using System; using System.Runtime.InteropServices; namespace XP.ImageProcessing.Processors; /// /// 匹配参数(与C++ TM_Params对应) /// [StructLayout(LayoutKind.Sequential)] public struct TM_Params { /// 匹配阈值 (0~1) public double Score; /// 角度容差 (度),0表示不旋转 public double ToleranceAngle; /// 最大重叠比例 (0~1) public double MaxOverlap; /// 最大匹配数 public int MaxCount; /// 金字塔最小面积,默认256 public int MinReduceArea; /// 是否使用SIMD加速 (1=是, 0=否) public int UseSIMD; /// 是否亚像素估计 (1=是, 0=否) public int UseSubPixel; /// /// 创建默认参数 /// public static TM_Params Default => new TM_Params { Score = 0.75, ToleranceAngle = 0, MaxOverlap = 0.3, MaxCount = 1, MinReduceArea = 256, UseSIMD = 1, UseSubPixel = 0 }; } /// /// 单个匹配结果(与C++ TM_Result对应) /// [StructLayout(LayoutKind.Sequential)] public struct TM_Result { /// 匹配中心X public double CenterX; /// 匹配中心Y public double CenterY; /// 匹配角度 (度) public double Angle; /// 匹配分数 public double Score; /// 左上角X public double LtX; /// 左上角Y public double LtY; /// 右上角X public double RtX; /// 右上角Y public double RtY; /// 右下角X public double RbX; /// 右下角Y public double RbY; /// 左下角X public double LbX; /// 左下角Y public double LbY; } /// /// TemplateMatchLib.dll P/Invoke 接口 /// public static class TemplateMatchNative { private const string DllName = "TemplateMatchLib.dll"; /// 创建匹配器实例 [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr TM_Create(); /// 销毁匹配器实例 [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] public static extern void TM_Destroy(IntPtr handle); /// 从内存数据学习模板 [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] public static extern int TM_LearnPattern(IntPtr handle, IntPtr templateData, int width, int height, int step); /// 从文件学习模板 [DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern int TM_LearnPatternFromFile(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string filePath); /// 执行模板匹配 [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] public static extern int TM_Match(IntPtr handle, IntPtr srcData, int srcWidth, int srcHeight, int srcStep, ref TM_Params param, [Out] TM_Result[] results, int maxResults); /// 获取上次匹配耗时(毫秒) [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] public static extern double TM_GetLastMatchTime(IntPtr handle); /// 获取模板信息 [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] public static extern int TM_GetTemplateInfo(IntPtr handle, out int width, out int height, out int pyramidLayers); /// 保存训练好的模型到文件 [DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern int TM_SaveModel(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string filePath); /// 从文件加载已训练的模型 [DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern int TM_LoadModel(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string filePath); } /// /// 模板匹配器托管封装(自动管理非托管资源) /// public sealed class TemplateMatcherHandle : IDisposable { private IntPtr _handle; private bool _disposed; public TemplateMatcherHandle() { _handle = TemplateMatchNative.TM_Create(); if (_handle == IntPtr.Zero) throw new InvalidOperationException("Failed to create TemplateMatcher instance"); } /// /// 从文件学习模板 /// public bool LearnPatternFromFile(string filePath) { ThrowIfDisposed(); return TemplateMatchNative.TM_LearnPatternFromFile(_handle, filePath) == 0; } /// /// 从EmguCV Image学习模板 /// public bool LearnPattern(IntPtr data, int width, int height, int step) { ThrowIfDisposed(); return TemplateMatchNative.TM_LearnPattern(_handle, data, width, height, step) == 0; } /// /// 执行匹配 /// public TM_Result[] Match(IntPtr srcData, int srcWidth, int srcHeight, int srcStep, TM_Params param) { ThrowIfDisposed(); var results = new TM_Result[param.MaxCount]; int count = TemplateMatchNative.TM_Match(_handle, srcData, srcWidth, srcHeight, srcStep, ref param, results, param.MaxCount); if (count <= 0) return Array.Empty(); if (count < results.Length) Array.Resize(ref results, count); return results; } /// /// 获取上次匹配耗时(毫秒) /// public double LastMatchTime { get { ThrowIfDisposed(); return TemplateMatchNative.TM_GetLastMatchTime(_handle); } } /// /// 获取模板信息 /// public bool GetTemplateInfo(out int width, out int height, out int pyramidLayers) { ThrowIfDisposed(); return TemplateMatchNative.TM_GetTemplateInfo(_handle, out width, out height, out pyramidLayers) == 0; } /// /// 保存训练好的模型到文件 /// /// 模型文件路径(建议扩展名 .tmmodel) /// 是否成功 public bool SaveModel(string filePath) { ThrowIfDisposed(); return TemplateMatchNative.TM_SaveModel(_handle, filePath) == 0; } /// /// 从文件加载已训练的模型(跳过LearnPattern) /// /// 模型文件路径 /// 是否成功 public bool LoadModel(string filePath) { ThrowIfDisposed(); return TemplateMatchNative.TM_LoadModel(_handle, filePath) == 0; } private void ThrowIfDisposed() { if (_disposed) throw new ObjectDisposedException(nameof(TemplateMatcherHandle)); } public void Dispose() { if (!_disposed) { if (_handle != IntPtr.Zero) { TemplateMatchNative.TM_Destroy(_handle); _handle = IntPtr.Zero; } _disposed = true; } } ~TemplateMatcherHandle() { Dispose(); } }