471 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			471 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //using HalconDotNet;
 | ||
| //using System;
 | ||
| //using System.Collections.Generic;
 | ||
| //using System.Drawing.Imaging;
 | ||
| //using System.IO;
 | ||
| 
 | ||
| //namespace HalconTemplateMatch
 | ||
| //{
 | ||
| //    public class LogoMatcher
 | ||
| //    {
 | ||
| //        private List<HTuple> modelHandles = new List<HTuple>();
 | ||
| 
 | ||
| //        /// <summary>
 | ||
| //        /// 从文件加载多个模板
 | ||
| //        /// </summary>
 | ||
| //        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}");
 | ||
| //            }
 | ||
| //        }
 | ||
| 
 | ||
| //        /// <summary>
 | ||
| //        /// 在测试图像中查找 Logo
 | ||
| //        /// </summary>
 | ||
| //        /// <returns>true = OK,false = NG</returns>
 | ||
| //        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; // 没找到
 | ||
| //        }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| //        /// <summary>
 | ||
| //        /// 重载FindLogo函数(double返回)
 | ||
| //        /// </summary>
 | ||
| //        /// <param name="bmp"></param>
 | ||
| //        /// <returns></returns>
 | ||
| //        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 = 没找到
 | ||
| //        }
 | ||
| 
 | ||
| //        /// <summary>
 | ||
| //        /// Bitmap 转 Halcon HObject
 | ||
| //        /// </summary>
 | ||
| //        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<HTuple> modelHandles = new List<HTuple>();
 | ||
| 
 | ||
|         // 构造函数用于初始化
 | ||
|         public LogoMatcher() { }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 从指定目录加载所有 .shm 模板文件
 | ||
|         /// </summary>
 | ||
|         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}");
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         //        /// <summary>
 | ||
|         //        /// 匹配并返回最高得分(double返回)
 | ||
|         //        /// </summary>
 | ||
|         //        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;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// Bitmap 转 Halcon HObject
 | ||
|         /// </summary>
 | ||
|         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);
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| }
 |