原图来自Ihalcon论坛
中间有一条对比度不明显的垂直折痕
(图片来源:http://www.ihalcon.com/read-4226.html)
发此帖子的楼主已经给出解决方案,如下:
1. 设计一个滤波器
2. 用convol_image算子来增强特定方向的纹理
3. 再用Gray_Range_Rect做图像变换
4. 最终用线高斯提取目标折痕
我们沿着楼主的解决思路走一遍。
首先介绍下相关理论点:卷积、如何构造方向滤波器。
1
卷积
提到卷积,想起大学时被《信号与系统分析》支配的恐惧了。对于图像处理的卷积,首先需要构造一个滤波矩阵,即卷积核,并将卷积核翻转180°,然后对于图像的每一个像素点,计算它的邻域像素和翻转后卷积核的对应元素的乘积,再加起来,作为该像素位置的值,即完成了卷积。还有一种滤波方式为协相关,其核矩阵不需要绕中心点翻转180°,平时接触的卷积核大都是关于x轴和y轴对称的,所以卷积和协相关在这种情况下没什么区别。
对于整幅图像,采用滑动卷积核的策略,如下图。
经过滑动卷积后,图像大小会变小,为避免这种问题,需要进行边界填充,主要有以下几种方式。
2
方向滤波器
若需检测水平边缘,需要在竖直方向上进行梯度运算,若需检测垂直边缘,需要在水平方向进行梯度运算。所以在检测垂直线条时,所构造的滤波器能在水平方向构成梯度差分运算,如一维水平滤波器[-1,0,1],若要扩展成3*3矩阵形式,可构成Prewitt的水平梯度卷积核。
如果所要检测线条比较宽,可以将3*3的卷积核扩展成5*5,7*7等。
通常情况,线条边缘灰度值会成渐变规律的,将卷积模板更改如下
使用此模板计算时,会将一些灰度值均匀分布的地方全部置0,如果我们不想要只得到的线条的效果,还需要原来的灰度值保持不变,这就需要将卷积模板所有值,相加等于1。
如果需要考虑锚点(中心点)周围所有像素的影响,则需要将其8邻域像素要参与计算。
此时,计算出的像素灰度值会偏大,所有值相加不等于1,需要在模板前乘以对应权值。
至此,我们滤波器构造完毕,在进行试验之前,先了解下Halcon使用构造滤波器的格式,见帮助文档中的如下说明。
大致意思是,我们可生成一个文本文件,文件内容可按照如下格式描述滤波器,文件扩展名为:.fil。
另一种方法可以以元组Tuple的格式描述滤波器,格式为:[模板高,模板宽,模板权重倒数,模板元素行排列],程序中使用的是此格式。
当然,从水平滤波器,也可以联想到垂直滤波器,或者一些特定曲线滤波器。
3
使用Sobel水平滤波器检测折痕
在使用构造滤波器之前,先使用sobel滤波器进行处理,如果前人总结一些经典的先验知识,秉承着”拿来主义“,使用一些已知的、经典的方法,来解决一些未知的、陌生的问题,这种处理思路是极力推崇的。
Sobel算子的处理过程,是分别在水平和垂直方向对图像进行卷积,再讲二者结果结合求得没一点的梯度值。下图为Soble算子的水平、垂直滤波器。
读入图像,将Sobel水平滤波器转换为Halcon的Tuple形式。
filter1 :=[3,3,1,-1,0,1,-2,0,2,-1,0,1]
Sobel水平滤波器与图像卷积后如下图,可以看见一条比较长的竖直线条。
Sobel算子已经做了灰度变换,Gray_Range_Rect可以不再使用,也可以使用做灰度增强,Sobel检测程序无用到。
关于lines_gauss的参数是比较难调,尤其是高低阈值,此处使用算子calculate_lines_gauss_parameters基本可以实现自适应参数条件,只需要设置所检测线条最大宽度与对比即可。
MaxLineWidth := 4
Contrast := 30
calculate_lines_gauss_parameters (MaxLineWidth, [Contrast,0], Sigma, Low, High)
lines_gauss (ImageResult, Lines, Sigma, Low, High, 'light', 'true', 'parabolic', 'true')
select_contours_xld (Lines, SelectedContours, 'contour_length', 180, 250, -0.5, 0.5)
检测结果如下图
干扰线还是比较多的,使用特征筛选可以排除。
4
使用构造方向滤波器检测折痕
将构造滤波器转为halcon的Tuple形式
filter :=[5,5,5,-1,-5,1,5,1,-1,-5,1,5,1,-1,-5,1,5,1,-1,-5,1,5,1,-1,-5,1,5,1]
与原图卷积后
垂直线条明显被加强
使用Gray_Range_Rect做灰度变换
排除垂直纹理以外的干扰
增强对比度
使用线高斯提取目标
干扰线减少些
特征筛选,检测折痕
基于构造滤波器的折痕检测程序
read_image (Image1030179715f15e264af3b, 'C:/Users/SWD-AR02/Desktop/10_3017_9715f15e264af3b.png')
*构造滤波器
filter :=[5,5,5,-1,-5,1,5,1,-1,-5,1,5,1,-1,-5,1,5,1,-1,-5,1,5,1,-1,-5,1,5,1]
*图像卷积
convol_image (Image1030179715f15e264af3b, ImageResult, filter, 'mirrored')
*灰度变换
gray_range_rect (ImageResult, ImageResult1, 6, 6)
*线高斯提取目标
MaxLineWidth := 8
Contrast := 50
calculate_lines_gauss_parameters (MaxLineWidth, [Contrast,0], Sigma, Low, High)
lines_gauss (ImageResult1, Lines, Sigma, Low, High, 'light', 'true', 'parabolic', 'true')
*选取折痕
select_contours_xld (Lines, SelectedContours, 'contour_length', 180, 250, -0.5, 0.5)
*结果显示
gen_region_contour_xld (SelectedContours, Region, 'margin')
dilation_rectangle1 (Region, RegionDilation, 11, 1)
dev_set_draw ('margin')
dev_display (Image1030179715f15e264af3b)
dev_display (RegionDilation)
目前,使用sobel的水平滤波器和构造滤波器都能检测出折痕,但是只是针对此幅图像,对于实际项目当中,构造滤波器可以根据不同情况进行设计,柔性更强、鲁棒性更好,相反地,复杂度也会增加。
后续,我们在此帖楼主的解决方案的框架下,尝试另外两种方法,敬请期待。
后台回复“折痕”可获取原图以及源代码。