2.3.2 第二个halcon程序转EXE程序:字符识别
老规矩,每一段halcon代码得用C#二次开发下。根据上一节所教的,我们配置下C#的环境,顺便添加好控件,如下图(2-3-2-1)。
控件基本跟上一节一样,只是少了一个button多了一个textBox。我就不用截图教了。
还是粗鲁的直接上代码。图中(2-3-2-2)①后面为声明全局变量,用来存储读取的图片;Form1_load里面的步骤②,可能新手有点迷糊,这其实是一种编程习惯了。(详见本节TIPS 1)步骤③有两个知识点:第一个是c#的,就是用OpenFileDialog类,该类的作用是显示一个标准的对话框,用于打开文件。当然对于我们这个例子,你也只能打开我给的那张照片,毕竟其它照片就不一定适用于剩下的代码了。适用方法就是如图中红笔标明的第③步了,首先是实例化一个ofd,然后if()条件语句判断,接下来你就可以在readImage()里面用ofd.FileName来表示图片的地址了。有没有比上一节用个string类型的path写地址高大上一丢丢?
关键是这个方法可以打开任何一张图片,算是比较灵活的打开文件的方式了。当然百度上还有更详细的教程,如果你有兴趣,不妨查查看。
第二个知识点就是,你读取的图片大小跟你的halconWindow大小不匹配怎么办,你得让图片矢量缩放。这个上一节的时候我刻意没讲解,怕知识点太多。现在教刚好,就是图中我画圈的两步。先获取图片的大小:GetImageSize(),里面的参数根据提示通俗易懂,再SetPart(): set the part of the image that is displayed in the graphics window。对,就是这个意思,所以你只要把上一步获得的长宽作为全部尺寸SetPart就可以了。当然有个需要注意的细节:GetImageSize的时候参数顺序是先宽再高,SetPart的时候参数顺序是先高再宽,比如本例中。可是为什么呢?因为坐标,自己悟去吧~~^_^
接下来是大头,OCR的识别,双击"OCR识别"按钮,在里面敲下如下代码,你若牛13,最好先根据上一节教的方法,自己先试试,这样带着问题看答案会效果超级好,我的答案如下图(2-3-2-3):
按照TIPS 1)里面的方法,我们先为所有的图形变量申请一个空变量。就是图中(2-3-2-3)矩形里面的一大坨。然后每个变量用之前先dispose,就是图中椭圆里面的。
程序结束,所有的图形变量再dispose掉,如图中的矩形框内。熟悉了这个大的结构形式,下面我们来看具体的代码。Halcon代码2.3.1里面已经有了,怎么转换,我也第二节里面说过,如果还要我废话,那这本书得厚很多倍。
不过有个地方,还是需要提一下的:就是本代码,我在halcon里面的时候是识别出字符然后在字符上方一定位置显示出来,这里面我没有那么做了,而是用textbox控件显示出来。那就涉及到一个问题,怎么把HTuple类型的classs(因为class是C#的关键字,不能作为变量名使用,所以我加了一个s,你没有意见吧?)里面的字符弄出来。对的,答案已经在上图(2-3-2-5)中了,就是一个for循环。不过所有对HTuple 的操作方法都是'.Tuple+~',比如说它的长度是'.TupleLength()',不是c#自带数组里面的'.Length()',然后就是HTuple每一个成员的调用方法'.TupleSelect()'。当然还有很多其它方法,你可以'.'之后自己看,也都有自带解释。(又是一个打渔方法,有木有?)
有了上一节的halcon程序转exe的铺垫,这一节好讲解多了,虽然代码长了不少,但是总共也就几页纸就可以说清楚了,其实主干部分还是蛮有规律可寻的。
亲爱的读者,当你学习到这一节。其实整个视觉项目的软件部分的主要流程你都大致了解了。只要是基于halcon和C#二次开发的,基本上是脱离不了这个主框架。什么主框架呢?有点懵?好吧。。
第一步:获取图片,一般都是通过相机现场拍照,保存下来;
第二步:用halcon对照片进行图像处理,达到目的(比如例子中的找到人脸,或者识别字符等);
第三步:把halcon代码转成C#代码(大多数情况下是作为一个类或者一个方法),可以自己一步一步转,也可以直接用halcon自己生成的方式(这个我在2.2.2有讲,网上有更详细的教程)。
写完这一节,现在已经是2018年2月份的某个晚上。听着毛不易的《像我这样的人》,不自禁情绪涌上心头。。。今年我就28周岁了,依旧碌碌无为。想做一些事,总是觉得缺把火。喜欢的女同事也一直刻意跟我保持距离。这女孩特别爱笑,眼睛也好看。同事教我三招:1)坚持;2)不要脸;3)坚持不要脸。
话是这么说,但是真的好难做到,总感觉她对我爱答不理,我也不想死皮赖脸,更觉得死皮赖脸会适得其反,毕竟大家都是同事。
亲戚中也有人劝我,不要眼光太高,找个差不多的就可以了。这意思再明白不过:我的能力配不上我的眼光。可是为什么非要我降低眼光呢?我不能提升能力吗?最近在看一本书知乎大神李栩然的《所有的奋斗都是一种不甘平凡》。哈哈,听名字就是鸡汤文。但是生活嘛,你有多久没喝过鸡汤了?隔段时间拿个鸡汤文鞭笞下自己对我来说还是挺有意义的。毕竟"最怕你一生碌碌无为,还安慰自己平凡可贵"……
本节TIPS:
1) 本人写过很多halcon代码,然后自动生成C#代码(方法上一节有说,别跟我说你忘记了)。再慢慢学习这些C#代码后,发现了一个规律:所有的图形变量(HObject,HImage,HRegion等)都是先声明,再为其申请一个空变量,每次用之前先dispose(),程序结束再dispose()。这样的好处是肯定不会有内存泄漏,这个问题上一节我刻意没提,换言之上一节代码有内存泄漏的缺陷,这样的缺陷,单次运行是没有什么关系的,但是一旦运用到工程上,往往都是循环执行的,每次内存泄漏一点儿,积少成多,一会儿系统就崩溃了。因此这一节开始,我们按照规范的来。(其实,当我再检查的时候,发现本例我的代码里面其实也还有变量没有被dispose。哈哈,机智的你发现没有?)
那么,有的人会疑问,为什么要先申请空变量呢?其实是因为,halcon代码自动转成C#代码的时候,一般方法里面都会加上try-catch语句,一旦运行报错,在catch里面也可以把所有的变量dispose()掉,避免内存泄漏,如果没有之前申请的空变量,报错后,就不知道怎么dispose()了。所以都在try-catch语句之前先为声明的所有图形变量(HObject,HImage,HRegion等)申请一个空变量。这个大家多写几次就能理解了。