halcon显示坐标_机器视觉入门(19)之 halcon与emgucv之间的转换

第五章 halcon与EmguCV之间的转换

其实一般情况下都是halcon转emguCV了,反过来做的应该很少吧?所以本章我也是只说怎么把halcon算子转换成emguCV代码。其实halcon跟emguCV都有那么多代码,很多我也在学习中呢,所以本章只有一节,把我整理的一些学习笔记写进来与大家一起分享。

先聊几个稍微简单的吧!

(1) Halcon里面的read_image(),其实就相当于emguCV里面的带地址参数的实例化image或者Mat,或者也还有一种方法,就是:

public static Mat Imread(string filename, LoadImageType loadType):读取一个图片。

(2) Halcon里面的打开相机open_framegrabber()相当于emguCV里面的实例化Capture类;

(3) Halcon里面的保存图片write_image()相当于:

public static bool Imwrite(string filename, IInputArray image, params int[] parameters):保存图片。

(4) Halcon里面的grab_image()就相当于emguCV的grab()了等等。

注意:这里说的"相当于",不是意思完全一样的意思,只是主要功能大致相同。

下面我们再主讲几个算子之间的转换。

第一个:图像格式的转换(trans_from_rgb()),如下图(4-5-1),是把一个BGR的图像转换成HSV空间。

1a2de33a0e0db215c31d69c1f5b05c32.png

图 4-5-1

如上图(4-5-1),我用方法的形式写了这个转换。首先,申明并实例化一个Hsv格式的image,大小等于需要转换的图像的尺寸。然后是关键代码:

public static void CvtColor(IInputArray src, IOutputArray dst, ColorConversion code, int dstCn = 0):一开始我看F12里面的解释以为这个代码只能进行颜色控件之间的转换(Bgr转换到Hsv),结果在ColorConversion的时候,发现Hsv转换到Bgr,Bgr转成灰度图也是这个算子!所以这个算子相当于也对应了trans_from_rgb(),trans_to_rgb(),rgb1_to_gray()。学一个抵三个了。这波不亏。那参数就好说了:第一个参数是输入的图像;第二个参数是输出的图像;第三个参数是要转换成哪个颜色空间(Bgr到Hsv,Hsv到Bgr,Bgr到Gray)全部在这里选择,其实还有其它类型的转换,在此不做扩展了。第四个参数是输出图片的通道数,默认为0,就是取决于转换的方式,不用填的。

可是转换出来后,它是一个Hsv空间的Image,需要单独得到三个通道的图片,还需要把他们分离开。这就相当于halcon里面的decompose3()了。这儿用到一个分离的方法:

public static void Split(IInputArray src, IOutputArray mv):把多通道的输入图像分离成多个单通道的图像。两个参数第一个是输入,第二个就是输出了。这儿我声明并实例化了一个VectorOfMat类型的变量,用来作为输出,然后分别拿三个Mat类型的图片来让它赋值。(遇到这种新类型,千万不要懵逼,因为我们有TIPS 1)。最后这三个Mat图片就是转换的3个单通道的H、S、V图片了。见下图(4-5-2),从左到右为RGB图,H,S,V图片:

5b883a322db3f64cb494ccfaee1af3f8.png

图 4-5-2

第二个:阈值筛选(threshold())。上一节已经详细介绍了阈值筛选的7种类型,但是它的思路跟halcon还不是完全一样,比如你要筛选灰度值在50到120之间的部分,该怎么做呢?如下图(4-5-3):

f1daf730b2a3f165ff3f56ba1dd04fc6.png

图 4-5-3

这是针对halcon里面的region理论选择的方法,就是说只记录这个地方的位置信息,不记录这个地方的像素灰度值信息。所以我的ThresholdType后面选的是Binary和BinaryInv。其实binary就是二进制的意思,非黑即白,先对这个单通道图片进行阈值筛选出灰度值大于minValue的部分,赋值为255;然后再对单通道图片阈值筛选出灰度值小于maxValue的部分,赋值为255,这样你就获得了两张图片,两张图片的高亮部分分别代表了原始图片灰度值[minValue,255]和[0,maxValue]的部分,这两个部分再求交集就是[minValue,maxValue]的地方了。那么求交集怎么求呢?不再是halcon里面的intersection了。而是:

