在C#中使用Halcon开发视觉检测程序

2023-11-13

本文的初衷是希望帮助那些有其它平台视觉算法开发经验的人能快速转入Halcon平台下,通过文中的示例开发者能快速了解一个Halcon项目开发的基本步骤,让开发者能把精力完全集中到算法的开发上面。

首先,你需要安装HalconHALCON 18.11.0.1的安装包会放在文章末尾。安装包分开发和运行时两个版本,运行时版本一般用于生产环境。
注:开发版本自带运行时可替代运行时版本,但安装的东西会比较多。

然后,你需要学会查看Halcon的帮助手册,这是很重要的一件事

本文涉及到帮助文档的主要章节如下:

原文 HALCON 18.11.0.1 / Programmer's Guide / Programming With HALCON/.NET
翻译 HALCON 18.11.0.1/程序员指南/使用 HALCON/.NET 编程

原文 HALCON 18.11.0.1 / HALCON Operator Reference
翻译 HALCON 18.11.0.1/ HALCON 运算符参考

文中的示例是我第一次接触Halcon时的学习测试用例,在电脑里面躺了一年,最近才有时间整理一下发出来,希望能对你有所帮助。

注:运行本文示例程序前至少安装Halcon的运行时,否则Halcon的dll无法正常使用

将 HALCON/.NET 添加到应用程序#

添加控件#

右键单击工具箱,然后选择“选择项”,弹出的对话框选择“.NET Framework组件”,单击下面的“浏览”,导航到HALCON安装目录下的\bin\dotnet35(VS2008以下版本的选择dotnet20) ,然后选择halcondotnet.dll

完成上述操作后,HSmartWindowControl和HWindowControl控件就会出现在工具箱中,其中HWindowControl控件已经过时官方不再推荐使用。

与HWindowControl相比,HSmartWindowControl控件具有以下几个优点:

  • 可以像任何其他控件一样使用
  • 提供预定义的鼠标交互(移动窗口内容并使用鼠标滚轮进行缩放), 可以通过双击窗口来重置视图
  • 控件会自动重新缩放,而不会闪烁

注:与HSmartWindowControlWPF 相反,HSmartWindowControl需要一个回调才能使用鼠标滚轮进行缩放

引用dll#

在HALCON安装目录下的\bin\dotnet35中,引用以下dll:

  • hdevenginedotnet.dll
  • halcondotnet.dll

注:使用 HALCON XL 开发应用程序时,必须选择以xl结尾的dll,hhdevelop xl适用于大分辨率的图像(大于 32k x 32k )。

引用以下命名空间:

  • HalconDotNet:控件所在的命名空间
  • HalconTypeLineRectangle2等数据类型所在的命名空间

调用Halcon算子#

ReadImage操作为例,函数原型如下:

static void HOperatorSet.ReadImage(out HObject image, HTuple fileName)

public HImage(HTuple fileName)

public HImage(string fileName)

void HImage.ReadImage(HTuple fileName)

void HImage.ReadImage(string fileName)

注:这些内容帮助手册上都有,在文章开头列出来的章节。

在C#调用HALCON 算子有两种选择:函数式对象式,前值通过HOperatorSet调用算子并通过out关键字传入关键对象,后者直接在关键对象上调用对应的方法。
两种方法完全等价,C#是一门面向对象的语言,建议使用对象式的方式调用算子会好一点。

程序示例#

本示例只实现下面几种关键功能:

  • 加载、保存图片
  • 画线、框并保存
  • 抓边算法、测宽算法

先新建一个Winform项目,界面设计如下:

注:项目的解决方案平台不能使用AnyCPU,只能根据安装的Halcon位数选择x64x86,我使用的是x64平台。

HSmartWindowControl控件使用#

将HSmartWindowControl控件拖入主界面即可,在窗体类里面定义一个HWindow类型的成员引用控件内部的窗体,同时设置控件的回调函数(WPF则不需要)。代码如下:

//窗口实例
private HWindow hwindow;
       
public Form1()
{
    InitializeComponent();
    hwindow = hSmartWindowControl1.HalconWindow;//初始化窗口变量
    hSmartWindowControl1.MouseWheel += HSmartWindow_MouseWheel;
}

//鼠标滚轮回调
private void HSmartWindow_MouseWheel(object sender, MouseEventArgs e)
{
    Point pt = this.Location;
    MouseEventArgs newe = new MouseEventArgs(e.Button, e.Clicks, e.X - pt.X, e.Y - pt.Y, e.Delta);
    hSmartWindowControl1.HSmartWindowControl_MouseWheel(sender, newe);
}

