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

十年热恋 提交于 2020-01-04 02:40:15

原文链接:https://blog.csdn.net/horsee/article/details/82794569

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

暴力拟合法


上来先给大家讲一下在多数博客里采用的方法——思路其实简单又暴力,而且确实是有效的,我将其称为暴力拟合法。
算法如下:

  • Step1: 如下图给出一个带有圆形区域的图形,首先我们调用一个画圆的工具,来逼近它的边缘区域。
  • Step2: 然后绘制这个圆的两个同心圆作为边界,即直径略大于和略小于它的两个同心圆;
  • Step3: 这样做的目的,是为了把包含待测量圆边界的环状区域分割出来;
  • Step4: 对分割出的局部环形区域作边缘提取,得到一系列边界轮廓;
  • Step5: 采用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')
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')



真的成功了吗?
但是,完美?No!

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

测量工具法


但是事实上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取出测量结果就大功告成了。

这个方法和任何其他测量工具一样,都可以与前置的定位工具进行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)

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')

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!