public static void BitwiseAnd(IInputArray src1, IInputArray src2, IOutputArray dst, IInputArray mask = null):这个算子就是"与"操作了。每个像素每个像素的进行。(这是"与"操作,那么"或"操作,"非"操作呢?详见本节TIPS 2)

经过这一步,一般的halcon里面的threshold就可以实现啦,如果还要实现一些其它的阈值方法,就靠同学们自己去摸索了。老规矩,看看这个方法实现的结果吧(4-5-4)(我的minValue和maxValue参数分别设置为50,150):

cd32b106a0326f66ca5b9c046c72e5ed.png

图 4-5-4

第三个:筛选区域(select_shape())。这儿我只讲最常用的面积筛选了哈。代码见下图:

030decc3231fb4b7d009f8365c5c67f4.png

图 4-5-5

其实意思是有点变化了。这个是找到一个一个的轮廓,然后根据轮廓的面积进行的筛选,注意不是那个区域的面积,是轮廓。这个方法的参数我得说一下,第一个参数就是输入的原始图片了,但是这个图片不是任何Mat都可以的,必须是binary的,或者说必须是二值图。如果不是怎么办?在线等,很着急?转呗,我就是这么弄的,直接用上面的第二个阈值筛选就可以得到二值图了;第二个参数是输出的轮廓,它是二维数组的点的集合,这个在本节TIPS 1 已经有说;第三个、第四个参数是轮廓面积的最小最大阈值了。那么,怎么实现的呢?首先:

public static void FindContours(IInputOutputArray image, IOutputArray contours, IOutputArray hierarchy, RetrType mode, ChainApproxMethod method, Point offset = default(Point)):顾名思义,找到轮廓。第一个算子输入的图片;第二个参数输出的轮廓;第三个参数是可选的输出向量;包含关于图像拓扑的信息,我一般都是null;第四个参数是找轮廓的类型,这可以有四个选项,请自己查看啦;第五个参数是计算轮廓里面用到的近似的方法,我喜欢选简单的,不让cpu太辛苦。第六个参数直接默认。

找到轮廓后还不够,还要根据面积筛选。筛选前得知道每个轮廓的面积,这就用到一个方法:

public static double ContourArea(IInputArray contour, bool oriented = false);计算轮廓面积。里面第一个参数是输入的轮廓,第二个参数是什么方向?默认为false吧。那我算出来的面积在哪输出啊?好吧,我调皮了,这是一个带返回值的方法,返回的double类型就是面积了。

整个函数的逻辑就是先找到所有的轮廓,然后用一个for循环依次求出每个轮廓的面积,再把符合面积的轮廓一个一个push到输出result_contour里面。这儿有一个细节,对于VectorOfVectorOfPoint类型的轮廓,里面的成员就是VectorOfPoint类型的,而vectorOfPoint类型的又相当于一个数组,它里面的成员又是Point类型的。

说了这么多,还是看看效果吧,下图(4-5-6)左一是一个彩色图片,中间的是转成的binary图片,最后是找到的轮廓。

de5a2e52883988b60831c9be10a802db.png

图 4-5-6

学完这么多是不是觉得有点别扭?特别是像我这种用惯了halcon的,刚转emguCV的时候特别的难受啊,各种数据类型之间的变换都特别的别扭。渐渐我发现了原因:首先:halcon喜欢基于region去做很多事,而emguCV则喜欢基于图片像素本身。这就意味着每次操作都是对图片的。而图片的类型也挺多的。其次,就是你执行一步后想看看什么效果不是很方便,不像halcon,全部在变量窗口里面,随时查看。最后,就是没有halcon那么多辅助功能啦,比如特征检测,前趋函数,后继函数,还有自动的彩色显示等等。(说到这儿我倒是想到一个小TIPS 3,差点忘记了)。总的来说,作为免费的,已经不错了~

第四个:裁剪图片(crop_part()),讲到这儿才发现这个算子我好像没讲过,那好吧:

crop_part( : ImagePart : , , , : ):就是裁剪图片。后面四个参数决定了一个矩形区域,裁剪掉图片矩形区域以外的部分。第一个参数是要裁剪的图像;第二个参数是裁剪以后的输出图像;第三个第四个参数是矩形的左上角点的坐标;第五个第六个参数是矩形的宽和高。

其实这个算子对应的emguCV算子超级简单,就是Mat类的实例化,非要写成一个方法的调用,那就如下图(4-5-7):

57bc91e68bdede3b8f28f0f83c6e6479.png