加载、保存图像#

加载、保存图像也比较简单,我们需要先定义一个HImage实例,然后按钮单击事件在该实例上调用对应的算子,代码如下:

//图片变量
private HImage image = new HImage();
//加载图片
private void button_ReadImage_Click(object sender, EventArgs e)
{           
    string imagePath = "TestRead.bmp";
    image.ReadImage(imagePath);
    hwindow.DispImage(image);
    //自动适应图片(相当于控件上面的双击操作)
    hwindow.SetPart(0, 0, -2, -2);
}
//保存图片
private void button_WriteImage_Click(object sender, EventArgs e)
{
    string imagePath = "TestWrite.bmp";
    image.WriteImage("bmp", 0, imagePath);
    hwindow.DispImage(image);
}

上面代码是从程序启动目下加载TestRead.bmp图片,保存图片到程序启动目下的TestWrite.bmp,实际路径可以根据项目情况自己定义。
上面的图片是自己生成的,不是生产环境下的产品图片,仅用于程序演示。

扩展:加载相机图像#

大部分项目都是从相机加载图片,但这涉及到相机驱动的一些知识,全部介绍一边会偏移文章主题。
简单来说,加载相机图像分两步:

  • 将相机图像保存到内存
  • 将内存中的图像传入Halcon

将相机图像保存到内存是相机驱动的工作,下面只讨论怎么将内存中的图像传入Halcon,代码如下:

private void GenImageByPtr()
{
    //这三个参数都可以通过相机驱动得到
    byte[] imageBuf = null;   //图像缓存数组
    int width = 0;            //图像宽度
    int heigth = 0;           //图像高度
    //获取内存图像中间的指针
    IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(imageBuf, 0);
    //加载内存中的图像
    image.GenImage1("byte", width, heigth, ptr);
    hwindow.DispImage(image);
}

这里只列一个简单的示例,类似的算子还有copy_imagegen_image3等。

画线、画框并保存#

在图像上画线、框是机器视觉里面常见的需求,根据线、框确定算法搜索的区域和特征。
在窗体类中定义一个HDrawingObject对象并附加到现有窗口用于交互,同时定义好Line对象、Rectangle2对象用于保存绘图的结果。
先在图像窗口上面画出线和框,然后再用鼠标手动调整大小、位置,代码如下:

//绘图对象
private HDrawingObject drawingObject = new HDrawingObject();
//线ROI
private Line line = new Line();
//框ROI
private Rectangle2 rectangle2 = new Rectangle2();

private void button_DrawLine_Click(object sender, EventArgs e)
{
    drawingObject.CreateDrawingObjectLine(100, 100, 200, 200);
    //将绘图对象关联到Halcon窗口
    hwindow.AttachDrawingObjectToWindow(drawingObject);
}
private void button_SaveLine_Click(object sender, EventArgs e)
{
    HTuple paramName, param;            
    paramName = new HTuple(new string[] { "row1", "column1", "row2", "column2" });
    param = drawingObject.GetDrawingObjectParams(paramName);
    //保存参数
    line.SetValue(param.ToDArr());
    paramName.Dispose();
    param.Dispose();
    //清除绘图内容
    drawingObject.ClearDrawingObject();           
}

private void button_DrawRect_Click(object sender, EventArgs e)
{
    drawingObject.CreateDrawingObjectRectangle2(300, 400, 0, 300, 200);
    //将绘图对象关联到Halcon窗口
    hwindow.AttachDrawingObjectToWindow(drawingObject);
}
private void button_SaveRect_Click(object sender, EventArgs e)
{
    HTuple paramName, param;
    paramName = new HTuple(new string[] { "row", "column", "phi", "length1", "length2" });
    param = drawingObject.GetDrawingObjectParams(paramName);
    //保存参数
    rectangle2.SetValue(param.ToDArr());
    paramName.Dispose();
    param.Dispose();
    //清除绘图内容
    drawingObject.ClearDrawingObject();
}

上面的paramName可以取以下值,里面包含了LineRectangle2类属性名:

"color", "column", "column1", "column2", "end_angle", "font", "length1", "length2", "line_style", 
"line_width", "phi", "radius", "radius1", "radius2", "row", "row1", "row2", "start_angle", "string", "type"

检测算法#

