目录
导言
1.桌面软件开发的两大开发流派
2.两种开发方式的优势和劣势总结
3.两种开发方式之外的开发方式
4.海康算子SDK二次开发要怎么做
方法步骤
2.1 使用C#的算子SDK二次开发配置
2.1.1 了解SDK文件目录结构
2.1.2 在IDE中进行引用库配置
第一步:设置工程生成属性
第二步:添加引用
2.2.1 添加必要引用
2.2.2 添加控件引用库
2.2.3 添加特定算法库引用
第三步:添加控件(可选步骤)
简单示例
总结
在介绍如何使用海康机器视觉算子SDK二次开发之前,我们先了解一下,在当今世界开发桌面应用软件,可以有哪些选择?有哪些趁手的武器?
当今桌面应用软件的开发,有两大门派,就像武侠小说中的少林和武当一样,一个是使用.net 语言的Winform,WPF开发,这种门派讲求的速成,高效,会点C#或者VB.net 的三脚猫功夫就能开发出一个功能有模有样的桌面应用软件(但其实精通也是需要修炼内功的)。使用.Net开发的软件,界面美观,不用很多代码就能实现各种各样的花里胡哨的功能(对软件界面颜值有要求的客户很喜欢吃这一套)如下下图所示。
另一种是使用C++语言的MFC, QT开发,这种门派武功讲求的心法和内功,可能学了大半年,连个简单的客户需求不借助百度搜索都无从下手。虽然学习曲线陡峭,经过长时间的学习,熟悉并掌握了一些C++常用库的用法,也能开发出功能复杂的应用软件。C++开发的软件运行效率高,写得不好有可能会内存泄漏。
总结起来就是,net开发效率高,开发难度相对C++较低(内存管理不要太多操心,有垃圾回收机制),开发的软件界面美观。C++开发效率低,但灵活性更高,软件运行效率高,开发的界面要美观需要很多额外的代码。内存需要程序员管理,写不好就容易内存泄漏(不过用现代C++可以借助智能指针规避掉一些内存管理问题)。
除了上面说的这两大门派之外,其实还有一些门派,只不过大浪淘沙,在日新月异的IT技术发展的历程中,逐渐被人遗忘,使用的客户越来越少,只剩下在工控领域还保留着最后的一片自留地。就是VisualBasic(注意是VB,不是VB.net)和Delphi(其实Delphi在国外还有很强的生命力,最新的版本Delphi Alexandria 可以跨平台,开发windows,linux,Android,Mac, ios应用)。
好了,扯远了,我会回到正题。
使用海康机器视觉算子SDK二次开发需要怎么做?
这个问题分两种情况来说明,一种情况就是使用C#语言进行二次开发,一种情况是使用C++进行二次开发。本文介绍的是使用C#语言如何进行算子SDK二次开发的配置,在另一篇文章中我将介绍C++的二次开发配置。(C#的海康算子SDK二次开发,关键在于添加C#的二次开发库引用的配置。C++的海康算子SDK二次开发关键在于头文件路径和静态库路径的配置)
首先了解一下海康算子SDK的安装目录的结构。
安装完海康算子SDK之后,一般是在C盘目录下C:\Program Files (x86)\MVDAlgorithmSDK
在此目录下,你会看到:
其中Documentations是二次开发的文档,这个目录下有SDK二次开发需要参考的知识。Includes是SDK的头文件目录,使用C++的算子SDK二次开发需要关注。
Libraries是静态库目录,同样,使用C++的算子SDK二次开发需要关注。
MVDTools 是运行环境的检测,版本信息,日志等,这个二次开发不要关心这个。
ReferencedAssembilies是算子SDK的.net 封装库,正是使用C#进行算子SDK二次开发需要关注的。
Runtime 是算子SDK运行时库,是算子工具运行时必须的依赖库。Runtime所在路径在安装算子SDK时写入系统环境变量,使得用户开发的程序EXE文件可以放在其他目录也能运行,而不必将Runtime目录下的所有DLL文件都拷贝到用户exe目录下,也能是用户EXE能运行起来。
做了这么多铺垫,废话讲了一大堆,接下来才是真正的关键步骤,有基础的开发者建议直接跳到这个步骤来看。
首先,按照正常的步骤,新建一个C#的工程,这里以Winform举例,首先将C#工程的生成设置一下,在“工程”->“属性”下,在弹出的窗口中,切换到“生成”选项卡,将首选32位去掉勾选。
因为海康的算子SDK是64位库,只支持生成64位的应用程序,因此这个设置非常关键,否则后面即使编译OK了,但是程序运行时还是会报各种异常导致的崩溃。
关于算子SDK需要引用的库,主要分两部分,一部分是基础库,这个库是只要使用算子SDK就必须要用到的库,另一部分是特定库,用户用到了才需要引用,没用到就可以不必引用,举例来说,我的应用程序需要用到直线查找这个算子,因此我只需要添加直线查找算子的引用,而不必引用那些我用不到的圆查找,Blob查找等算子库。
基础库有以下必须添加引用:
MVDCore.Net.dll
MVDImage.Net.dll
MVDShape.Net.dll
其他DLL都是可选的引用,用到则添加,用不到则不必添加。
所以,接着我们添加引用,如下图所示:在VS的解决方案窗口,对工程右键,添加引用。
在随后弹出的窗口中,定位路径到:
C:\Program Files (x86)\MVDAlgorithmSDK\ReferencedAssemblies\Common
选择MVDCore.net.dll MVDImage.Net.dll MVDSDKLog.Net.dll MVDShpae.dll MVDXmlParse.Net.dll MvdRenderActiceX.dll
其中MVDSDKLog.Net.dll 和日志功能相关,如果用户用的是自己的日志组件,这个可以不必添加,MVDXmlParse.Net.dll 这个是解析XML的组件,用来读取和保存配置运行参数的,如果用户这一块有自己的实现方式,也是不必引用。MVRenderActiveX.dll 是渲染控件用到的库,如果用户是自己渲染算法运行结果,这个也是不必添加的引用。
添加控件引用库,同样也是在解决方案窗口对工程右键菜单添加,在随后的窗口中定位路径到C:\Program Files (x86)\MVDAlgorithmSDK\ReferencedAssemblies\Control
这些控件库是并非是算子SDK二次开发必须要用到的库,只是海康对算子SDK二次开发需要用到的一些常用控件做了二次封装,方便二次开发者对常见的操作做一些图形化的交互设计。这些控件包含模板匹配建模和识别控件(MVDAlmightyPatMatch.Controls, MVDAlmightyPattern.Controls),相机管理(MVDCamera.Controls.Net),图像源控件(MVDImageSource.Controls),字符识别和训练控件(MVDOCR.Control.Net, MVDOCRTrain.Controls)。如果开发者不满意现有的这些控件(比如,太丑啦,界面风格不喜欢,交互设计和我们用户使用习惯不一致等等), 开发者则不必添加这些引用,开发者可以自己去实现控件。海康算子SDK的核心是算法,而不在UI呈现。
这里多提一嘴,在交互设计领域,每个人有每个人的看法,这个真的是一千人心中有一千个哈姆雷特。经常能见到在很多公司产品经理能和程序员争论得面红耳赤,恨不得打起来。所以,用户交互的最高原则是什么?是用户满意,所以如果海康算子SDK中提供的用户控件不能满足客户需求时,开发者完全可以自行设计一套交互逻辑,基于海康算子开发用户自己的控件,而不必过分要求海康必须提供符合用户需求的控件,海康算子SDK附带的控件只能满足大部分客户需求,因为用户控件是一个极容易引起争议非常的地方,不同的用户有不同的使用习惯,不可能一套控件能满足所有用户的需求。
接着添加特定库,特定库根据用户需求添加,以圆查找为例,需要添加的库为MVDCircleFind.dll, 添加引用时定位到路径到
C:\Program Files (x86)\MVDAlgorithmSDK\ReferencedAssemblies\Algorithms
选择MVDCircleFind.Net.dll
如果开发者自己也不清楚实现功能要用到哪些DLL,可以选择全选这些DLL,这样就不必担心引用到的算法库没有被添加进来。
C#很多初学者学编程时,有一个很大的误区,就是过分依赖控件,编写应用程序,最先关注的是,有没有对应的控件?比如,Socket通讯,有没有现成的直接拖到窗口设计器中配置下属性就能用的控件啊?再比如,我要显示来自相机的图像,用什么控件啊?这种思路在初学者身上很常见。
海康算子SDK附带了一些控件,在上面添加控件DLL引用的时候已经提到,在安装完海康算子SDK时,这些控件并不会自动的添加到Visual Studio的工具箱中,还需要用户自己手动添加一下,手动添加也很简单,对着工具箱空白处,右键选择“选择项”,如下图所示:
在随后弹出的窗口中,选择“.NET Framework Components”,找到MV开头的控件DLL,如下图所示:
让我们来做一个简单的示例,读取一张本地图片,对图片执行一次圆查找,并在图像窗口显示查找到的圆。
界面设计如下:
窗口放置了一个MVDRenderActiceX控件,两个按钮,一个加载图片,一个执行算法,两个GroupBox,一个用来设置参数,一个用来显示算法结果。
这个程序非常简单,实现代码也很简单,首先我们在窗口的构造函数中,添加一个mvdRenderActivex1控件的注册事件代码,如下:
public Form1()
{
InitializeComponent();
comboBox1.SelectedIndex = 0;
mvdRenderActivex1.MVDShapeChangedEvent +MvdRenderActivex1_MVDShapeChangedEvent;
}
之所以要注册渲染控件的ShapeChanged事件,是因为我们要通过渲染控件的交互事件中获取用户绘制的ROI。
然后我们在用户添加了ROI或者修改了ROI之后,获取这个ROI,这里我特意过滤一下,就是只有当用户绘制的圆形ROI才把ROI数据获取到,代码如下:
private CMvdShape roi = new CMvdCircleF(new MVD_POINT_F(10,10),5);
private void MvdRenderActivex1_MVDShapeChangedEvent(MVDRenderActivex.MVD_SHAPE_EVENT_TYPE enEventType, MVD_SHAPE_TYPE enShapeType, CMvdShape cShapeObj
{
if (enEventType == MVDRenderActivex.MVD_SHAPE_EVENT_TYPE.MVD_SHAPE_ADDED ||
enEventType == MVDRenderActivex.MVD_SHAPE_EVENT_TYPE.MVD_SHAPE_EDITED)
{
if (enShapeType == MVD_SHAPE_TYPE.MvdShapeCircle)
{
roi = cShapeObj;
}
}
}
读取图片按钮的单击事件,我们添加下面的代码用来获取输入的图像,代码如下:
private string testImagePath = @"D:\测试图\圆查找\test001.bmp";
private CMvdImage testImage = new CMvdImage();
private void btnLoadImage_Click(object sender, EventArgs e)
{
testImage.InitImage(testImagePath);
mvdRenderActivex1.ClearImages();
mvdRenderActivex1.LoadImageFromObject(testImage);
mvdRenderActivex1.Display();
}
设置输入参数,通过下面的代码:
private CCircleFindTool tool = new CCircleFindTool();
private void SetCircleFindParam()
{
tool.SetRunParam("MinRadius",tbMinRadius.Text);
tool.SetRunParam("MaxRadius",tbMaxRadius.Text);
tool.SetRunParam("RadNum",tbCaliperNum.Text);
if (comboBox1.SelectedIndex == 0)
{
tool.SetRunParam("EdgePolarity","Both");
}
if (comboBox1.SelectedIndex == 1)
{
tool.SetRunParam("EdgePolarity", "BlackToWhite");
}
if (comboBox1.SelectedIndex == 2)
{
tool.SetRunParam("EdgePolarity", "WhiteToBlack");
}
}
执行算法按钮单击事件里,我们控制算法执行一次,代码如下:
private void btnExecute_Click(object sender, EventArgs e)
{
tool.InputImage = testImage;
tool.ROI = roi;
SetCircleFindParam();
tool.Run();
if (tool.Result != null)
{
float cx = tool.Result.Circle.Center.fX;
float cy = tool.Result.Circle.Center.fY;
float cr = tool.Result.Circle.Radius;
tbCirX.Text = cx.ToString("f3");
tbCirY.Text = cy.ToString("f3");
tbCirR.Text = cr.ToString("f3");
CMvdShape findCircle = new CMvdCircleF(new MVD_POINT_F(cx,cy),cr);
findCircle.BorderColor = new MVD_COLOR(0x7f,0xff,0x00);
findCircle.BorderWidth = 1;
mvdRenderActivex1.ClearShapes();
mvdRenderActivex1.AddShape(findCircle);
mvdRenderActivex1.Display();
}
}
添加了以上代码后,先执行读取图片按钮,然后设置一下卡尺数量,圆查找的最小半径,最大半径,查找极性,然后在主窗口,右键添加图形,如下图所示:
我们添加一个圆形ROI,添加完成后,调整一下ROI的位置和大小,如下图所示:
接着单击执行算法按钮,执行完成后,会显示如下图的效果:
总体上看,通过上面简单例子,我们发现其实海康算子SDK的二次开发还是非常便捷的,海康的机器视觉算子SDK二次开发入门还是颇为简单的,国内的机器视觉算法平台软件不少,如凌云的VisionWare, OPT的Smart3, 创科的CKVision等,很多只能做到专用,比如锂电行业专用,3C行业专用,只能解决特定应用场景的特定问题,离真正的通用还有很长的距离,SDK封装程度也不高,多数完全是面向过程的C函数式的API,易用性不高,像SDK能封装到海康这样的易用程度,完全面向对象的编程,应该说是国内少有的了。这一点我们欣喜的看到,未来国产机器视觉平台软件会越来越缩小与那些国际大牌(如Mvtec 的Halcon,Cognex的Visionpro,NI的Vision Development Module)的差距,道阻且长,在接下来的机器视觉领域的竞争中,海康的机器视觉算法平台值得期待。