图 4-5-7

在halcon的F1帮助里面,搜索"crop",发现好几个裁剪的算子,还有一个算子:

crop_domain_rel( : ImagePart : , , , : ):也是裁剪图片,只是形式稍有不同。第一个参数就是待裁剪的输入图片;第二个参数就是裁剪后的输出图片;第三个参数是从顶部往下裁剪掉多少行像素;第四个参数是从左往右裁剪掉多少列像素;第五个参数是从下往上裁剪掉多少行像素;第六个参数是从右往左裁剪掉多少列像素。这个感觉有点像剪刀,对图像四个边各给上一剪刀。经过简单的数学变换,这也是可以变成上面的那个算子的。但是如果还用上面那种算法,我就没必要扯这么多了嘛。这儿我再教大家一招,如下图(4-5-8):

7a3f3bb0539656cbac7843da3e20d470.png

图 4-5-8

这个算法,是从像素的角度去裁剪图片,或者说把要保留的部分重新赋值给一个新的图片。所以新图片的尺寸就是裁剪后的尺寸了,也就是上图中(4-5-8)的size1,是原图片宽度减去左右裁剪掉的列数,和原图片高度减去上下裁剪掉的行数。然后对图片进行实例化,赋予尺寸。然后两个for循环的嵌套,给这个新图片ImageCroped三个通道的每个像素赋值。怎么赋值呢?这儿有一个对应关系,假设原图片left减掉了5列,top减掉了6行,那么原图片的(5,6)位置的像素值就等于新图片(0,0)位置的像素值,对不?理解了这一点,再看上图中我的嵌套循环就很好理解了。其中data[]里面的三个数分别代表像素的横纵坐标和通道,都是从0开始的。

讲了这么多,不能只是看看而已哦亲们,一定要自己亲自操作下,才能转换成自己的知识,反正都是最后一节了,要辛苦也是最后一次了,再坚持一下咯!

还有就是,halcon算子跟emguCV的算法都是上千个的,我这儿只是列举了其中的很少一部分,非常常用的一部分。其实还有很多重要的算子,要考我们自己去学习了。毕竟,这只是一本入门的教材嘛,一年级的数学书怎么会教你乘法口诀,但它依然是你将来学会微积分,泰勒公式,高斯定理,傅里叶函数最下面的那块垫脚石。

最后,一起复习下这一节学到的方法:

1)public static Mat Imread(string filename, LoadImageType loadType):

2)public static bool Imwrite(string filename, IInputArray image, params int[] parameters);

3)public static void CvtColor(IInputArray src, IOutputArray dst, ColorConversion code, int dstCn = 0);

4)public static void BitwiseAnd(IInputArray src1, IInputArray src2, IOutputArray dst, IInputArray mask = null):

5)public static void FindContours(IInputOutputArray image, IOutputArray contours, IOutputArray hierarchy, RetrType mode, ChainApproxMethod method, Point offset = default(Point)):

6)public static double ContourArea(IInputArray contour, bool oriented = false);

7)crop_part(: ImagePart : , , , : ):

8)crop_domain_rel(Image:: , , , : ):

本节TIPS:

1) VectorOfMat具体什么意思,我也说不上来,矢量图片?查了一些资料没找到很好的解释。我自己的理解就是数组,Mat是一个图像,那VectorOfMat就是n个Mat,不过是有序排列的。那同理:

VectorOfPoint就是一组点的有序排列了,VectorOfVectorOfpoint就是n个二维排列的点了。一法通,万法通,所有的VectorOf的都好理解很多了,以后应该还会再遇到它的。

2) 其实你自己F12也能找到了,毕竟打渔方法都交给你们啦!

e6c93b0aca2d74bf9dba60c51ca4b915.png

图 4-5-7

如上图(4-5-7)从上到下,分别为与,非,或,异或。

3) 这个是关于imageBox控件的一个使用小技巧,就是当程序运行时,可以在imageBox控件上右键来做一些操作。比如保存图片,读取图片,缩放,以及最后一个property,可以看到很多图像的特征,如下图:图中红框框按钮还可以看到图像的灰度直方图,看不清数字是可以放大看的哈。

de90d20730661dbfefdda87043208cdf.png

图 4-5-8

f2e1e7090453be3c32152dcbd7af12e3.png

图 4-5-9

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:1024 设计师:我叫白小胖 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值