用Halcon开发检测算法一般有两种方法:

  • 根据直接调用Halcon在对应语言平台下的算子接口
  • 用Halcon自带的脚本语言开发算法然后转成C#类

第一种自由度比较高,代码看起来也比较简洁易懂,但上手比较困难。第二种更简单,但生成的类很难看,而且与程序集成的时候需要做一些改动。
两种方法并不是绝对对立的,一般会先用Halcon验证算法,然后参考导出的C#类实现自己的检测算法。

抓边算法#

抓变算法直接调用的是Halcon的C#算子接口,里面有用到2D 测量模型

2D测量模型

简述一下2D 测量的使用步骤:

  • 创建测量模型并指定图像大小:首先必须使用create_metrology_model创建测量模型,然后使用set_metrology_model_image_size指定测量结果所在的图像的大小。

  • 提供近似值:将测量对象添加到测量模型中,每个测量对象由图像中相应对象的近似形状参数控制测量的参数组成,控制测量的参数包括例如指定测量区域的尺寸和分布的参数,测量对象有以下几种:

    • :add_metrology_object_circle_measure
    • 椭圆:add_metrology_object_ellipse_measure
    • 矩形:add_metrology_object_rectangle2_measure
    • 线:add_metrology_object_line_measure
    • 使用一个运算符创建不同形状:add_metrology_object_generic

要直观检查定义的度量对象,可以使用运算符get_metrology_object_model_contour访问其XLD轮廓。要直观检查创建的测量区域,可以使用运算符get_metrology_object_measures访问其XLD轮廓。

  • 修改模型参数:如果已执行相机校准,则可以使用set_metrology_model_param,没有就忽略(本示例没有使用)。

  • 修改对象参数:当将测量对象添加到测量模型时,可以设置许多参数,之后还可以使用运算符set_metrology_object_param修改其中的一些(本示例是在添加时设置的参数,所以没有此步骤)。

  • 调整测量模型:在执行下一次测量之前平移和旋转测量模型,可以使用操作员align_metrology_model。通常使用基于形状的匹配来获得对准参数,相当于测量前的位置就纠偏(本示例比较简单没有此步骤)。

  • 应用测量:使用apply_metrology_model执行测量过程。

  • 访问结果:测量后,可以使用get_metrology_object_result访问结果,也可以使用get_metrology_object_measures获取定位边的行坐标和列坐标再进一步处理(本示例使用前者)。

代码实现

抓变算法的C#代码如下:

private void button_FindEdge_Click(object sender, EventArgs e)
{
    //创建测量对象
    HMetrologyModel hMetrologyModely = new HMetrologyModel();
    //设置图片大小            
    image.GetImageSize(out int width, out int height);
    hMetrologyModely.SetMetrologyModelImageSize(width, height);
    //添加直线测量
    double measureLength1= 30, measureLength2=30, measureSigma=1, measureThreshold=30;
    HTuple genParamName = new HTuple(), genParamValue = new HTuple();
    hMetrologyModely.AddMetrologyObjectLineMeasure(line.Row1, line.Column1,line.Row2, line.Column2, measureLength1, measureLength2, measureSigma, measureThreshold, genParamName, genParamValue);
    //执行并获取结果
    hMetrologyModely.ApplyMetrologyModel(image);
    //获取测量区域
    HTuple mRow = new HTuple(), mCol = new HTuple();
    HXLDCont mContours = hMetrologyModely.GetMetrologyObjectMeasures("all", "all", out mRow, out mCol); //检测区域轮廓
    HXLDCont mmContours = hMetrologyModely.GetMetrologyObjectModelContour("all", 1);    //测量对象轮廓
    //参数顺序 ["row_begin", "column_begin", "row_end", "column_end"]
    HTuple  lineRet =hMetrologyModely.GetMetrologyObjectResult("all", "all", "result_type", "all_param");
    double[] retAry = lineRet.DArr;
    //打印结果
    hwindow.SetLineWidth(2);
    hwindow.SetColor("green");
    hwindow.DispLine(retAry[0], retAry[1], retAry[2], retAry[3]);
    hwindow.SetColor("blue");
    hwindow.DispXld(mContours);
    hwindow.SetColor("yellow");
    hwindow.DispXld(mmContours);
    //清空测量对象
    hMetrologyModely.ClearMetrologyModel();
    //清理对象
    hMetrologyModely?.Dispose();
    genParamName?.Dispose();
    genParamValue?.Dispose();
    mRow.Dispose();
    mCol.Dispose();
    mContours.Dispose();
    mmContours.Dispose();
}

