This commit is contained in:
2025-10-20 14:47:17 +08:00
parent 2e46747ba9
commit 546b894e6b
16 changed files with 917 additions and 141 deletions

View File

@@ -33,6 +33,8 @@ namespace Check.Main.Common
_slaveId = slaveId;
}
public bool IsConnected => _tcpClient != null && _tcpClient.Connected;//10.11添加
public async Task ConnectAsync()
{
await _tcpClient.ConnectAsync(_ip, _port);

View File

@@ -0,0 +1,290 @@
//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>();
/// <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;
}
/// <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);
}
}
}
}

View File

@@ -0,0 +1,62 @@
using HalconDotNet;
using System;
using System.Collections.Generic;
using System.IO;
namespace HalconTemplateMatch
{
public class LogoTemplateTrainer
{
/// <summary>
/// 从多张样本图像生成模板并保存到文件
/// </summary>
/// <param name="imagePaths">训练图片路径集合</param>
/// <param name="saveDir">模板保存目录</param>
public void TrainAndSaveTemplates(List<string> imagePaths, string saveDir)
{
if (!Directory.Exists(saveDir))
Directory.CreateDirectory(saveDir);
int index = 0;
foreach (var path in imagePaths)
{
HObject ho_Image;
HOperatorSet.ReadImage(out ho_Image, path);
// 转灰度
HOperatorSet.Rgb1ToGray(ho_Image, out HObject ho_Gray);
// 二值化
HOperatorSet.Threshold(ho_Gray, out HObject ho_Region, 128, 255);
// 提取连通域
HOperatorSet.Connection(ho_Region, out HObject ho_Connected);
HOperatorSet.SelectShapeStd(ho_Connected, out HObject ho_Selected, "max_area", 70);
// ROI 约束
HOperatorSet.ReduceDomain(ho_Gray, ho_Selected, out HObject ho_ROI);
// 创建形状模板
HTuple modelID;
HOperatorSet.CreateShapeModel(
ho_ROI,
"auto",
new HTuple(0).TupleRad(),
new HTuple(360).TupleRad(),
"auto",
"auto",
"use_polarity",
"auto",
"auto",
out modelID);
// 保存模板到文件
string modelFile = Path.Combine(saveDir, $"logo_model_{index}.shm");
HOperatorSet.WriteShapeModel(modelID, modelFile);
Console.WriteLine($"训练完成并保存模板: {modelFile}");
index++;
}
}
}
}

View File

@@ -11,9 +11,9 @@ namespace Check.Main.Common
{
public int CameraIndex { get; }
public long ProductId { get; }
public SKImage ResultImage { get; } // 【修改】携带已绘制好结果的SKImage
public Bitmap ResultImage { get; } // 原来是SKImage ResultImage
public ProcessingCompletedEventArgs(int cameraIndex, long productId, SKImage resultImage)
public ProcessingCompletedEventArgs(int cameraIndex, long productId, Bitmap resultImage)//原来是SKImage resultImage
{
CameraIndex = cameraIndex;
ProductId = productId;