qt怎么调用halcon_机器视觉入门(18)之emgcv实现halcon例程:fin.hdev

第四节 第三个EmguCV程序:fin

还记得上一节开头说的那个例子么,经过今天这两天的念念不忘,被我摸索出来解决办法了!知道答案那一刻才知道我为了实现这一步走了多少弯路,答案原来so easy……好在念念不忘,必有回响。有结果终究是好的,在琢磨的过程中我还学了点新东西,不亏!

那么言归正传,这是一个什么例子呢?见下图:

3e8b32c5d702da2d01de95f763a16edd.png

图 4-4-1

有没有发现有个不小的突起在左边深色物体的边缘,本节的目的就是筛选出这个边缘!图片可以去我QQ群文件下载(强行打广告还是很不好的,所以还是老实点吧,图片下载方式详见本节TIPS 1)。面对这么一块大突起,颜色也跟主物体差不多,有什么好的思路呢?其实简单的形态学就可以了!好像从这一节开始,我们开始重点讲解一些emguCV图像处理方面的内容,好吧,且听我娓娓道来~

首先,先到解决方案那里再新建一个项目(Windows窗体应用程序)。添加完该添加的引用、选择项,然后在form里添加一个imageBox控件一个button控件,如下图(4-4-2):

46a2bac8b48aaf72910d7462ed009e17.png

图 4-4-2

我这人比较懒,按钮少一个是一个,所以读取图片直接放到了form_load()里面,同理,说过的知识点,我也懒得再重复,直接上代码吧(4-4-3):

ab9fb92b682f231f14428dfb2a5c6b84.png

图 4-4-3

Path里面就是那张图片在我电脑保存的位置,这个你得根据你的情况稍微变动变动。所以我一运行,imageBox1控件就已经显示照片了。接下来是"识别"按钮的代码了。粗鲁的先上图(4-4-4)吧:

44519dee8a54ad0392748bd26d416b2f.png

图 4-4-4

代码就这么长啦,但是全篇知识点!思路是这样的:先选出图片右边白色区域,再用大的结构元素进行闭运算,把凹坑处填上,再与闭运算之前的白色区域做差,求出因为闭运算多出来的部分,再用小点的结构元素开运算去掉小的部分,最后得到的就是大的那个突起部分了,最后显示。也就是代码中我写的六步,我们一步一步来:

第一步:跟halcon类似又几乎不一样的threshold:

public static double Threshold(IInputArray src, IOutputArray dst, double threshold, double maxValue, ThresholdType thresholdType):首先,这个方法来自CvInvoke类,emguCV的几乎所有方法都来自这个类。这个方法的意思就是用来阈值的,但是它的功能复杂了很多。先说参数:第一个是要进行阈值筛选的图片,必须是单通道的;第二个是筛选后输出的图片,不是region,是图片!必须强调下;第三个参数是阈值的值(有点蒙?无妨);第四个参数是阈值的最大值,第五个参数你要阈值筛选的方法,对的,一个阈值筛选,emguCV整出了7种方法,多到令人发指啊。。。(欲知7种详情,请见本节TIPS 2),在此先说本例中选择的这种方法,它的意思保留灰度值大于threshold的像素不动,小于threshold的像素全部为0。我们就是选出右边白色的区域,也就是灰度值大于100的区域,灰度值小于100的像素直接被赋值为0了。如果你希望可以像halcon那样看到每一步之后的变量,可以加一句imageBox1.Image=matThreshold;然后再执行下看看。

第二步:就是闭运算这一大块白色的区域了。闭运算是有一个结构元素的嘛,所以先创建一个结构元,这里面用到一个方法:

public static Mat GetStructuringElement(ElementShape shape, Size ksize, Point anchor):这是一个构建并返回Mat类型的结构元的方法:第一个参数是结构元素的形状,第二个参数是它的尺寸,第三个元素是它的锚点,一般都选择(-1,-1)点,即默认的中心点。本例通过这个方法获得了一个半径为270的圆形结构元素。

然后进行闭运算,这个闭运算的算子又厉害了,它不但可以闭运算,还会…,算了我先只讲闭运算,(具体详情详见本节 TIPS 3):

public static void MorphologyEx(IInputArray src, IOutputArray dst, MorphOp operation, IInputArray kernel, Point anchor, int iterations, BorderType borderType, MCvScalar borderValue):这个方法确切来说是进行形态学变换的,但是主线路我们只讲闭运算:第一个参数是输入的图像,第二个参数是变换后输出的图像,第三个参数是你要形态学变换的方法,选择闭运算(close),第四个参数是你要用到的结构元素,本例中就是上面那个圆啦,第五个参数是锚点,选择默认的(-1,-1)就挺好,第六个参数是形态变换的次数,它可以重复多次,这一点与halcon不同;第七个参数是边界模式,我一般也是选择默认的default,第八个参数是边界的颜色,因为是单通道,所以这儿的颜色只有一个参数。闭运算之后,再拿输出的图像再跟输入图像做差,也就是接下来的