Halcon的代码如下:

*读取图片
read_image (Image, 'D:/test.bmp')
dev_get_window (WindowHandle)

*画线
Row1:=1218.79
Column1:=1002.95
Row2:=1242.07
Column2:=2786.18
*draw_line (WindowHandle, Row1, Column1, Row2, Column2)
*gen_region_line (RegionLines, Row1, Column1, Row2, Column2)

*创建测量几何形状所需的数据结构
create_metrology_model (MetrologyHandle)
get_image_size (Image, Width, Height)
set_metrology_model_image_size (MetrologyHandle, Width, Height)  
add_metrology_object_line_measure (MetrologyHandle, Row1, Column1, Row2, Column2, 100, 50, 1, 30, [], [], Index)

apply_metrology_model (Image, MetrologyHandle)

get_metrology_object_result (MetrologyHandle, 'all', 'all', 'result_type','all_param', Parameter)

get_metrology_object_measures(Contours, MetrologyHandle, 'all', 'all', Row, Column)

get_metrology_object_model_contour (Contour, MetrologyHandle, 0, 1.5)

*清空测量对象,否则会导致内存泄露
clear_metrology_model (MetrologyHandle)

*可视化
dev_clear_window ()
dev_display(Image)
dev_set_color('green')
dev_set_line_width(1)
disp_line (WindowHandle, Parameter[0], Parameter[1], Parameter[2], Parameter[3])
dev_display (Contours)
dev_display (Contour)

使用方法

直接在界面上点击“打开图片”->“画线ROI”(默认位置我都调好了,你也可以自己调整大小、位置)->“抓边”,过程如下:

测宽算法#

测宽算法使用一维测量中的measure_pairs算子提取直边对,然后计算两个直边的距离。代码太长这里就不贴了,完整的项目源码会在文章末尾给出。
需要注意,measure_pairs算子的搜索框必须和目标边缘完全垂直,否则宽度数据会不准确,算子原理如下:


直接在界面上点击“打开图片”->“画框ROI”(默认位置我都调好了,你也可以自己调整大小、位置)->“测宽”,过程如下:

上面的箭头就是框的方向,测量边必须与框的方向接近垂直否则会运算失败,实际项目中还是建议用2D测量单独抓两个边来测宽度。
源码里面显示边缘的DispEdgeMarker方法,是直接从measure_pairs算子示例里面导出转C#的,所以风格会比较奇怪。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在C#中使用Halcon开发视觉检测程序 的相关文章

