Halcon联合C#开发最新版实用框架 实际项目应用验证过的版本,源码,修改了大量Bug以适合实际项目应用 采用仿Visionpro拖拉流程形式,很适合学习使用,可修改参考用于项目。 注:软件能够正常编译运行,使用中遇到Bug自行摸索解决,主要是源码学习参考为主。
工业视觉项目的甲方总喜欢在验收前一天提出"能不能加个旋转检测"这种需求。去年用Halcon+C#折腾出的那套框架,最近被我改造成了VisionPro风格的拖拉拽工具,实测在口罩机外观检测项目里扛住了每天12小时连续运转。今天就带大家扒开这个框架的代码骨架,看看怎么用WPF把Halcon算子玩出花。

流程设计器的界面布局直接照抄了VisionPro的经典三栏结构(别问,问就是致敬)。左侧的算子库用TreeView实现层级分类,这部分XAML代码值得细品:
xml
<TreeView ItemsSource="{Binding ToolCategories}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Tools}">
<TextBlock Text="{Binding CategoryName}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Tag="{Binding Script}">
<Image Source="{Binding Icon}"/>
<TextBlock Text="{Binding ToolName}" Margin="5"/>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
绑定ViewModel里的ToolCategories集合时,注意每个算子都带有脚本属性和图标路径,这为后续的拖拽操作埋下伏笔。当用户把Blob分析工具拖到画布时,实际是复制了预置的HDevelop脚本模板。
核心的拖拽逻辑藏在PreviewMouseMove事件里。判断鼠标移动距离超过系统阈值后,启动拖拽操作:
csharp
private void OnToolItemPreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed &&
_startPoint.HasValue &&
(e.GetPosition(null) - _startPoint.Value).Length > 2.0)
{
var frameworkElement = sender as FrameworkElement;
var data = new DataObject("ToolTemplate", frameworkElement.Tag.ToString());
DragDrop.DoDragDrop(frameworkElement, data, DragDropEffects.Copy);
}
}
这里有个坑:直接从Halcon导出的hdev脚本在C#环境里跑不起来,得手动替换掉那些反人类的变量命名。比如把AreaCenter转成area_center,还要处理坐标系转换问题------工业相机拍出来的图Y轴是反的!

参数配置窗体用了动态生成控件的大招。读取算子脚本的输入输出参数后,自动渲染对应控件:
csharp
foreach (var param in script.Parameters)
{
switch (param.Type)
{
case "int":
var numBox = new NumericUpDown { Value = param.Value };
_paramControls.Add(param.Name, numBox);
break;
case "string":
var txtBox = new TextBox { Text = param.Value.ToString() };
_paramControls.Add(param.Name, txtBox);
break;
// 其他类型处理...
}
}
调试时发现Halcon的阈值参数用double类型传参会精度丢失,后来改成字符串传递再在脚本里转换才解决。这种坑文档里可不会写,都是项目现场踩出来的经验。
Halcon联合C#开发最新版实用框架 实际项目应用验证过的版本,源码,修改了大量Bug以适合实际项目应用 采用仿Visionpro拖拉流程形式,很适合学习使用,可修改参考用于项目。 注:软件能够正常编译运行,使用中遇到Bug自行摸索解决,主要是源码学习参考为主。

流程引擎最核心的部分是算子执行队列。用BackgroundWorker跑异步任务时,切记要加try-catch把Halcon异常转成C#异常:
csharp
private void RunProcess(object sender, DoWorkEventArgs e)
{
var process = e.Argument as Process;
try
{
foreach (var tool in process.Tools)
{
_halconEngine.ExecuteScript(tool.Script);
// 更新进度条需要回UI线程
(sender as BackgroundWorker).ReportProgress(0, tool.ToolName);
}
e.Result = true;
}
catch (HOperatorException ex)
{
// 这里要解析Halcon错误代码
e.Result = new ProcessError(ex.Message, ex.ErrorCode);
}
}
重点注意HOperatorException的ErrorCode需要查Halcon文档,特别是2000系列错误基本都是图像没载入或区域为空这种低级错误。
图像显示控件继承自HalconDotNet.HWindowControl,但原始版本在多线程下会花屏。改进方案是加双缓冲:
csharp
public class HSmartWindow : HWindowControl
{
protected override void OnPaint(PaintEventArgs e)
{
if (_backBuffer != null)
{
lock (_backBuffer)
{
e.Graphics.DrawImageUnscaled(_backBuffer, 0, 0);
}
}
}
public void UpdateImage(HImage image)
{
using (var g = Graphics.FromImage(_backBuffer))
{
// 这里调用Halcon的dump_window方法生成Bitmap
var bitmap = image.DumpWindow(this.HalconWindow);
g.DrawImage(bitmap, 0, 0);
}
Invoke(new Action(Refresh));
}
}
实测这个改写版本在i7处理器上能稳定跑60fps的1280x1024图像,比原生控件节省30%的CPU占用率。注意一定要加lock,否则多线程渲染时会内存溢出。

项目里还藏了些黑科技:比如用Roslyn动态编译用户自定义脚本,支持在界面里写C#代码直接操作Halcon对象;再比如用EF Core记录每次检测的算法参数和结果,方便后续追溯质量问题。
源码里最值得参考的是异常处理机制------毕竟工业现场的环境千奇百怪。我们给每个算子都加了try-catch包装,发生错误时自动保存现场图像和参数到错误目录,这对后期调试帮助巨大。

最后友情提示:别在UI线程里调用任何Halcon的耗时操作,否则拖动滚动条时画面会卡成PPT。正确做法是用Task.Run把图像处理丢到线程池,然后用Dispatcher.BeginInvoke更新界面。不过要注意Halcon对象不是线程安全的,跨线程使用记得加锁或者克隆对象。