<think>我们将在WinForm中实现以下功能:
1. 使用多线程进行循环截图(不保存文件)
2. 将截图转换为Halcon图像格式
3. 使用Halcon进行模板匹配(模板不保存,直接从内存加载)
4. 匹配成功后,自动点击匹配区域中心
5. 整个流程在多线程中完成,不阻塞UI
步骤:
1. 创建WinForm项目,添加HalconDotNet引用(需要安装Halcon库)
2. 设计界面:开始/停止按钮
3. 后台实现:
- 使用单独的线程进行循环处理(截图、匹配、点击)
- 使用Halcon加载模板(从内存,不保存文件)
- 截图使用Graphics.CopyFromScreen
- 匹配成功后,在主线程中执行点击(使用Invoke,因为鼠标点击需要回到主线程,但注意:模拟点击实际上可以在任何线程执行,但为了安全我们使用主线程)
4. 注意线程安全,使用volatile标志控制线程退出
注意:模拟鼠标点击需要管理员权限,或者使用SendInput API(这里使用mouse_event,但注意它已过时,但简单)
完整代码如下(包括必要的异常处理和资源释放):</think>以下是一个完整的C# WinForm多线程实现Halcon模板匹配、自动截图和点击的解决方案。代码包含线程安全设计、资源管理和Halcon集成:
```csharp
using HalconDotNet;
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace HalconAutoClicker
{
public partial class MainForm : Form
{
// 线程控制变量
private volatile bool _isRunning = false;
private Thread _workerThread;
private readonly object _lockObj = new object();
// Halcon对象
private HWindow _halconWindow;
private HImage _templateImage;
private HShapeModel _shapeModel;
public MainForm()
{
InitializeComponent();
InitializeHalcon();
}
private void InitializeHalcon()
{
// 创建Halcon窗口(隐藏)
_halconWindow = new HWindow(0, 0, 100, 100);
// 创建模板图像(示例使用,实际应替换为你的模板)
CreateTemplateImage();
// 创建形状模型
CreateShapeModel();
}
private void CreateTemplateImage()
{
// 示例:创建内存中的模板图像(实际应替换为你的模板)
Bitmap templateBmp = new Bitmap(100, 100);
using (Graphics g = Graphics.FromImage(templateBmp))
{
g.FillRectangle(Brushes.Red, 10, 10, 80, 80);
}
_templateImage = BitmapToHImage(templateBmp);
}
private void CreateShapeModel()
{
// 创建形状模型(不保存到文件)
_shapeModel = new HShapeModel(
_templateImage,
"auto",
-0.39,
0.79,
"auto",
"auto",
"use_polarity",
"auto",
"auto"
);
_shapeModel.SetShapeModelParam("min_contrast", 10);
}
private void btnStart_Click(object sender, EventArgs e)
{
if (_isRunning) return;
_isRunning = true;
_workerThread = new Thread(ProcessingLoop)
{
IsBackground = true,
Priority = ThreadPriority.BelowNormal
};
_workerThread.Start();
btnStart.Enabled = false;
}
private void btnStop_Click(object sender, EventArgs e)
{
_isRunning = false;
_workerThread?.Join(500);
btnStart.Enabled = true;
}
private void ProcessingLoop()
{
while (_isRunning)
{
try
{
// 步骤1:屏幕截图(不保存文件)
using (Bitmap screenshot = CaptureScreen())
{
// 步骤2:转换为Halcon图像
using (HImage halconImage = BitmapToHImage(screenshot))
{
// 步骤3:模板匹配
HTuple row, column, angle, score;
_shapeModel.FindShapeModel(
halconImage,
-0.39,
0.79,
0.5,
1,
0.5,
"least_squares",
0,
0.9,
out row,
out column,
out angle,
out score
);
// 步骤4:处理匹配结果
if (score.Length > 0 && score[0].D > 0.8) // 匹配阈值
{
// 获取匹配中心坐标
Point targetPoint = new Point((int)column[0].D, (int)row[0].D);
// 在主线程执行点击操作
Invoke((MethodInvoker)delegate
{
PerformClick(targetPoint);
});
}
}
}
// 控制处理频率(每秒2次)
Thread.Sleep(500);
}
catch (Exception ex)
{
Console.WriteLine($"处理错误: {ex.Message}");
}
}
}
private Bitmap CaptureScreen()
{
// 捕获整个屏幕
Rectangle screenBounds = Screen.PrimaryScreen.Bounds;
Bitmap bmp = new Bitmap(screenBounds.Width, screenBounds.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(0, 0, 0, 0, screenBounds.Size);
}
return bmp;
}
private HImage BitmapToHImage(Bitmap bmp)
{
// 将Bitmap转换为HImage
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(
rect,
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppRgb
);
try
{
return new HImage("byte", bmp.Width, bmp.Height, bmpData.Scan0);
}
finally
{
bmp.UnlockBits(bmpData);
}
}
private void PerformClick(Point location)
{
// 保存原始鼠标位置
Point originalPos = Cursor.Position;
// 移动鼠标到目标位置
Cursor.Position = location;
// 模拟鼠标点击
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
// 恢复鼠标位置
Cursor.Position = originalPos;
}
// 鼠标事件常量
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
[DllImport("user32.dll")]
private static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
protected override void OnFormClosing(FormClosingEventArgs e)
{
_isRunning = false;
_workerThread?.Join();
// 释放Halcon资源
_templateImage?.Dispose();
_shapeModel?.Dispose();
_halconWindow?.Dispose();
base.OnFormClosing(e);
}
}
}
```
### 实现步骤详解
1. **Halcon初始化**:
- 创建隐藏的Halcon窗口对象`HWindow`
- 在内存中创建模板图像(示例使用红色矩形,实际应替换为你的模板)
- 创建形状模型`HShapeModel`并设置参数[^1]
2. **多线程处理**:
```csharp
_workerThread = new Thread(ProcessingLoop) {
IsBackground = true,
Priority = ThreadPriority.BelowNormal
};
```
- 使用独立线程执行处理循环
- `volatile bool`确保线程安全退出
3. **屏幕截图处理**:
```csharp
using (Bitmap screenshot = CaptureScreen())
{
using (HImage halconImage = BitmapToHImage(screenshot))
{
// 处理图像
}
}
```
- `Graphics.CopyFromScreen`捕获屏幕
- 使用`using`确保资源释放
- 转换为Halcon图像格式
4. **模板匹配**:
```csharp
_shapeModel.FindShapeModel(halconImage, ...);
if (score[0].D > 0.8) // 匹配阈值
{
// 执行点击
}
```
- 使用Halcon的形状匹配算法
- 设置匹配阈值过滤结果
5. **鼠标点击**:
```csharp
Invoke((MethodInvoker)delegate {
PerformClick(targetPoint);
});
```
- 使用`Invoke`确保UI线程安全
- 保存/恢复原始鼠标位置
- 使用`mouse_event`模拟点击
### 界面设计建议
```csharp
// MainForm.Designer.cs
partial class MainForm
{
private Button btnStart;
private Button btnStop;
private void InitializeComponent()
{
this.btnStart = new Button();
this.btnStop = new Button();
//
// btnStart
//
this.btnStart.Location = new Point(20, 20);
this.btnStart.Size = new Size(100, 40);
this.btnStart.Text = "开始";
this.btnStart.Click += new EventHandler(this.btnStart_Click);
//
// btnStop
//
this.btnStop.Location = new Point(20, 70);
this.btnStop.Size = new Size(100, 40);
this.btnStop.Text = "停止";
this.btnStop.Click += new EventHandler(this.btnStop_Click);
//
// MainForm
//
this.ClientSize = new Size(300, 150);
this.Controls.Add(this.btnStart);
this.Controls.Add(this.btnStop);
}
}
```
### 优化建议
1. **性能提升**:
```csharp
// 限制搜索区域
HRegion searchRegion = new HRegion(100, 100, 500, 500);
_shapeModel.FindShapeModel(halconImage, searchRegion, ...);
```
2. **动态模板更新**:
```csharp
public void UpdateTemplate(HImage newTemplate)
{
lock(_lockObj) {
_shapeModel?.Dispose();
_templateImage?.Dispose();
_templateImage = newTemplate.Clone();
CreateShapeModel();
}
}
```
3. **错误处理增强**:
```csharp
catch (HOperatorException hex)
{
MessageBox.Show($"Halcon错误: {hex.GetErrorMessage()}");
}
```
### 注意事项
1. **权限要求**:
- 程序需要管理员权限才能模拟鼠标点击
- 在项目属性中设置`app.manifest`:
```xml
<requestedExecutionLevel level="requireAdministrator"/>
```
2. **Halcon依赖**:
- 安装Halcon运行时库(推荐版本≥18.11)
- 添加`HalconDotNet.dll`引用
- 部署时包含`halcon.dll`和许可证文件
3. **多显示器支持**:
```csharp
// 捕获特定显示器
Screen targetScreen = Screen.AllScreens[1];
Rectangle bounds = targetScreen.Bounds;
```
[^1]: Halcon形状匹配文档建议设置`min_contrast`参数以提高稳定性