上一专题《halcon学习拓展系列—弱边缘缺陷检测方法汇总之频域方法(一)》,该专题主要讲解频域检测边缘,本专栏主要讲空域边缘检测,总目录如下:
***************************弱边缘缺陷检测方法汇总之空域方法*******************************
一、算法实现
1、图像增强部分
1)对比度增强(emphasize)
2)照明度增强(illuminate)
3)直方图均衡化(equ_histo_image)
4)灰度线性变换(scale_image,scale_image_max)
5)灰度非线性指数变换(exp_image)
6)灰度非线性对数变换(log_image)
7)局部灰度范围统计(gray_range_rect)
8)局部灰度熵统计(entropy_image)
9)局部灰度值标准方差(deviation_image)
10)局部最大灰度值统计(gray_dilation_rect)
11)高通滤波(highpass_image)
12)sobel幅值边缘检测(sobel_amp)
13)sobel幅值和方向边缘检测(sobel_dir)
2、边缘/区域分割部分
1)自动阈值—由直方图确定的阈值分割图像(auto_threshold)
2)动态阈值—由局部动态阈值分割(dyn_threshold)
3)滞后阈值分割(hysteresis_threshold)
4)骨架分割(skeleton)
5)二阶导数(lines_gauss)
二、总结
written by guke
****************************************************************************************
下面开始...
一、基础知识
1、图像增强部分
1)对比度增强(emphasize)
emphasize(Image : ImageEmphasize : MaskWidth, MaskHeight, Factor : ) 增强图像对比度
和频域对比度增强原理类似:
res := round((orig - mean) * Factor) + orig
测试代码:
read_image (Image, 'surface_scratch')
get_image_size (Image, Width, Height)
emphasize (Image, ImageEmphasize, 7, 7, 1.5)
测试结果:
2)照明度增强(illuminate)
illuminate(Image : ImageIlluminate : MaskWidth, MaskHeight, Factor : ) 照明度增强
** 光照增强公式
** 图像中非常暗的部分被“照亮”得更强烈,非常亮的部分被“暗化”
new = round ( (val - mean) * Factor + orig )
测试代码:
**光照增强
read_image (Image, 'surface_scratch')
illuminate (Image, ImageIlluminate, 101, 101, 0.7)
测试效果:
3)直方图均衡化(equ_histo_image)
equ_histo_image(Image : ImageEquHisto : : ) 直方图均衡化
测试代码:
**直方图均衡化
read_image (Image, 'surface_scratch')
equ_histo_image (Image, ImageEquHisto)
测试效果:
显然,直方图均衡化不太适合刮伤、划伤、毛丝和异物等检测
4)线性灰度变换(scale_image,scale_image_max)
scale_image(Image : ImageScaled : Mult, Add : ) 灰度线性变换
** scale_image公式
g' := g * Mult + Add
测试代码:
**线性灰度变换
read_image (Image, 'surface_scratch')
scale_image (Image, ImageScaled, 1, 20)
scale_image_max (Image, ImageScaleMax)
测试效果:
5)非线性灰度指数变换(exp_image)
exp_image(Image : ExpImage : Base : ) 灰度指数变换
测试代码:
**exp图像增强
read_image (Image, 'surface_scratch')
exp_image (Image, ExpImage, 1.1)
测试效果:
显然,图像灰度指数变换太适合刮伤、划伤、毛丝和异物等检测,更适合灰阶较多的图像
6)非线性灰度对数变换(log_image)
log_image(Image : LogImage : Base : ) 灰度对数变换
测试代码:
**log图像增强
read_image (Image, 'surface_scratch')
log_image (Image, LogImage, 'e')
测试效果:
7)局部灰度范围统计(gray_range_rect)
gray_range_rect(Image : ImageResult : MaskHeight, MaskWidth : ) 局部矩形内灰度范围统计
测试代码:
**局部灰度统计
read_image (Image, 'surface_scratch')
gray_range_rect (LogImage, ImageResult, 11, 11)
测试效果:
8)局部灰度熵统计(entropy_image)
entropy_image(Image : ImageEntropy : Width, Height : ) 局部灰度熵统计
测试代码:
**局部灰度熵统计
read_image (Image, 'surface_scratch')
entropy_image (Image, ImageEntropy, 9, 9)
测试效果:
9)局部灰度值标准方差(deviation_image)
deviation_image(Image : ImageDeviation : Width, Height : )
测试代码:
**局部灰度标准方差统计
read_image (Image, 'surface_scratch')
deviation_image (Image, ImageDeviation,7, 7)
测试效果:
10)局部最大灰度值统计(gray_dilation_rect)
gray_dilation_rect(Image : ImageMax : MaskHeight, MaskWidth : )
测试代码:
**局部灰度最大值统计
read_image (Image, 'surface_scratch')
gray_dilation_rect (Image, ImageMax, 11, 11)
测试效果:
显然,局部最大灰度值统计不适合检测黑对象,我们将图像反转一下:
测试代码:
**局部灰度最大值统计
read_image (Image, 'surface_scratch')
invert_image (Image, ImageInvert)
gray_dilation_rect (ImageInvert, ImageMax, 11, 11)
测试效果:
11)高通滤波(highpass_image)
highpass_image(Image : Highpass : Width, Height : )
测试代码:
**高通滤波
read_image (Image, 'surface_scratch')
highpass_image (Image, Highpass, 15, 15)
测试效果:
12)sobel幅值边缘检测(sobel_amp)
sobel_amp(Image : EdgeAmplitude : FilterType, Size : )
测试代码:
**sobel_amp
read_image (Image, 'surface_scratch')
mean_image (Image, ImageMean, 1, 1)
illuminate (ImageMean, ImageIlluminate, 101, 101, 0.7)
emphasize (ImageIlluminate, ImageEmphasize, 11, 11, 1.5)
sobel_amp (ImageEmphasize, EdgeAmplitude, 'sum_abs', 3)
测试效果:
13)sobel幅值和方向边缘检测(sobel_dir)
sobel_dir(Image : EdgeAmplitude, EdgeDirection : FilterType, Size : )
测试代码:
**sobel_dir
read_image (Image, 'surface_scratch')
mean_image (Image, ImageMean, 1, 1)
illuminate (ImageMean, ImageIlluminate, 101, 101, 0.7)
emphasize (ImageIlluminate, ImageEmphasize, 11, 11, 1.5)
sobel_dir (Image, EdgeAmplitude, EdgeDirection, 'sum_abs', 3)
nonmax_suppression_dir (EdgeAmplitude, EdgeDirection, ImageResult, 'nms')
dev_display (ImageResult)
测试效果:
效果不好啊,sobel_dir对弱边缘效果一般!
2、边缘/区域分割部分
为了比较分析,我们统一用illumination和emphasize的结果ImageEmphasize
1)自动阈值—由直方图确定的阈值分割图像(auto_threshold)
auto_threshold(Image : Regions : Sigma : )
测试代码:
**auto_threshold
read_image (Image, 'surface_scratch')
mean_image (Image, ImageMean, 1, 1)
illuminate (ImageMean, ImageIlluminate, 101, 101, 0.7)
emphasize (ImageIlluminate, ImageEmphasize, 11, 11, 1.5)
auto_threshold (ImageEmphasize, Regions, 0.5)
intensity (Regions, ImageEmphasize, Mean, Deviation)
intensity (ImageEmphasize, ImageEmphasize, MeanWhole, Deviation1)
tuple_sort_index (Mean, Indices)
tuple_less_equal_elem (Mean, MeanWhole, Lesseq)
tuple_find (Lesseq, 1, IndicesLess)
select_obj (Regions, ObjectSelected, Indices[IndicesLess]+1)
closing_circle (ObjectSelected, RegionClosing1, 6)
connection (RegionClosing1, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ['area','max_diameter'], 'and', [1,1], [99999,99999999])
union1 (SelectedRegions, RegionUnion)
dev_display (ImageEmphasize)
dev_display (RegionUnion)
测试效果:
分割效果太散了!不建议利用auto_threshold检测比较细的线状缺陷特征,优于用于区域块状的Blob分析,一是比较灵活,二是稳定性较好
2)动态阈值—由局部动态阈值分割(dyn_threshold)
dyn_threshold(OrigImage, ThresholdImage : RegionDynThresh : Offset, LightDark : ) 动态阈值
测试代码:
**dyn_threshold
read_image (Image, 'surface_scratch')
mean_image (Image, ImageMean, 1, 1)
illuminate (ImageMean, ImageIlluminate, 101, 101, 0.7)
emphasize (ImageIlluminate, ImageEmphasize, 11, 11, 1.5)
mean_image (ImageEmphasize, ImageMean1, 2, 2)
mean_image (ImageEmphasize, ImageMean2, 12, 12)
dyn_threshold (ImageMean1, ImageMean2, RegionDynThresh, 10, 'dark')
closing_circle (RegionDynThresh, RegionClosing1, 3)
connection (RegionClosing1, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ['area','max_diameter'], 'and', [25,30], [99999,99999999])
dev_display (ImageEmphasize)
dev_display (SelectedRegions)
测试效果:
3)滞后阈值分割(hysteresis_threshold)
hysteresis_threshold(Image : RegionHysteresis : Low, High, MaxLength : ) 滞后阈值
测试代码:
**hysteresis_threshold
**illumination和emphasize增强后图像
read_image (Image, 'surface_scratch')
mean_image (Image, ImageMean, 1, 1)
illuminate (ImageMean, ImageIlluminate, 101, 101, 0.7)
emphasize (ImageIlluminate, ImageEmphasize, 11, 11, 1.5)
hysteresis_threshold (EdgeAmplitude, RegionHysteresis, 25, 55, 10)
connection (RegionHysteresis, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ['area','max_diameter'], 'and', [10,15], [99999,99999999])
dev_display (ImageEmphasize)
dev_display (SelectedRegions)
**sobel_amp增强后图像
read_image (Image, 'surface_scratch')
mean_image (Image, ImageMean, 1, 1)
illuminate (ImageMean, ImageIlluminate, 101, 101, 0.7)
emphasize (ImageIlluminate, ImageEmphasize, 11, 11, 1.5)
sobel_amp (ImageEmphasize, EdgeAmplitude, 'sum_abs', 3)
hysteresis_threshold (EdgeAmplitude, RegionHysteresis, 25, 55, 10)
connection (RegionClosing1, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ['area','max_diameter'], 'and', [10,15], [99999,99999999])
dev_display (EdgeAmplitude)
dev_display (SelectedRegions)
测试效果:
4)骨架分割(skeleton)
skeleton(Region : Skeleton : : )
测试代码:
**skeleton
read_image (Image, 'surface_scratch')
mean_image (Image, ImageMean, 1, 1)
illuminate (ImageMean, ImageIlluminate, 101, 101, 0.7)
emphasize (ImageIlluminate, ImageEmphasize, 11, 11, 1.5)
threshold (ImageEmphasize, Region, 0, 115)
closing_circle (Region, RegionClosing1, 3)
connection (RegionClosing1, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ['area','max_diameter'], 'and', [10,10], [99999,99999999])
skeleton (SelectedRegions, Skeleton)
dev_display (ImageEmphasize)
dev_display (Skeleton)
测试效果:
skeleton是对分割好的region进行骨架提取,前提是分割好,所以这里简单用了threshold,与其他分割效果无法进行对比,这里知道skeleton能够对Reigon进行骨架提取即可(像素级)
5)二阶导数(lines_gauss)
测试代码:
**lines_gauss
read_image (Image, 'surface_scratch')
mean_image (Image, ImageMean, 1, 1)
illuminate (ImageMean, ImageIlluminate, 101, 101, 0.7)
emphasize (ImageIlluminate, ImageEmphasize, 11, 11, 1.5)
lines_gauss (ImageEmphasize, Lines, 1.5, 3, 8, 'dark', 'true', 'bar-shaped', 'true')
union_adjacent_contours_xld (Lines, UnionContours, 10, 1, 'attr_keep')
select_contours_xld (UnionContours, SelectedContours, 'contour_length', 50, 2000, -0.5, 0.5)
dev_display (ImageEmphasize)
dev_display (SelectedContours)
测试效果:
我们修改一下参数:
**lines_gauss
read_image (Image, 'surface_scratch')
mean_image (Image, ImageMean, 1, 1)
illuminate (ImageMean, ImageIlluminate, 101, 101, 0.7)
emphasize (ImageIlluminate, ImageEmphasize, 11, 11, 1.5)
lines_gauss (ImageEmphasize, Lines, 1.5, 2, 5, 'dark', 'true', 'bar-shaped', 'true')
union_adjacent_contours_xld (Lines, UnionContours, 10, 1, 'attr_keep')
select_contours_xld (UnionContours, SelectedContours, 'contour_length', 30, 2000, -0.5, 0.5)
dev_display (ImageEmphasize)
dev_display (SelectedContours)
效果很好!
二、总结
1、不管频域还是空域,需要根据缺陷形态特征和灰阶特征,来选择合适的图像增强方式,然后选择合适的缺陷分割算法
2、图像增强对比分析总结:
1)对于较细划痕:频域对干扰的过滤效果要优于空域
2)频域正弦带通滤波器和空域illumination&&emphasize滤波,要优于空域sobel滤波,如下图:
1频域正弦带通滤波器滤波 2-空域sobel滤波 3-空域illumination和emphasize滤波
有兴趣的同学可以尝试一下,对频域图像增强后的图片进行缺陷分割,这个不再添加,测试效果也很好
3、分割对比分析总结:空域的dyn_threshold和lines_gauss对弱边缘由较好的分割效果,lines_gauss效果更为突出
4、还有其他好的方法,后面继续添加