Halcon找圆系列(4)测量圆直径/半径的方法之暴力拟合法 vs 测量工具法

今天要给大家分享一点关于Halcon测量圆直径(半径)的方法。
首先容我啰嗦两句:之所以要对这个看似很基础的问题进行探讨,主要原因有二,其一是这个问题确实困扰了我一段时间,当然这主要是由于我自己经验不足所致;其二是为了解决这个问题,我在网上查阅了很多博客资料,突然发现一件比较有趣的事情——网上多数能搜索到的关于这个问题的博客居然都主动避开了Halcon设计者的初衷,即最简单实现它的方式,反而和我这个经验不足的家伙一样,采用了自以为合理的解决方案——而且居然还是相近甚至相同的思路。针对这个现象,我后来也发现了一些原因,留待本篇的末段解释,此处卖一个关子,暂且不表。

1 暴力拟合法

上来先给大家讲一下在多数博客里采用的方法——思路其实简单又暴力,而且确实是有效的,我将其称为暴力拟合法。
算法如下:
Step1: 如下图给出一个带有圆形区域的图形,首先我们调用一个画圆的工具,来逼近它的边缘区域。

image.png

Step2: 然后绘制这个圆的两个同心圆作为边界,即直径略大于和略小于它的两个同心圆;

image.png

Step3: 这样做的目的,是为了把包含待测量圆边界的环状区域分割出来;
Step4: 对分割出的局部环形区域作边缘提取,得到一系列边界轮廓;
Step5: 采用Halcon的轮廓拟合算子完成圆的拟合。

image.png

短短五步,成功获得了当前圆的拟合参数。
参考代码如下所示:

dev_close_window()
dev_update_off ()
dev_open_file_dialog ('read_image', 'default', 'default', Selection)
read_image (Image, Selection)
get_image_size (Image, Width, Height)
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image)
draw_circle_mod (WindowHandle, Height/2, Width/2, Width/20, Row, Column, Radius)
gen_circle_contour_xld (ContCircle, Row, Column, Radius, 0, 6.28318, 'positive', 1)
dev_display (ContCircle)
dev_set_color ('green')
gen_circle (Circle1, Row, Column, Radius*13.0/10)
gen_circle (Circle2, Row, Column, Radius*7.0/10)
dev_set_draw ('margin')
dev_display (Circle1)
dev_display (Circle2)
stop()
difference (Circle1, Circle2, RegionDifference)
reduce_domain (Image, RegionDifference, ImageReduced)
edges_sub_pix (ImageReduced, Edges, 'canny', 1, 20, 40)
fit_circle_contour_xld (Edges, 'algebraic', -1, 0, 0, 3, 2, Row1, Column1, Radius1, StartPhi, EndPhi, PointOrder)
gen_circle_contour_xld (ContCircle1, Row1, Column1, Radius1, 0, 6.28318, 'positive', 1)
dev_clear_window ()
dev_display (Image)
dev_display (ContCircle1)
message1 := 'CenterRow: ' + Row1
message2 := 'CenterCol: ' + Column1
message3 := 'Radius: ' + Radius1
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
disp_message (WindowHandle, message1, 'window', 0, -1, 'forest green', 'false')
disp_message (WindowHandle, message2, 'window', 20, -1, 'forest green', 'false')
disp_message (WindowHandle, message3, 'window', 40, -1, 'forest green', 'false')

2 真的成功了吗?

但是,完美?No!
这个方法有一个致命缺陷,因为它是我们强行通过Contour轮廓算子的一些特性来完成的拟合,所以它是一个一次性的产物,并不符合Halcon设计者的初衷。
为什么这样说呢?我举下一个例子来说明这样做的局限性:
还是刚才这个工件的图像,但是现在不是一张,而是一组,这个工件在图像中的位置角度等均发生了变化,现在要求我们1)定位工件2)在定位工件的基础上找到圆孔并计算它的直径。
我们知道,Halcon完成“定位”-“测量”分别是通过*.shm和*.mtr文件这样的形式来构成通用方案的。那么通过暴力拟合法,如何才能跟*.shm文件进行绑定,从而减低我们在定位完成的基础上,二次定位圆ROI的工作量呢?
(当然这也是有方法的,并且我也尝试并实现过,需要通过记录圆和定位模板间的相对位置关系,通过仿射变换来得到每次定位后的圆ROI,但这样增加了很多参数的传递,使定位过程和测量过程更加孤立,显然也不会是Halcon设计者的设计思路)
别急,相信和我水平相当的Halcon小白使用者都会想到Halcon的测量助手工具。假如问题不是要测量一个圆的直径,而是要测量某个工件的宽度,那么我们可以通过Halcon的Measure工具生成一个测量卡尺。点一下生成代码,略微添加几个变量,轻松加愉快。可是问题来了,Halcon的测量助手居然没有提供测量圆直径的工具!

 

