1、视觉软件
当我们拿到一个视觉项目,如果有一个拖拽式视觉软件去帮我们完成这样一个项目,既省时又省力,学什么halcon、opencv、visionpro,甚至头疼的C++、C#,统统不需要,也能快速成为一名视觉工程师,哈哈哈,这样一想门槛也太低了吧。下图海康的视觉软件vision master想必各位视觉大佬都不陌生吧,每个公司都有自己研发的视觉软件,市场上五花八门的软件,不过框架都差不多,学一个其他的也差不多了吧。这些视觉软件究竟为什么框选出一个区域,就能找到一个圆、一条线、识别出数字、或者其他特征呢,这个问题也困扰了我很久,奈何自己读书少,一直困惑于此,前几天闲来无事,工地搬完砖下班回到宿舍,打开才上手不久的halcon,和在工地上自学的C#,用底层代码去编写这样一个小视觉软件。
vision master
2、图像处理
利用halcon软件进行图像处理,这里用一个下班在路上捡的一个药品盖做一个模板匹配。图像处理上的细节不过多阐述,主要就是创造模板(create_shape_model)、寻找模板(create_shape_model)、点和角度刚性仿射变换,XLD轮廓任意仿射2D变换,相信各位大神对这些都不陌生,我就不在关公面前耍大刀,代码仅供跟我一样的小白参考,哈哈哈。
3、halcon导出c#
用halcon菜单栏文件,将算子代码转为c#代码,因为我们待会做界面要用winform来做,到时候直接用导出的代码,大神也可以用MFC编界面。
导出来之后,我们只需要关注action这个方法里面的代码,前面的都是定义变量,halcon的变量一般只有三个变量类型, HTuple数据变量(宽度,大小,数量),Hobject图像变量,HWindow 窗口句柄。
private void action()
{
// Local iconic variables
HObject ho_Qq20211015161226, ho_GrayImage;
HObject ho_Rectangle, ho_ImageReduced, ho_ModelContours;
HObject ho_ContoursAffineTrans, ho_RegionAffineTrans=null;
HObject ho_ContoursAffineTrans1=null, ho_Rectangle1=null;
// Local control variables
HTuple hv_WindowHandle = null, hv_Row1 = null;
HTuple hv_Column1 = null, hv_ModelID = null, hv_Area = null;
HTuple hv_Row = null, hv_Column = null, hv_HomMat2D = null;
HTuple hv_Angle = null, hv_Score = null, hv_i = null, hv_HomMat2DIdentity = new HTuple();
HTuple hv_HomMat2DTranslate = new HTuple(), hv_HomMat2DRotate = new HTuple();
HTuple hv_HomMat2D1 = new HTuple();
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_Qq20211015161226);
HOperatorSet.GenEmptyObj(out ho_GrayImage);
HOperatorSet.GenEmptyObj(out ho_Rectangle);
HOperatorSet.GenEmptyObj(out ho_ImageReduced);
HOperatorSet.GenEmptyObj(out ho_ModelContours);
HOperatorSet.GenEmptyObj(out ho_ContoursAffineTrans);
HOperatorSet.GenEmptyObj(out ho_RegionAffineTrans);
HOperatorSet.GenEmptyObj(out ho_ContoursAffineTrans1);
HOperatorSet.GenEmptyObj(out ho_Rectangle1);
if (HDevWindowStack.IsOpen())
{
HOperatorSet.CloseWindow(HDevWindowStack.Pop());
}
HOperatorSet.SetWindowAttr("background_color","black");
HOperatorSet.OpenWindow(0,0,512,512,0,"visible","",out hv_WindowHandle);
HDevWindowStack.Push(hv_WindowHandle);
ho_Qq20211015161226.Dispose();
HOperatorSet.ReadImage(out ho_Qq20211015161226, "G:/实验/药瓶盖检测1.bmp");
ho_GrayImage.Dispose();
HOperatorSet.Rgb1ToGray(ho_Qq20211015161226, out ho_GrayImage);
//draw_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
ho_Rectangle.Dispose();
HOperatorSet.GenRectangle1(out ho_Rectangle, 328, 456, 676, 797);
ho_ImageReduced.Dispose();
HOperatorSet.ReduceDomain(ho_GrayImage, ho_Rectangle, out ho_ImageReduced);
HOperatorSet.CreateShapeModel(ho_ImageReduced, "auto", (new HTuple(-180)).TupleRad()
, (new HTuple(180)).TupleRad(), "auto", "auto", "use_polarity", "auto", "auto",
out hv_ModelID);
ho_ModelContours.Dispose();
HOperatorSet.GetShapeModelContours(out ho_ModelContours, hv_ModelID, 1);
HOperatorSet.AreaCenter(ho_Rectangle, out hv_Area, out hv_Row, out hv_Column);
HOperatorSet.VectorAngleToRigid(0, 0, 0, hv_Row, hv_Column, 0, out hv_HomMat2D);
ho_ContoursAffineTrans.Dispose();
HOperatorSet.AffineTransContourXld(ho_ModelContours, out ho_ContoursAffineTrans,
hv_HomMat2D);
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_Qq20211015161226, HDevWindowStack.GetActive());
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_ContoursAffineTrans, HDevWindowStack.GetActive());
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.SetDraw(HDevWindowStack.GetActive(), "margin");
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_Rectangle, HDevWindowStack.GetActive());
}
//关闭
ho_ContoursAffineTrans.Dispose();
if (HDevWindowStack.IsOpen())
{
HOperatorSet.ClearWindow(HDevWindowStack.GetActive());
}
ho_Qq20211015161226.Dispose();
HOperatorSet.ReadImage(out ho_Qq20211015161226, "G:/实验/药瓶盖检测2.bmp");
HOperatorSet.FindShapeModel(ho_Qq20211015161226, hv_ModelID, (new HTuple(-180)).TupleRad()
, (new HTuple(180)).TupleRad(), 0.6, 0, 0.5, "least_squares", 0, 0.9, out hv_Row1,
out hv_Column1, out hv_Angle, out hv_Score);
for (hv_i=0; (int)hv_i<=(int)((new HTuple(hv_Score.TupleLength()))-1); hv_i = (int)hv_i + 1)
{
HOperatorSet.HomMat2dIdentity(out hv_HomMat2DIdentity);
HOperatorSet.HomMat2dTranslate(hv_HomMat2DIdentity, hv_Row1.TupleSelect(hv_i),
hv_Column1.TupleSelect(hv_i), out hv_HomMat2DTranslate);
HOperatorSet.HomMat2dRotate(hv_HomMat2DTranslate, hv_Angle.TupleSelect(hv_i),
hv_Row1.TupleSelect(hv_i), hv_Column1.TupleSelect(hv_i), out hv_HomMat2DRotate);
HOperatorSet.VectorAngleToRigid(hv_Row1, hv_Column1, hv_Angle, hv_Row1, hv_Column1,
hv_Angle, out hv_HomMat2D1);
ho_RegionAffineTrans.Dispose();
HOperatorSet.AffineTransRegion(ho_Rectangle, out ho_RegionAffineTrans, hv_HomMat2D1,
"nearest_neighbor");
ho_ContoursAffineTrans1.Dispose();
HOperatorSet.AffineTransContourXld(ho_ModelContours, out ho_ContoursAffineTrans1,
hv_HomMat2DRotate);
ho_Rectangle1.Dispose();
HOperatorSet.GenRectangle2(out ho_Rectangle1, hv_Row1.TupleSelect(hv_i), hv_Column1.TupleSelect(
hv_i), hv_Angle.TupleSelect(hv_i), 170, 170);
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_Qq20211015161226, HDevWindowStack.GetActive());
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_ContoursAffineTrans1, HDevWindowStack.GetActive()
);
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.SetDraw(HDevWindowStack.GetActive(), "margin");
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_Rectangle1, HDevWindowStack.GetActive());
}
}
ho_Qq20211015161226.Dispose();
ho_GrayImage.Dispose();
ho_Rectangle.Dispose();
ho_ImageReduced.Dispose();
ho_ModelContours.Dispose();
ho_ContoursAffineTrans.Dispose();
ho_RegionAffineTrans.Dispose();
ho_ContoursAffineTrans1.Dispose();
ho_Rectangle1.Dispose();
}
4、界面编写
下面就是激动人心的代码时刻了,本界面使用c#下winform编写的。首先配置halcon与vs环境,一共就只有两步,不像MFC配置那么复杂,到现在我也忘了,反正自认为很难搞,会的可以教教我,第一步添加应用,第二步添加命名空间using HalconDotNet。如果配置成功但总是报错,可以改以下生成平台
第一步
第二步
环境配置好后,进行界面的设计,大家在界面上添加hWindowControl1窗口,这里也是需要在工具箱添加halcon窗体控件的,工具箱里面控件,右键点击选择项,找到halcon安装路径,添加halcondotnet.dll文件,因为图像处理都基于halcon窗口来做的,picturebox是没法做。这里我们只需要注意模板匹配里面的控件,采集图片和清除功能。我们的理清楚我们模板匹配的思路,一、读入图像,二、画出ROI,找到所需要的模板区域,三、创建模板,将你所框选区域的模板物体进行显示、四、再读取一张图片,在这张图中进行模板搜索,识别出该图中的目标予以框出,显示目标坐标,五,清除界面。
4.1、读入图像
双击采集图片按钮,我们以选取文件夹里面的图片为例,按钮中添加以下代码。
4.2、画出ROI
双击画矩形按钮,设置框选的颜色,样式(一般margin),线宽,画出区域,将区域图片进行裁剪显示。
4.3、创建模板
4.4、读取图片,寻找模板
将匹配分数设置为0.5,这里需要注意的是,halcon处理得到的中心坐标是HTuple类型,textBox显示出来得用string类型,进行类型转换,我用了如下方法,其他也没找到比较好的方法。
4.5,清除界面
5、结果展示
该模板匹配,检测,适用于常规目标识别,只需要模板图片和测试图片。
6、还做了一些以相机实时采集的形式、查找圆、查找线、拟合、测量的一些小控件。框选出目标区域,自动找圆、找线,如下图,下次再分享,明天还得上工地,第一次写,写的不好,望各位大神提出意见,相互学习,晚安!