第三步:求差

public static void AbsDiff(IInputArray src1, IInputArray src2, IOutputArray dst):这个方法是求两个图像对应像素之间灰度值不一样的地方,这个地方用同一位置两个像素灰度值差值的绝对值表示出来,相当于halcon里面的sub_image()我感觉。不过这儿的灰度值做差是求绝对值的。到了这一步,图像是什么样子了呢?加一行imageBox1.Image=matDifference;就可以看到了,如下图(图4-4-5):

b8c96dbc1cd2d687f453edcae36bf6a5.png

图 4-4-5

第四步:看这图片,心中自然就能想到该怎么做,那就是开运算!对的,跟第三步也就八九不离十了。先实例化一个开运算要用到的结构元素,这儿我又实例化了一个尺寸为5*5的矩形作为结构元素。然后开运算,还是一样的方法,只不过第三个参数改成了Open。开运算结束,就算是咱找出来这一片区域了吧,不过我们得把它框出来,所以用到

第五步:求边缘。要是halcon好像很多种方法可以实现,其实emguCV也差不了多少,这儿我们就用一招canny求边缘的方法。

public static void Canny(IInputArray image, IOutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool l2Gradient = false):后面两个参数一般不用管,第一个参数是输入的原始图像了,第二个参数是输出的边缘图像,第三个第四个参数就是最小最大阈值了,是canny算法里面的。怎么用,前面讲过的啦,你应该知道。经过这一步就求出边缘啦,看下图(4-4-6)。现在问题就是怎么把原图像和这个边缘同时显示出来了,也就是

c044e3667df7309d58ca422475bcb42a.png

图 4-4-6

第六步:要显示,必须要把这个轮廓画到原图上去,然后再显示出来。这儿我们用到了一个方法:

public static void Add(IInputArray src1, IInputArray src2, IOutputArray dst, IInputArray mask = null, DepthType dtype = DepthType.Default):这个方法的意思就是把两张图片的灰度值相加然后输出,类似于halcon里面的add_image()吧,那参数就很好理解了:第一个第二个参数就是输入的两幅图片,第三个参数就是输出的相加后的图片。后面的两个参数都不用填的。(这个加图片如果用的不过瘾,还有更厉害的,详见本节TIPS 3)经过这一步,这个白色的轮廓就画到原图中去了。我们再显示这张图片就大功告成了!

最后一起看结果吧!如下图(4-4-7)。

16246b69a91f559cf3dcbf3733ce7685.png

图4-4-7

最后我们还是得复习下本节新学到的一些方法:

1)public static double Threshold(IInputArray src, IOutputArray dst, double threshold, double maxValue, ThresholdType thresholdType);

2)public static Mat GetStructuringElement(ElementShape shape, Size ksize, Point anchor);

3)public static void MorphologyEx(IInputArray src, IOutputArray dst, MorphOp operation, IInputArray kernel, Point anchor, int iterations, BorderType borderType, MCvScalar borderValue):

4)public static void AbsDiff(IInputArray src1,IInputArray src2, IOutputArray dst):

5)public static void Canny(IInputArray image, IOutputArray edges, double threshold1, double threshold2, int apertureSize = 3, bool l2Gradient = false):

6)public static void Add(IInputArray src1,IInputArray src2, IOutputArray dst, IInputArray mask = null, DepthType dtype = DepthType.Default):

总结:emguCV有点类似于halcon在C#的二次开发,也有一个大的类里面装了很多种方法(halcon里面叫算子),就是CvInvoke类。所以每次调用一个方法的时候,有输出变量的话,都得先申明并实例化那个变量。另外,很多方法你猜是有这个方法的,但是不知道有没有,可以对这个类F12,进入后ctrl+F,搜索你想到的这个方法的关键词就可以了。或者当你对某个方法的参数不记得怎么用的了,不太清晰某个方法是做什么的了,都可以到这里面查找,这个F12的作用就相当于halcon里面的F1帮助。这也是知识点啊兄弟们!

最后的最后,不得不无耻的告诉大家一下:本节的图片其实来自halcon的一个例子:fin.hdev,我是直接截屏保存的。当然这个解题思路也是copy例子里面的,但是运行速度真的慢了好多,比halcon。

本节TIPS:

1) 其实这个图片来自halcon例程:fin.hdev的第一个图片的截图。。。你去截图保存就可以了。

