🎊 C#/Halcon联合编程——C#中使用Halcon引擎

C#/Halcon联合编程——C#中使用Halcon引擎

环境配置

从Halcon安装目录中引入下面的两个Dll文件。

Halcon文件主要分为以下几种:

hdev:本地函数文件,函数定义在hdev文件内部,只能当前hdev内部使用,其他hdev程序无法使用

hdvp:外部函数文件,函数定义在hdvp中可以传输给任何hdev使用,即可以发给别人使用。同时允许对hdvp进行加密

hdpl:库函数,即内部可以定义多个hdvp函数的文件

使用Halcon引擎好处很多,其中最重要的一点就是避免了我们调用Halcon算子时程序可能存在的内存溢出问题。

通常情况下,我们选择使用Halcon引擎在C#中调用封装好的.hdvp文件。在这种方式下,我们可以自由的获取或设置对应函数的返回值。第一种方式我们只能获取主函数的参数。

上面的两种文件,整体的调用流程是一致的。本文介绍最常用的方法——调用Halcon函数(.hdvp文件)。

项目基于 .NetFrameWork4.8 开发,运行环境为64位。

使用方法

加载Halcon引擎,(并设置Halcon文件路径)。

获取调用程序文件。

初始化调用函数实例。

设置参数并执行。

获取结果。

函数文件创建

此处要注意,定义的函数文件输入变量名称和输出变量名称,我们在C#就是通过这里的名称实现传参和取值的。

使用函数文件

整体调用流程

private void Button_Click(object sender, RoutedEventArgs e)

{

HDevEngine hDevEngine = new HDevEngine();

var path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "method");

//设置方法路径

hDevEngine.SetProcedurePath(@"C:\Users\Yty\Desktop\method");

//直接传入方法名(此处会对函数文件进行一次编译,如果有错误会直接报异常)

//如果没设置引擎路径,就要传全路径

HDevProcedure hDevProcedure = new HDevProcedure("MyProcedure");

//生成调用实例 用来传参 取值 执行

HDevProcedureCall hDevProgramCall = new HDevProcedureCall(hDevProcedure);

hDevProgramCall.SetInputCtrlParamTuple("MyImageFile", new HTuple(@"C:\Users\Yty\Desktop\通讯服务.png"));

HOperatorSet.ReadImage(out var image, @"C:\Users\Yty\Desktop\通讯服务.png");

//设置图形参数

hDevProgramCall.SetInputIconicParamObject("MyImage",image);

//执行方法后才能取值

hDevProgramCall.Execute();

//获取控制参数

HTuple num= hDevProgramCall.GetOutputCtrlParamTuple("MyOutputNum");

//获取图形参数

HObject region= hDevProgramCall.GetOutputIconicParamObject("MyRegion");

this.window.HalconWindow.DispObj(region);

HOperatorSet.DispText(this.window.HalconWindow, num,"window",20,20,"red",null,null);

}

由于 HDevProcedure hDevProcedure = new HDevProcedure("MyProcedure") 会直接编译获取到的文件,因此我们也可以通过这种方式去检验文件语法,从而实现一个Halcon文件的编译功能。但是,对于代码中的逻辑错误(如0/N这种),就需要等到对应函数文件执行时才能获取到异常信息。

使用Hdev文件

这种方法只能获取到在main方法中调用的算子返回的参数。不能去设置参数。

流程

HDevEngine hDevEngine = new HDevEngine();

var path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "method");

//设置默认路径

hDevEngine.SetProcedurePath(@"C:\Users\Yty\Desktop\method");

//直接传入方法名(此处会对函数文件进行一次编译,如果有错误会直接报异常)

//如果没设置引擎路径,就要传全路径

var Program = new HDevProgram(ProgramPathString);

var ProgramCall = new HDevProgramCall(Program);

//这个类是没有设置参数的方法的

ProgramCall.Execute();//执行程序

double area;

area = ProgramCall.GetCtrlVarTuple("Area");//获取程序中的某个参数

混合使用方法

上面的代码中,我只介绍了单一的使用方法要么向hdev文件,要么向hdvp文件。如果,我们想运行某一个hdev文件下的某个封装函数,并获取其结果。我们可以使用如下的方法。这是重点内容,最灵活的使用方法。

点击查看代码

//新建一个Program读取hdev文件

HDevProgram program = new HDevProgram(tempName);

// 方法:将HDevProgram作为参数创建HDevProcedure,并根据函数名获取函数。

HDevProcedure procedure = new HDevProcedure(program, RunProcedureMethodName);

// 核心:生成执行实例,后续操作与上面相同

HDevProcedureCall hDevProgramCall = new HDevProcedureCall(procedure );

结合Halcon引擎开发相关功能

Compile

上面已经讲过这个了,就是在创建HDevProcedure或者HDevProgram,这个类就会自动编译一下传入的文件检查对应是否存在语法错误。这就实现了编译功能。

Debug

此处的Debug方案依旧是借助Halcon引擎实现的。在Halcon中,提供了以下方式帮助我们实现C#和Halcon软件的联合调试。

C#中启动Halcon引擎的调试服务

在Halcon中对需要调试的部分添加断点。

在Halcon软件中进行附加到C#进程即可实现联调。

因为,我们此处希望实现的是打上断点后一步步进行调试,因此在开启调试之前,我们关闭了JIT(防止因为JIT生成机器码影响调试过程)。当我们结束调试时,在重新打开JIT。