随机推荐

  • AXI smartconnect

    AXI smartconnect 简介 AXI smartconnect 是为了一个或多个主机通过AXI总线和一个或多个从机进行数据读写而用的 此前常用的应该是AXI interconnect这个IP 实质上smartconnect是int
  • [无线]433M天线、2.4G天线、5G天线长度设计

    无线 无线传输距离预估计算 我们回顾一下 天线最佳长度为波长的1 4 波长 波速 频率 波速 光速 3 100000000 一段金属导线中的交变电流能够向空间发射交替变化的感应电场和感应磁场 这就是无线电信号的发射 相反 空间中交变的电磁场
  • 关于==和equals的深入了解

    关于 和equals的深入了解 比较的是地址 这里指的是对象的比较 如果是基本数据类型 则比较的是值 未被重写的equals比较也是地址 因为调用的是Object的equals方法 Object类中equals源码如下 public boo
  • angularjs2 ajax请求,AngularJS - 将ajax请求传递给另一个控制器

    我的页面中有两个表 当点击第一个表上的一行时 我想调用ajax请求来更新第二个表 我正在尝试使用两个控制器执行此操作 每个控制器都使用ng repeat填充带有值的行 我已经烧掉了我能买得起的每一个神经元 而且我仍然难过 这是我的代码 ap
  • 机器学习——逻辑回归

    一下理解均为本人的个人理解 如有错误 欢迎指出 文章目录 什么是逻辑回归 如何处理因变量取值离散的情况 如何求解w b 梯度下降法的推导 逻辑回归的用途 如何衡量逻辑回归模型的好坏 逻辑回归的使用条件 pytorch实现逻辑回归 什么是逻辑
  • React笔记(七) React路由

    React笔记 七 1 React路由理解 React实现的是SPA应用 即单页Web页面 整个应用中只有一个完整的页面 点击页面中的链接也不会刷新页面 只会对页面进行局部的刷新 因此在更换页面时需要使用路由实现 路由就是一个键值对映射关系
  • pip升级 以及python3升级python3.9

    Ubuntu16 04 升级pip问题 you are using pip version 8 1 1 however version 20 0 2 is available you should consider upgrading vi
  • python中的删除:remove()、pop()、del

    这三种方法都是list的删除方法 其中remove是针对可变列表的元素进行搜索删除 而pop和del是针对可变列表的下标进行搜索删除 具体区别如下 remove item 方法是直接对可变序中的元素进行检索删除 返回的是删除后的列表 不返回
  • 【AD20】关于AD设计过程中一些小细节

    线上实习学习AD的过程中 学习到的一些懒狗快捷技巧以及一些因版本问题的不同操作 就浅浅归纳了一下 目录 原理图相关 1 批量命名元件 2 阵列式粘贴 3 给元器件添加属性 PCB相关 1 自绘元件封装 2 自定义板子的形状 3 按板子形状铺
  • 树莓派摄像头监控&Android手机查看&浏览器查看

    树莓派摄像头监控 Android手机查看 浏览器查看 链接USB相关参考 源码 usb摄像机直接接入树莓派USB接口 1 安装motion pi raspberrypi code camera sudo apt get install mo
  • jpa limit查询_在JPA的@Query注解中使用limit条件(详解)

    在 Query注解注释的JPQL语句中写limit语句是会报错的 unexpected token limit near line 解决方法是讲 Query注解中的limit语句去掉 然后传一个Pageable pageable new P
  • 6个网页背景特效源码 canvas+three.js科技贴图 webgl源码

    隧道穿梭特效 粒子矩阵特效 几何随机变换特效
  • websocket传输速率_STM32 websocket,TCP和UDP的传输速率

    网络上经常有人提到websocket TCP和UDP 的差别 说的大都是协议之间的差别 没有提及它们的传输能力 为了设计高吞吐量的物联网微服务器 最近对websocket TCP UDP的传输能力做了测试 使用STM32F746 处理器 操
  • unity打开除主菜单其他地方黑屏或白屏与unityHub安装unity简介

    unity打开除主菜单其他地方黑屏或白屏 新安装完成unity后 解决与原因 缘由 新安装完成unity后 打开unity进入项目后 只显示出主菜单栏 其他为白屏或黑屏 如下图 解决与原因 具体原因没仔细去查百度了一下 可以是时区的设置问题
  • MatLab中滤波器(filterDesigner)的设计和使用(附代码)

    本文章只作为本人学习笔记使用 matlab具有非常使用的滤波器设计工具 关于如何找到这个小工具有两种方法 1 我们可以在命令行输入filterDesigner 不同版本命令可能会有所不同 2 在APP页面中找到filterDesigner
  • 控制研究的混杂因素(Confounder)

    高高兴兴地写完一篇 SCI 投稿 苦苦等待好久 却只等来审稿人的一句话 你有控制研究的混杂因素 Confounder 吗 额 什么是混杂因素 又该如何控制 其实 混杂因素的控制在研究设计阶段就应该注意 今天 笔者就从 什么是混杂因素 为什么
  • C++学习:动态内存

    动态内存 静态内存用来保存局部static对象 类static数据成员 定义在任何函数之外的变量 static对象在使用之前分配 在程序结束后销毁 栈内存用来保存定义在函数内的非static对象 对于栈对象 仅在其定义的程序块运行时才存在
  • LR寄存器

    异常的发生会导致程序正常运行的被打断 并将控制流转移到相应的异常处理 异常响应 有些异常 fiq irq 事件处理后 系统还希望能回到当初异常发生时被打断的源程序断点处继续完成源程序的执行 异常返回 这就需要一种解决方案 用于记录源程序的断
  • android 调用短信,Android 调用发送短信的方法

    Android 调用发送短信的方法 功能 调用发送短信功能 1 权限 2 具体实现 Uri smstoUri Uri parse smsto Intent intent new Intent Intent ACTION VIEW smsto
  • 在C#中使用Halcon开发视觉检测程序

    本文的初衷是希望帮助那些有其它平台视觉算法开发经验的人能快速转入Halcon平台下 通过文中的示例开发者能快速了解一个Halcon项目开发的基本步骤 让开发者能把精力完全集中到算法的开发上面 首先 你需要安装Halcon HALCON 18