2)

1690ccad716a598f263525203df4e786.png

图 4-4-8

开局我就说过,本书的目的是为了授之以渔,所以我不但要说这七种方法分别代表什么意思,而且我是怎么学来的我也要告诉你们:你用一个emguCV的方法的时候,先F12进入[从元数据]里面看看按照提示一点点弄懂这个方法是干啥的,每个参数的意思以及参数的类型,最后看看所有的可选项,比如上图中的ThresholdType(阈值类型),你在敲入"."之后会自动出来下面的7种阈值筛选的方法,每种方法都有解释,这儿它是用"?:"语法来写的,这个语法是先在问好的左边说一句话,问你对不对,对就返回冒号左边的数值,不对就返回冒号右边的数值。 比如第一个Binary,问号左边就是value>threshold(第三个参数:阈值的值),若对,就返回max_value,那该点的灰度值value就等于max_value(方法里面第四个参数)了,若不对,就返回冒号右边的,就是0 了。所以这个方法的作用就是把一张图片中灰度值大于threshold(第三个参数)的像素全部重新赋值为最大阈值(第四个参数),小于threshold的全部赋值为0,即(抹黑)。如下图(4-4-9),我的threshold是50,max_value是255:

3df9c03c4027dec9eaf6f256c8db77bc.png

图 4-4-9

灰度值大于50的地方都变成了255的灰度值,小于50的地方灰度值都变成了0。

理解通第一个,接下来的就很好理解了:

BinaryInv:value= value>threshold?0:max_value。跟Binary刚好相反,大于threshold的像素赋值为0,小于threshold的反而赋值max_value。如下图(4-4-10)(参数还是那么多):

d7db5e22c620e63551b4f786647de82c.png

图 4-4-10

Mask:是什么意思呢?我母鸡啊~鼠标选中它也不解释,我运行还报错。。算了不管它!

Otsu:这个是自动选择最优阈值,就是第三个参数,它自己给你算出来,所以你设置的多少就没用了。哈哈知道它是怎么算的吗?我知道,但我不想说!好啦,其实在halcon部分已经说过了……。先看效果(4-4-11)(我三、四两个参数都设置为255的):

c3999b523b82de91fdeb3f8746b10fe3.png

图 4-4-11

ToZero:value=value>threshold? Value:0。这意思就好理解了,保留灰度值大于threshold的像素不动,小于threshold的像素全部为0,如下图(4-4-12)(为了明显点,第三个参数我改成了100):

2ac87ef98f38cd34dc9302039abe7b66.png

图 4-4-12

ToZeroInv:value= value>threshold? 0:Value。这个又跟上面一个相反了,大于threshold的像素全部抹黑为0,小于threshold的全部保留。如下图(4-4-13)(参数没变):

22dbdad1beee886723e147d717d9ed0c.png

图 4-4-13

Trunc:value= value>threshold? Threshold:Value。灰度值大于threshold的像素全部赋值为threshold,灰度值小于threshold的像素保持原状。如下图(4-4-14)(参数没变):

650c433c2cb5c3f08ac9866c5996fd86.png

图 4-4-14

七种方法总算讲完了,感觉画了我好多的力气去讲一个算子实在是心累,划不来。以后这种知识点我不会再这么认真详细的讲了哈!已经教你们方法了,得自己学会学习嘛。

3) MorphologyEx()这个算子其实是形态学变换嘛,看完正文你也知道,但是它不但可以进行开运算(open)、闭运算(close),还可以进行腐蚀(erose)、膨胀(dilate)、梯度(gradient)、顶帽(tophat)、黑帽(blackhat),对的,就是这么多,简直厉害!开闭运算,腐蚀膨胀,相信你都用的很熟悉了,但是剩下三个可能就有点陌生了,我在网上搜到了这三个形态学变换的公式,方便大家理解:

Gradient(img)=dilate(img)-erose(img);

Tophat(img)=img-open(img);

Blackhat(img)=close(img)-img;

其实有点像是组合拳了。梯度感觉有点像轮廓的感觉,顶帽黑帽感觉有点像是找那些边缘的突起和凹坑。其实这个黑帽就是本节找那个疙瘩的思路,你发现没有?

4) public static void AddWeighted(IInputArray src1, double alpha, IInputArray src2, double beta, double gamma, IOutputArray dst, DepthType dtype = DepthType.Default);这个算子也是两个图片灰度值相加,只不过它加的有点任性,我用公式来表达吧:dst=src1*alpha+src2*beta+gamma;对的,就是说不但可以灰度相加,还可以乘以系数相加,最后还可以加一个补偿!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值