在C#中使用Halcon开发视觉检测程序
简介
本文的初衷是希望帮助那些有其它平台视觉算法开发经验的人能快速转入Halcon平台下,如果你完全没有视觉算法开发经验也没关系,你可以先学会Halcon的使用再单独补视觉方面的知识。
文中的示例是一个极简的Halcon项目,通过该示例开发者能快速了解一个Halcon项目开发的基本步骤,让开发者能把精力完全集中到算法的开发上面。
首先,你需要安装Halcon,HALCON 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控件就会出现在工具箱中。
这些控件包含一个用于可视化图像和结果的HALCON 图形窗口,其中HWindowControl控件已经过时官方不再推荐使用。
与HWindowControl相比,HSmartWindowControl控件具有以下几个优点:
- 可以像任何其他控件一样使用
- 提供预定义的鼠标交互(移动窗口内容并使用鼠标滚轮进行缩放), 可以通过双击窗口来重置视图
- 控件会自动重新缩放,而不会闪烁
注:与HSmartWindowControlWPF 相反,HSmartWindowControl需要一个回调才能使用鼠标滚轮进行缩放。
引用dll
在HALCON安装目录下的\bin\dotnet35中,引用以下dll:
- hdevenginedotnet.dll
- halcondotnet.dll
注:使用 HALCON XL 开发应用程序时,必须选择以xl结尾的dll,hhdevelop xl适用于大分辨率的图像(大于 32k x 32k )。
引用以下命名空间:
- HalconDotNet:控件所在的命名空间
- HalconType:Line、Rectangle2等数据类型所在的命名空间
调用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位数选择x64或x86,我使用的是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_image、gen_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可以取以下值,里面包含了Line、Rectangle2类属性名:
"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#的,所以风格会比较奇怪。
附件
在C#中使用Halcon开发视觉检测程序的更多相关文章
- 在Visual Studio中使用MonoTouch开发iOS应用程序
前段时间在工作机上装了Mac OS X,这主要是因为我最近需要开发iPhone应用程序.虽然Xcode,Objective C一定是开发iOS应用程序的主流,但是经过一番考虑,我还是决定尝试一下使用M ...
- WIN10 64位下VS2015 MFC直接添加 halcon 12的CPP文件实现视觉检测
近段时间开始接触halcon,但是在VS2015里面使用,无论是配置还是生产EXE文件,都不如意. 加上网上的教程很多,经过多次测试,其实有很多地方无需修改,如果修改的太多也失去了直接添加封装的意义. ...
- cv2.cornerHarris()详解 python+OpenCV 中的 Harris 角点检测
参考文献----------OpenCV-Python-Toturial-中文版.pdf 参考博客----------http://www.bubuko.com/infodetail-2498014. ...
- Halcon · 曲线宽度检测算法总结
视觉检测中,直线的宽度很好检测,即两条平行线的垂直距离,而曲线的宽度检测则需要另辟蹊径. 检测图像中曲线边缘的宽度,用以判断边缘是否崩缺,总结如下五种方法: 1.图像匹配判断 概述:建立标准图像参考, ...
- 在iOS应用程序中使用Frida绕过越狱检测
阿里聚安全在之前的三篇博客中介绍了利用Frida攻击Android应用程序,整个过程仿佛让开发者开启上帝视角,在本篇博客中,我们将会介绍在iOS应用程序中使用Frida绕过越狱检测.即使 ...
- halcon开发必读
关于HALCON的新手入门问题简答(1) 无论读入什么图像,读入图像显示效果明显和原始图像不一致,哪怕是从相机读入的图像,也是明显颜色差异.什么原因引起? 答:初步诊断是,显示的时候调用的颜色查找表存 ...
- 在Ubuntu中搭建.NET开发环境
Mono简介Mono是Xamarin公司C#和CLR的ECMA标准基于开发的一个开源的.NET实现版本,它是Linux平台上开发.NET应用程序首选.同时其也提供了Xamarin.IOS和Xamari ...
- MacOS中使用QT开发iOS应用
因为项目合同中规定一部分业务内容要在手机端实现,包括安卓机和苹果机,因此选择了QT作为开发工具.程序在Win10和安卓系统上已经完美运行,这几天开始搭建iOS的编译和发布环境,因为以前没有使用过mac ...
- 在Visual Studio 2012中使用VMSDK开发领域特定语言(二)
本文为<在Visual Studio 2012中使用VMSDK开发领域特定语言>专题文章的第二部分,在这部分内容中,将以实际应用为例,介绍开发DSL的主要步骤,包括设计.定制.调试.发布以 ...
- 在Visual Studio 2012中使用VMSDK开发领域特定语言(一)
前言 本专题主要介绍在Visual Studio 2012中使用Visualization & Modeling SDK进行领域特定语言(DSL)的开发,包括两个部分的内容.在第一部分中,将对 ...
随机推荐
- 【Elasticsearch】ES选主流程分析
Raft协议 Raft是分布式系统中的一种共识算法,用于在集群中选举Leader管理集群.Raft协议中有以下角色: Leader(领导者):集群中的领导者,负责管理集群. Candidate(候选者 ...
- win10设置vmware 虚拟机开机自启
Windows10设置VMware虚拟机开机自启的具体步骤如下: 一.配置vmrun环境变量 1)找到VMware的安装目录,并将目录路径拷贝进入环境变量进行添加,如下图 2)检查添加的环境变量是否生 ...
- Git Rebase-提交整洁之道
git rebase git rebase是一个非常有用的命令,但知道和用的人非常少,今天介绍一下其作用 git rebase -i 作用:常用来合并多个相同目的的提交. 交互式有下面几个命令,常用命 ...
- Linux 使用 Systemd 管理进程服务
转载自:https://mp.weixin.qq.com/s/e-_PUNolUm22-Uy_ZjpuEA systemd 介绍 systemd是目前Linux系统上主要的系统守护进程管理工具,由于i ...
- vue-router query和params 传参和接收参数
1.params 方式传递和接收参数 //传参 this.$router.push({ name: 'checkDetailInfo', params:{ fkdNum:fkdNum, jyayStr ...
- day05-离线留言和离线文件
多用户即时通讯系统05 4.编码实现04(拓展) 拓展功能: 实现离线留言,如果某个用户不在线 ,当登陆后,可以接收离线的消息 实现离线发文件,如果某个功能没有在线,当登录后,可以接收离线的文件 4. ...
- 页面导出Excel
后端: 1.准备要导出的数据 2.利用XSSFWorkbook对象(workbook)创建工作簿行列等并添加数据 3.响应给前端 例: // 获取响应流 OutputStream output = r ...
- ToroiseGit/GitBash 设置提交信息模板设置
一.背景:当使用git提交代码时,每次的提交信息固定,却又比较长不好记的时,还需要将模板的地址保存下来,如果能设置一个固定的模板就可以很好的解决这个问题. 提交前的提交信息需要手动输入: 二.Toro ...
- ETL工具Datax、sqoop、kettle 的区别
一.Sqoop主要特点: 1.可以将关系型数据库中的数据导入到hdfs,hive,hbase等hadoop组件中,也可以将hadoop组件中的数据导入到关系型数据库中: 2.sqoop在导入导出数据时 ...
- JDK 8之前日期和时间的API
JDK 8之前日期和时间的API(1) System类中的currentTimeMillis():返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差.称为时间戳. java.util ...