最近研究halcon的圆孔定位四个月了,这里分享一下我的心得,也是备忘
项目描述
- 图片尺寸1600*1200
- 支持任意类型的圆孔检测
- 参数:圆的半径,极性
- 极性除了内黑外白,内白外黑,还有可能是黑色条带中心,白色条带中心
- 时间:100ms以内
- 图像有可能虚焦
- 用户给出的直径有可能有10%的偏差
- 用户给的极性可能是错误的
- 圆环周围可能有干扰边缘,但必须找到最精准边缘
- 容差:2个像素以内
- 宁可拒报,不允许误报
Halcon圆检测相关方法
方法 | 描述 | 缺点 | 比较好用的算子 |
---|---|---|---|
区域分割 | 直接用对比度分割出关键的圆形 | 当圆环和周围颜色相近时,直接罢工 | segment_image_mser |
边缘分析 | 提取图像中的关键边缘,找到可能是圆弧的部分,拼接成一条完整圆弧,然后拟合 | 平滑后的精度低,不平滑图像中有很多零散圆弧干扰 | edges_sub_pix |
霍夫变换 | 通过沿着区域点画圆,找到大概率是圆心的区域 | 当参数半径和实际偏差较大时,得到的区域不准确 | hough_circle_trans |
二维边缘测量 | 在圆周一圈找阈值峰值点,用这些点进行拟合 | 有图像可能存在非常多的干扰峰值 | add_metrology_object_circle_measure |
NCC模板匹配 | 基于模板和图像的偏差 | 当图像圆中有复杂图像时,无法找到结果 | find_ncc_models |
形状模板匹配 | 基于模板的边缘对比度 | 较差的图像需要调低得分,但低得分容易带来错误结果 | find_shape_models |
梯度图关键点拟合 | 先找到梯度图中可能是圆弧的点,再用这些点进行拟合 | 找的点不准确容易有偏差 | edges_image, fit_circle_contour_xld |
算法步骤
通常,我们进行两次定位
- 粗定位:目的是获得圆的大致位置,然后可以用reduce_domain缩小图像范围(减少精定位时间),粗定位有很多好用的方法,但是都有其局限性,这里就不赘述。
- 精定位:为的是能找到更精确的边缘,得到更高精度的结果
算法描述
因为遇到了很多糟心的图片,所以楼主的算法也相应比较复杂
下面是简单的描述:
- 粗定位 :
1. create_shape_model 共需两个模板,金字塔层数设为2(1太耗时,3以上有可能找不到目标圆),一个ignore_global_polarity,一个ignore_local_polarity,最好保存模板,因为生成模板是很耗时的操作
2. 第一次 find_shape_models 找ignore_global_polarity的模板,分数0.8,个数5,不允许重叠
3. 第二次 find_shape_models(第一次没找到才需要) 找ignore_local_polarity的模板,分数0.8,个数5,不允许重叠
4. 第三次 find_shape_models 平滑图像(第二次没找到才需要),找ignore_global_polarity的模板,分数0.8,个数5,不允许重叠
注意:三次有任何一次有结果就可以直接作为粗定位结果,接下来对找到的结果逐个分析 - 精定位 :
-
预处理:
reduce_domain 缩小范围
edges_image 获取梯度图,方向图 -
获取梯度方向偏差图片:
因为圆环的梯度方向都是统一的,类似如下的图片(有可能需要旋转),我们可以用得到的梯度方向图减去下图,就可以得到梯度方向偏差图,其中灰度接近0的点就是我们所需要的关键点 -
对梯度方向偏差图做极大值抑制,得到Image_Result
nonmax_suppression_dir 这样可以获得最可能是圆周的边缘点集 -
找条带边缘
find_shape_models 找梯度方向偏差图的边缘,极性ignore_global_polarity,分数0.8,只找最高分的结果,这个结果就是我们所需的边缘 -
对条带边缘做精拟合
因为shape_model得到的结果不稳定,在边缘有毛刺时容易有细微的偏差,所以我在这个结果周围找到Image_Result中的关键点进性拟合 -
找边缘结果
find_shape_models 找原图的reduce_domain图的边缘,极性ignore_global_polarity,分数0.8,只找最高分的结果,这个结果就是我们所需的边缘
注意:如果粗定位使用了平滑,那这里也需要平滑,因为图像可能存在很多噪点、条纹的干扰 -
对原始边缘做精拟合
因为shape_model得到的结果不稳定,容易有细微的偏差,所以我在这个结果周围找到Image_Result中的关键点进性拟合 -
仍未找到目标圆的情况
如果还没找到圆,有两种可能,
1:图像很差
2:客户的直径或极性输错了 -
权重定位法
因为客户给出的直径有可能是错误,所以这里我使用过程中得到的半径作为目标分析,而不再使用客户给出的直径,这样也可以提高对不良结果的过滤。
注意:精定位可以直接使用权重定位法,跳过上面的条带结果和边缘结果分析,但这样遇到多层圆环时,容易带来一半内环,一半外环的问题。 -
得到关键点
对Image_Result使用get_region_points,注意严格区分正负极性,分开分析 -
给关键点赋予权重
Weight = Amp (点的梯度) / Dist (点到圆心和理论直径的偏差)
注意:权重还可以添加很多要素,比如圆周的灰度一致性,梯度方向一致性等,这里只是个例子 -
二值分割
过滤出最权重较为显著的点,构成contour,过滤掉circularity较低的结果 -
拟合成圆
fit_circle_contour_xld
-