3 测量工具法

但是事实上Halcon提供了一个圆的测量卡尺,只是它的名称被藏在了另一个算子里。下面隆重推出这个算子:

add_metrology_object_generic( : : MetrologyHandle, Shape, ShapeParam, MeasureLength1, MeasureLength2, MeasureSigma, MeasureThreshold, GenParamName, GenParamValue: Index)
你也许和我一样,在对这个算子还不了解的时候完全忽视它。从名称上看,这个算子和圆卡尺工具有半毛钱关系?(相信这也是博客里都是暴力拟合法而鲜有提及这个方法的主要原因。)
然而当看到Shape这个参数的列表时,我就知道Halcon的设计者绝对还是聪明人,这个参数有一个选项是’Circle’.
当Shape参数设置为’Circle’时, ShapeParam的格式要写成[Row, Column, Radius].
这样就清楚了,问题也解决了,和其他测量工具一样,只要调用这个算子生成一个圆测量卡尺,通过apply_metrology_model,再通过get_metrology_object_result取出测量结果就大功告成了。

image.png

这个方法和任何其他测量工具一样,都可以与前置的定位工具进行align,省下了好多事情,而且也维持了Halcon在定位-测量环节上工具逻辑的一致性。
参考代码如下:

dev_close_window()
dev_update_off ()
dev_open_file_dialog ('read_image', 'default', 'default', Selection)
read_image (Image, Selection)
get_image_size (Image, Width, Height)
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image)
draw_circle_mod (WindowHandle, Height/2, Width/2, Width/20, Row, Column, Radius)
gen_circle_contour_xld (ContCircle, Row, Column, Radius, 0, 6.28318, 'positive', 1)
dev_display (ContCircle)
dev_set_color ('green')
create_metrology_model (MetrologyHandle)
add_metrology_object_generic (MetrologyHandle, 'circle', [Row, Column, Radius], 20, 5, 1, 30, [], [], Index)
apply_metrology_model (Image, MetrologyHandle)
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'result_type', 'all_param', Parameter)
get_metrology_object_result_contour (Contour, MetrologyHandle, 'all', 'all', 1.5)
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row1, Column1)
dev_display (Contours)
stop()
clear_metrology_model (MetrologyHandle)
dev_clear_window ()
dev_display (Image)
dev_display (Contour)
message1 := 'CenterRow: ' + Parameter[0]
message2 := 'CenterCol: ' + Parameter[1]
message3 := 'Radius: ' + Parameter[2]
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
disp_message (WindowHandle, message1, 'window', 0, -1, 'forest green', 'false')
disp_message (WindowHandle, message2, 'window', 20, -1, 'forest green', 'false')
disp_message (WindowHandle, message3, 'window', 40, -1, 'forest green', 'false')

4 总结

经过这件事情我发现,只有当我们接触更加复杂的任务的时候,才更有机会站在一个全局的设计者,而不仅仅是一个一锤子买卖的使用者的角度来思考问题。所以面对很多工程问题,如果我们一直站在边缘而不去做泛化的尝试,那么我们将永远无法得窥它的真实内涵。从这个角度来说,可能Halcon的设计者才真的用心良苦,把这样的工具藏在只有深入思考才能找得到的地方。
ps:

关于本文中提到的定位测量联合算法可能会在后期博客中呈现,毕竟短时间内没有形成比较成熟的文字,相信水平比我高的读者朋友们肯定早就自己想到该如何实现了。
本文中提取圆ROI的方法之所以手绘是为了方便讲述,实际使用时当然可以通过blob分析来获得近似圆区域的ROI,相信这是小白Halcon玩家一样能做得到的事情。


转载自:https://blog.csdn.net/libaineu2004/article/details/106745204


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864