Files
CheckDevice/Check.Main/Common/LogoMatcher.cs

471 lines
17 KiB
C#
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

//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 = OKfalse = 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);
}
}
}
}