//using HalconDotNet; //using System; //using System.Collections.Generic; //using System.Drawing.Imaging; //using System.IO; //namespace HalconTemplateMatch //{ // public class LogoMatcher // { // private List modelHandles = new List(); // /// // /// 从文件加载多个模板 // /// // public void LoadTemplates(string dir) // { // foreach (var file in Directory.GetFiles(dir, "*.shm")) // { // HTuple modelID; // HOperatorSet.ReadShapeModel(file, out modelID); // modelHandles.Add(modelID); // Console.WriteLine($"加载模板: {file}"); // } // } // /// // /// 在测试图像中查找 Logo // /// // /// true = OK,false = NG // public bool FindLogo(string testImagePath) // { // HObject ho_TestImage; // HOperatorSet.ReadImage(out ho_TestImage, testImagePath); // HOperatorSet.Rgb1ToGray(ho_TestImage, out ho_TestImage); // foreach (var modelID in modelHandles) // { // HOperatorSet.FindShapeModel( // ho_TestImage, // modelID, // new HTuple(0).TupleRad(), // new HTuple(360).TupleRad(), // 0.5, // 最低分数 // 1, // 最大匹配数 // 0.5, // 重叠度 // "least_squares", // 0, // 0.9, // out HTuple row, // out HTuple col, // out HTuple angle, // out HTuple score); // if (score.Length > 0 && score[0].D > 0.5) // { // Console.WriteLine($"找到 Logo: Row={row[0]}, Col={col[0]}, Score={score[0]}"); // return true; // 找到即返回成功 // } // } // return false; // 没找到 // } // /// // /// 重载FindLogo函数(double返回) // /// // /// // /// // public double FindLogo(Bitmap bmp) // { // // Bitmap 转 HObject // HObject ho_TestImage; // Bitmap2HObject(bmp, out ho_TestImage); // HOperatorSet.Rgb1ToGray(ho_TestImage, out ho_TestImage); // double bestScore = -1; // foreach (var modelID in modelHandles) // { // HOperatorSet.FindShapeModel( // ho_TestImage, // modelID, // new HTuple(0).TupleRad(), // new HTuple(360).TupleRad(), // 0.5, // 最低分数 // 1, // 最大匹配数 // 0.5, // 重叠度 // "least_squares", // 0, // 0.9, // out HTuple row, // out HTuple col, // out HTuple angle, // out HTuple score); // if (score.Length > 0 && score[0].D > bestScore) // { // bestScore = score[0].D; // } // } // ho_TestImage.Dispose(); // return bestScore; // -1 = 没找到 // } // /// // /// Bitmap 转 Halcon HObject // /// // private void Bitmap2HObject(Bitmap bmp, out HObject hobj) // { // HOperatorSet.GenEmptyObj(out hobj); // Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); // BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); // try // { // HOperatorSet.GenImageInterleaved( // out hobj, // bmpData.Scan0, // "bgr", // Bitmap 默认是 BGR // bmp.Width, // bmp.Height, // 0, // "byte", // bmp.Width, // bmp.Height, // 0, // 0, // -1, // 0 // ); // } // finally // { // bmp.UnlockBits(bmpData); // } // } // } //} using HalconDotNet; using NPOI.OpenXmlFormats.Vml; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; namespace HalconTemplateMatch { public class LogoMatcher { private readonly List modelHandles = new List(); // 构造函数用于初始化 public LogoMatcher() { } /// /// 从指定目录加载所有 .shm 模板文件 /// public void LoadTemplates(string dir) { try { string fullPath = Path.GetFullPath(dir); if (!Directory.Exists(fullPath)) { Console.WriteLine($"[警告] 模型目录不存在: {fullPath}"); return; } string[] modelFiles = Directory.GetFiles(fullPath, "*.shm", SearchOption.TopDirectoryOnly); if (modelFiles.Length == 0) { Console.WriteLine($"[警告] 模型目录中没有任何 .shm 文件: {fullPath}"); return; } foreach (var file in modelFiles) { try { HTuple modelID; HOperatorSet.ReadShapeModel(file, out modelID); modelHandles.Add(modelID); Console.WriteLine($"[加载成功] 模板: {file}"); } catch (HOperatorException ex) { Console.WriteLine($"[错误] 无法加载模板 {file}: {ex.Message}"); } } if (modelHandles.Count == 0) { Console.WriteLine($"[警告] 没有成功加载任何模板文件。"); } } catch (Exception ex) { Console.WriteLine($"[异常] 加载模板目录出错: {ex.Message}"); } } // /// // /// 匹配并返回最高得分(double返回) // /// // public double FindLogo(Bitmap bmp) // { // if (modelHandles.Count == 0) // { // Console.WriteLine("[警告] 尚未加载任何模板。"); // return -1; // } // // Bitmap 转 Halcon 对象 // HObject ho_TestImage; // Bitmap2HObject(bmp, out ho_TestImage); // HOperatorSet.Rgb1ToGray(ho_TestImage, out ho_TestImage); // double bestScore = -1; // foreach (var modelID in modelHandles) // { // try // { // HOperatorSet.FindScaledShapeModel( // ho_TestImage, // modelID, // new HTuple(0).TupleRad(), // new HTuple(360).TupleRad(), // 0.8, 1.2, // 0.5, 1, 0.5, // "least_squares_high", // 0, 0.9, // out HTuple row, out HTuple col, out HTuple angle, out HTuple scale, out HTuple score //); // if (score.Length > 0 && score[0].D > bestScore) // bestScore = score[0].D; // } // catch (HOperatorException ex) // { // Console.WriteLine($"[错误] 模板匹配失败: {ex.Message}"); // } // } // ho_TestImage.Dispose(); // return bestScore; // } public double FindLogo(Bitmap bmp, out Bitmap resultImage) // 返回结果图像 { if (modelHandles.Count == 0) { Console.WriteLine("[警告] 尚未加载任何模板。"); resultImage = (Bitmap)bmp.Clone(); return -1; } HObject ho_TestImage; Bitmap2HObject(bmp, out ho_TestImage); HOperatorSet.Rgb1ToGray(ho_TestImage, out ho_TestImage); double bestScore = -1; HTuple bestRow = new HTuple(), bestCol = new HTuple(), bestAngle = new HTuple(), bestScale = new HTuple(); int bestModelIndex = -1; for (int i = 0; i < modelHandles.Count; i++) { var modelID = modelHandles[i]; try { HOperatorSet.FindScaledShapeModel( ho_TestImage, modelID, new HTuple(0).TupleRad(), new HTuple(360).TupleRad(), 0.8, 1.2, 0.5, 1, 0.5, "least_squares_high", 0, 0.9, out HTuple row, out HTuple col, out HTuple angle, out HTuple scale, out HTuple score ); if (score.Length > 0 && score[0].D > bestScore) { bestScore = score[0].D; bestRow = row; bestCol = col; bestAngle = angle; bestScale = scale; bestModelIndex = i; } } catch (HOperatorException ex) { //Console.WriteLine($"[错误] 模板匹配失败: {ex.Message}"); // 避免过多日志 } } resultImage = DrawHalconResults(bmp, bestModelIndex >= 0 ? modelHandles[bestModelIndex] : new HTuple(), bestRow, bestCol, bestAngle, bestScale, bestScore); ho_TestImage.Dispose(); return bestScore; } //private Bitmap DrawHalconResults(Bitmap originalBmp, HTuple modelID, HTuple row, HTuple col, HTuple angle, HTuple scale, double score) //{ // Bitmap drawnBmp = (Bitmap)originalBmp.Clone(); // if (score <= 0 || modelID.Length == 0) return drawnBmp; // 未找到或分数过低不绘制 // using (Graphics g = Graphics.FromImage(drawnBmp)) // { // Pen pen = (score > 0.7) ? new Pen(Color.Green, 3) : new Pen(Color.Orange, 3); // 可以根据分数改变颜色 // Font font = new Font("Arial", 12, FontStyle.Bold); // Brush brush = (score > 0.7) ? new SolidBrush(Color.Green) : new SolidBrush(Color.Orange); // // 获取匹配模板的轮廓 // HOperatorSet.GetShapeModelContours(out HObject modelContours, modelID, 1); // // 转换到图像坐标 // HOperatorSet.AffineTransContourXld(modelContours, out HObject transformedContours, // new HTuple(angle), new HTuple(scale), new HTuple(row), new HTuple(col), // "fit_origin"); // 假设 FindScaledShapeModel 的 row/col 是中心 // // 绘制 XLD 轮廓 // HTuple numContours; // HOperatorSet.CountObj(transformedContours, out numContours); // for (int i = 1; i <= numContours; i++) // { // HOperatorSet.SelectObj(transformedContours, out HObject currentContour, i); // HOperatorSet.GetContourXld(currentContour, out HTuple contourRow, out HTuple contourCol); // if (contourRow.Length > 1) // { // Point[] points = new Point[contourRow.Length]; // for (int j = 0; j < contourRow.Length; j++) // { // points[j] = new Point((int)contourCol.DArr[j], (int)contourRow.DArr[j]); // } // g.DrawPolygon(pen, points); // } // currentContour.Dispose(); // } // // 绘制得分 // if (row.Length > 0 && col.Length > 0) // { // g.DrawString($"Score: {score:F2}", font, brush, (float)col.D - 50, (float)row.D - 50); // } // modelContours.Dispose(); // transformedContours.Dispose(); // } // return drawnBmp; //} private Bitmap DrawHalconResults(Bitmap originalBmp, HTuple modelID, HTuple row, HTuple col, HTuple angle, HTuple scale, double score) { // 克隆输入图像用于绘制 Bitmap drawnBmp = (Bitmap)originalBmp.Clone(); // 如果未找到匹配,不绘制任何内容 if (score <= 0 || modelID.Length == 0) return drawnBmp; using (Graphics g = Graphics.FromImage(drawnBmp)) { // 绘制样式:高分绿色、低分橙色 Pen pen = (score > 0.7) ? new Pen(Color.Green, 3) : new Pen(Color.Orange, 3); Font font = new Font("Arial", 12, FontStyle.Bold); Brush brush = (score > 0.7) ? new SolidBrush(Color.Green) : new SolidBrush(Color.Orange); // 1️⃣ 获取模板的轮廓 HOperatorSet.GetShapeModelContours(out HObject modelContours, modelID, 1); // 2️⃣ 构建仿射变换矩阵 HTuple homMat2D; HOperatorSet.HomMat2dIdentity(out homMat2D); // 初始化单位矩阵 HOperatorSet.HomMat2dScale(homMat2D, scale, scale, 0, 0, out homMat2D); // 缩放 HOperatorSet.HomMat2dRotate(homMat2D, angle, 0, 0, out homMat2D); // 旋转 HOperatorSet.HomMat2dTranslate(homMat2D, col, row, out homMat2D); // 平移 // 3️⃣ 将轮廓按仿射矩阵变换 HOperatorSet.AffineTransContourXld(modelContours, out HObject transformedContours, homMat2D); // 4️⃣ 统计轮廓数量并逐一绘制 HOperatorSet.CountObj(transformedContours, out HTuple numContours); for (int i = 1; i <= numContours; i++) { HOperatorSet.SelectObj(transformedContours, out HObject currentContour, i); HOperatorSet.GetContourXld(currentContour, out HTuple contourRow, out HTuple contourCol); if (contourRow.Length > 1) { Point[] points = new Point[contourRow.Length]; for (int j = 0; j < contourRow.Length; j++) { points[j] = new Point((int)contourCol[j].D, (int)contourRow[j].D); } g.DrawPolygon(pen, points); } currentContour.Dispose(); } // 5️⃣ 绘制得分文字 if (row.Length > 0 && col.Length > 0) { g.DrawString($"Score: {score:F2}", font, brush, (float)col.D - 50, (float)row.D - 50); } // 6️⃣ 清理资源 modelContours.Dispose(); transformedContours.Dispose(); // 释放 GDI+ 对象 pen.Dispose(); font.Dispose(); brush.Dispose(); } return drawnBmp; } /// /// Bitmap 转 Halcon HObject /// private void Bitmap2HObject(Bitmap bmp, out HObject hobj) { HOperatorSet.GenEmptyObj(out hobj); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); try { HOperatorSet.GenImageInterleaved( out hobj, bmpData.Scan0, "bgr", bmp.Width, bmp.Height, 0, "byte", bmp.Width, bmp.Height, 0, 0, -1, 0); } finally { bmp.UnlockBits(bmpData); } } } }