调试逻辑代码

private void StartDebug_Click(object sender, RoutedEventArgs e)

{

try

{

//一步一步向下调试

// 关闭即时编译(JIT, Just-In-Time)调试需求:解释执行模式下,代码逐行执行,更便于调试(如设置断点、单步执行)。

SysProcessSln.s_HDevEngine.SetEngineAttribute("execute_procedures_jit_compiled", "false");

//先停止调试 再打开调试

SysProcessSln.s_HDevEngine.StopDebugServer();

SysProcessSln.s_HDevEngine.StartDebugServer();

this.bd_DebugStatus.Background = new SolidColorBrush(Colors.Green);

frm_ModuleObj.isDebug = true;

}

catch (Exception ex)

{

Log.Error(ex.ToString());

System.Windows.Forms.MessageBox.Show(ex.ToString());

this.bd_DebugStatus.Background = new SolidColorBrush(Colors.Red);

frm_ModuleObj.isDebug = false;

}

}

private void StopDebug_Click(object sender, RoutedEventArgs e)

{

try

{

//重新打开JIT

SysProcessSln.s_HDevEngine.SetEngineAttribute("execute_procedures_jit_compiled", "true");

SysProcessSln.s_HDevEngine.StopDebugServer();

this.bd_DebugStatus.Background = new SolidColorBrush(Colors.Red);

frm_ModuleObj.isDebug = false;

}

catch (Exception ex)

{

Log.Error(ex.ToString());

System.Windows.Forms.MessageBox.Show(ex.ToString());

this.bd_DebugStatus.Background = new SolidColorBrush(Colors.Red);

frm_ModuleObj.isDebug = false;

}

}

补充内容

Halcon的变量分类

上面代码展示了如何向方法传参和取结果,在Halcon中,变量实际上就分为两类一种是图形变量(Image、Region等),还有一种是控制变量(字符串、数值等)。对于取值没必要具体到具体的变量类型,使用泛用方法即可(GetOutputIconicParamObject、GetOutputCtrlParamTuple等)。

Halcon引擎的路径修改问题(8.27)

这个问题会出现在我们使用HDevProgram时,路径被自动修改为了传入的.hdev文件的路径。使用HDevProcedure就不会出现这种问题,需要特别注意。

当我们使用Halcon引擎去编译文件后,会修改项目中Environment.CurrentDirectory的值。

从图上可以看到,当我们使用HDevProgram编译代码后,我们的工作路径被自动修改了。所以,如果涉及到一些相对路径的DLL加载问题。最好避免使用Environment.CurrentDirectory属性,使用AppDomain.CurrentDomain.BaseDirectory会更加安全稳定。

2025.9.24补充:通过XML文件解析Halcon的hdev函数文件

实际上,Halcon文件实际上就是使用XML结构来定义的。因此通过XML的解析方法,我们就能够从Halcon文件中解析出每个函数的函数名以及输出参数和函数体等内容。

先给出下面这个简单的Halcon文件(.hdev),其中有我使用的Halcon自带的算子还有一个自定义函数。这个函数里我只是去读一张图片,然后不进行任何操作。

该函数文件对应的Txt文本内容如下(内容太长,分两张截图)。

对应的XML文件中,首先是一个hdevelop的Element,其中给出了当前的Halcon版本以及文件版本。

其次,在一个hdevelop的Element中,每一个函数都对应着一个procedure的Element,并且函数名字由name给出。。我们重点挑一个procedure进行分析,剩下的处理逻辑都是相同的。

io:对应InputIconicParam,输入图形参数

ic:对应InputCtrlParam,输入控制参数

oo:对应OutputIconicParam,输出图形参数

oc:对应OutputCtrlParam,输出控制参数

对于最下面的docu标签中的内容,其类似于一种注释或说明的作用,对于Halcon文件的解析是可有可无的,即便你把这块内容删去,Halcon文件依然能正常打开并执行。

通过解析不同的标签即可获取到对应Halcon文件中,对应方法的输入输出参数信息和方法名称等消息,与上面的引擎使用方法结合,即可实现使用C#去操作Halcon文件。

最后,再来看一下main方法的内容

综上,结合C#解析XML的方法,我们就能顺利解析Halcon文件了。

🎈 相关推荐

河南这15个5A景区,去过一半才算真玩家!你去过几个?
🏷️ 足球比分365cv

河南这15个5A景区,去过一半才算真玩家!你去过几个?

📅 01-03 👀 1368
做一个u盘启动盘需要多大的u盘
🏷️ 2022年bet体育365官网合法吗

做一个u盘启动盘需要多大的u盘

📅 01-06 👀 1539
dota2回城按哪个键 游戏中怎么快速回城
🏷️ 足球比分365cv

dota2回城按哪个键 游戏中怎么快速回城

📅 02-08 👀 4245
全球领先!纳微半导体宣布氮化镓芯片出货量超1300万颗
🏷️ 足球比分365cv

全球领先!纳微半导体宣布氮化镓芯片出货量超1300万颗

📅 08-19 👀 7229
《原神》平民仆人最佳盾辅蓝砚,武器/圣遗物/技能加点/配队推荐,萌新开荒的最佳保姆。
依然名字的寓意分析
🏷️ 2022年bet体育365官网合法吗

依然名字的寓意分析

📅 01-10 👀 2528