机器视觉中缺陷检测分为一下几种:
前一篇总结了频域与空间域的结合使用,本篇就光度立体的缺陷检测做一个总结。
在工业领域,表面检测是一个非常广泛的应用领域。在halcon中,使用增强的光度立体视觉方法,三维表面检测被加强。利用阴影可方便快速的检测物体表面的缺口或凹痕。 使用光度立体视觉方法可在复杂图像中轻松找到表面缺陷 。
1️⃣光度立体法的典型应用:
光度立体法的典型应用是检测物体表面微小变化,例如,受打光方向影响的缺陷。比如非平面的打印检测(个人理解:普通打光方式受光线影响特征成像不理想,可以通过光度立体法检测)。值得注意的是:光度立体法不适用于绝对高度的重建,也就是说,它不能替代传统的3D重建算法,如对焦测距和激光三角测量。
2️⃣光度立体法的局限性:
光度立体法基于Woodham算法。因此:
此外,物体必须具有朗伯反射特性,即它必须以漫反射的方式反射入射光。有镜面反射的物体或者区域(镜子或者光滑的表面)不能使用此方法,会得到一个错误的结果。
3️⃣采集图像设置:
带有远心镜头的相机必须与被测物体表面垂直安装,在采集多幅图像时,一定要保证相机和物体不被移动。相反,对于采集至少三张的灰度图像,其每次取像的照明方向必须改变(相对于相机)。
光度立体核心算子:(注意:光度立体法需要使用灰度图,而且至少需要3张图像,最好是4张)
photometric_stereo (Images ,HeightField, Gradient, Albedo : Slant, Tilt, ResultType, ReconstructionMethod, GenParamName, GenParamValue )
参数列表:
Images(in)//输入灰度图像(4张)
HeightField(out)//返回重建高度信息图
Gradient(out)//返回表面的梯度信息图
Albedo(out)//返回表面的反射率信息图
Slant//光源光线与摄像机光轴的夹角(下面有示意图)
Tilt//光源光线投影与被测物主轴的夹角
ResultType//请求结果类型(高度场/梯度场/反射率)
ReconstructionMethod//重建方法类型
GenParamName//一般参数名称
GenParamValue// 一般参数设置
photometric_stereo 函数详解:
光度立体法可以根据二维纹理信息提取出三维模型(实际只有2.5维)。photometric_stereo算子至少需要三张图(最好四张图),这些图是在相机和物体相对位置不变条件下(Note),通过不同方向打光获取的。
物体的三维模型主要是根据三维表面的局部梯度计算提取的。三维表面的局部梯度信息可以进一步整合获得高度信息图,灰度值与高度值一一对应。二维纹理被称为反照率,它对应于物体表面局部光吸收和反射特性,被遮挡的部分没有此特性。
1️⃣光照方向说明:对于采集的多张图像中的每一幅图,照明方向必须指定Slants和Tilts两个参数角度,其描述了相对于当前场景的光照角度。为了更好的理解这两个参数含义,我们假定光源射出的光束是平行光,镜头是远心镜头,相机垂直于物体表面。
Slant参数:
Tilt参数:
这个角度是以图像为准的,比如光从图像右侧打过来,角度就是0°,从上面打过来,角度是90°,从左面打过来,角度是180°,下边打过来是270°。
正常情况下一般都是至少采集三张不同方向打光的图。但对于一些特殊的产品,因为阴影的原因,三个方向打光不能很好的表征缺陷特征,造成重建的图像特征不明显,这个时候就需要在原来基础上增加打光方向,避免死角。随着打光方向增加采集图像也跟着增加,那么算法处理时间也变长。根据经验:
2️⃣输入图像:
输入图像是一个图像数组,其中每张图像都是在不同打光方向下采集的。如果采集的是多通道图像,可以通过算子 image_to_channels转换成单通道图像,采集的多张图像可以通过算子concat_obj合并成一个数组图像。
光度立体法依托于对光度信息的评估,也就是图像中的灰度值。因此,图像质量的好坏决定了结果。要保证好的图像质量,首先要确保相机采集的图像具有线性特征,可以使用算子radiometric_self_calibration确认相机特性,如果相机采集的图像是非线性的,可以利用算子 lut_trans 矫正灰度信息。此外,如果需要更高精度,可以从以下两点着手:(1)、使用相机的全部动态范围;(2)、使用高于8位深度的图像(灰度范围0-65535而不是0-255类型的图像)
3️⃣输出图像:算子输出重建后的梯度、反射率、以及高度场图像。1、梯度图(矢量场)是根据对图像求偏导数获取,它可以作为算子reconstruct_height_field_from_gradient的输入。为了视觉观看更直观,将表面梯度进行归一化处理。因此ResultType类型需要设置成“normalized_gradient”,而不是“gradient”。如果ResultType设置成默认模式“all”,处理方式是“gradient”,而不是“normalized_gradient”,所以在参数设置时要根据需要设置。2、Albedo 图像描述的是物体的反射率,其值介于0(黑色)-1(白色)之间。因此,Albedo反应了物体表面特性。比如对于印刷表面表面,Albedo反应的是表面明暗程度的特性。
3,HeightField 图像中每个像素值以某种关系与其高度一一对应。
4️⃣ResultType参数:
默认情况下,ResultType设置成“all”。假如在应用中仅仅需要部分结果,可以通过数组的形式在‘gradient’, ‘albedo’, and ‘height_field’中选择设置ResultType参数,例如ResultType := [‘gradient’,‘albedo’]。对于特定的表面检测应用,如果只需要‘gradient’, ‘albedo’,那么将ResultType设置成‘gradient’, 'albedo’不进行三维重构(‘height_field’),处理速度将会有效提升。
5️⃣photometric_stereo 函数:
photometric_stereo算子首先会计算出梯度矢量场,如果需要高度场,光度立体法内部会采用reconstruct_height_field_from_gradient算子进行整合处理,通过 ReconstructionMethod, GenParamName, and GenParamValue这三个参数控制效果。如果参数ResultType参数中没有设置‘height_field’,可以忽略这三个参数。
derivate_vector_field(VectorField ,Result , Sigma, Component )
参数列表:
VectorField(in)// 梯度场图像
Result(out) // 返回平均曲率场图像
Sigma(in) // 高斯系数
Component(in) //组件计算
derivate_vector_field函数详解:
将向量场的分量与高斯函数的导数进行卷积,并计算由此得到的各种特征。在光度立体项目中,专门用于处理photometric_stereo 函数输出的重建后的梯度、反射率、以及高度场图像。
1️⃣Sigma参数:
如果在Sigma中传递一个值,那么在列和行方向上的平滑量是相同的。
如果在Sigma中传递两个值,第一个值指定列方向的平滑量,第二个值指定行方向的平滑量。
2️⃣Component参数:(有四个值可选,后两个值专用于光度立体)
halcon实例分析
在实际应用中,有些产品缺陷对光源角度有要求,且方向不固定(比如:带方向的缺陷,需要多角度打光才能凸显缺陷的产品)那么就可以考虑光度立体法。
利用反射率图像和梯度图像检测皮革表面缺陷
下面是两种皮革表面拍摄图像:
dev_close_window ()
dev_open_window (0, 0, 640, 480, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
* Part 1利用反射率图像检测皮革表面缺陷
read_image (Images, 'photometric_stereo/leather_1_0' + [1:4])
write_image (Images, 'tiff', 0, 'D:/1.tiff')
** 展示不同方向光源成像图像
for I := 1 to 4 by 1
Message := 'Sample 1: Acquire image ' + I + ' of 4'
select_obj (Images, ObjectSelected, I)
dev_display (ObjectSelected)
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
wait_seconds (0.5)
endfor
* 应用光度立体法生成的反射率图进行缺陷检测
Tilts := [6.1,95.0,-176.1,-86.8]
Slants := [41.4,42.6,41.7,40.9]
ResultType := ['gradient','albedo']
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, ResultType, 'poisson', [], [])
* 显示反射率图
dev_display (Albedo)
*检测缺陷
var_threshold (Albedo, Region, 15, 15, 0.4, 0.4, 'light')
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 10, 99999)
union1 (SelectedRegions, RegionUnion)
closing_circle (RegionUnion, RegionClosing, 3.5)
connection (RegionClosing, Defects)
area_center (Defects, Area, Row, Column)
gen_circle (Circle, Row, Column, gen_tuple_const(|Row|,sqrt(Area) + 30))
*显示缺陷
dev_display (Albedo)
dev_set_color ('red')
dev_set_draw ('margin')
dev_set_line_width (4)
dev_display (Circle)
* Part 2 利用梯度图像检测皮革表面缺陷
read_image (Images, 'photometric_stereo/leather_2_0' + [1:4])
for I := 1 to 4 by 1
Message := 'Sample 2: Acquire image ' + I + ' of 4'
select_obj (Images, ObjectSelected, I)
dev_display (ObjectSelected)
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
wait_seconds (0.5)
endfor
* 应用光度立体法生成的反射率图
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, ResultType, 'poisson', [], [])
*对反射率图二值化(发现无法二值化)
threshold (Albedo, Region1, 128, 255)
* 显示反射率图
dev_display (Albedo)
derivate_vector_field (Gradient, Curl, 1, 'curl')
derivate_gauss (Curl, CurlGradient, 1, 'gradient')
* 显示梯度图
dev_display (CurlGradient)
Message := 'Changes in the gradient curl'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 用梯度图寻找缺陷
threshold (CurlGradient, Region, 0, 0.01)
rank_region (Region, RegionCount, 10, 10, 30)//归类区域
connection (RegionCount, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 2000, 99999)
union1 (SelectedRegions, RegionUnion)
rank_region (RegionUnion, RegionCount1, 25, 25, 170)
connection (RegionCount1, NoTextured)
* 显示
dev_display (Albedo)
dev_set_draw ('margin')
dev_set_color ('red')
dev_set_line_width (3)
dev_display (NoTextured)
disp_message (WindowHandle, 'Non-textured areas on leather', 'window', 12, 12, 'black', 'true')
stop ()
Part1:反射率图找缺陷 Part2:梯度图找缺陷
思考:Part1利用反射率图检测皮革表面缺陷,而Part2却利用梯度信息图检测缺陷,Why?
[分析]
仔细观察不难发现,Part1中的缺陷区域(左图)展现的都是高亮特性。缺陷特征比背景区域具有较高的反光特性,所以反射率图能很好的凸显缺陷特征,所以用反射率图检测缺陷。
如果用梯度图去检测Part1中的缺陷会怎样呢?如下图:(可以看出缺陷和纹理对比度很差,所以不能用梯度信息图检测Part1中的缺陷。)
对于Part2,可以发现,缺陷为细条状,是比较明显的划痕因此利用梯度信息图检测这种缺陷是一种不错的选择。
该例程的Tilts参数构建:
这个例子展示的是利用光度立体法检测洗发水瓶的标签缺陷:
dev_close_window ()
dev_update_off ()
dev_open_window (0, 0, 640, 512, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
*读入4幅由四个不同光照方向所成的图像
read_image (Images, 'photometric_stereo/shampoo_label_0' + [1:4])
for I := 1 to 4 by 1
Message := 'Acquire image ' + I + ' of 4'
select_obj (Images, ObjectSelected, I)
dev_display (ObjectSelected)
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
wait_seconds (0.5)
endfor
*
*设置参数,用光度立体法生成梯度以及反射率图
Tilts := [6.1,95.0,-176.1,-86.8]
Slants := [41.4,42.6,41.7,40.9]
ResultType := ['gradient','albedo']
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, ResultType, 'poisson', [], [])
* 显示反射率图
dev_display (Albedo)
stop ()
* 对梯度图像进行高斯导数卷积操作
derivate_vector_field (Gradient, MeanCurvature, 1.0, 'mean_curvature')
*
*缺陷检测
threshold (MeanCurvature, Region, -10, -0.07)
opening_circle (Region, RegionOpening, 1)
connection (RegionOpening, ConnectedRegions)
select_shape (ConnectedRegions, Defects, 'area', 'and', 50, 99999)
shape_trans (Defects, Circle, 'outer_circle')
stop ()
*显示
dev_set_draw ('margin')
dev_set_color ('red')
dev_display (Albedo)
dev_display (Circle)
disp_message (WindowHandle, 'Defect in albedo image', 'window', 12, 12, 'black', 'true')
思路如下:
dev_close_window ()
dev_update_off ()
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
stop ()
*
* 读入4张各角度图像
read_image (Images, 'photometric_stereo/blister_back_0' + [1:4])
for I := 1 to 4 by 1
Message := 'Acquire image ' + I + ' of 4'
select_obj (Images, ObjectSelected, I)
dev_display (ObjectSelected)
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
wait_seconds (0.5)
endfor
*
*用光度立体法得到梯度图和反射率图
Tilts := [6.1,95.0,-176.1,-86.8]
Slants := [41.4,42.6,41.7,40.9]
ResultType := ['gradient','albedo']
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, ResultType, 'poisson', [], [])
*
*显示反射率图
dev_display (Albedo)
stop ()
*
* 使用之前得到的梯度图,计算表面的高斯曲率,得到高斯曲率图像(在曲率图像上能更容易的进行检测)
derivate_vector_field (Gradient, GaussCurvature, 1, 'gauss_curvature')
* 对高斯曲率图像进行预处理和Blob分析,从而得到缺陷区域
*图像分割(区域生长)
regiongrowing (GaussCurvature, Regions, 1, 1, 0.001, 250)
select_shape (Regions, TabletRegions, ['width','height'], 'and', [150,150], [200,200])
shape_trans (TabletRegions, TabletRegions, 'convex')
union1 (TabletRegions, TabletRegions)
erosion_circle (TabletRegions, TabletRegions, 3.5)
* Search for defects inside the tablet areas
reduce_domain (GaussCurvature, TabletRegions, ImageReduced)
abs_image (ImageReduced, ImageAbs)
threshold (ImageAbs, Region, 0.03, 255)
closing_circle (Region, RegionClosing, 10.5)
connection (RegionClosing, ConnectedRegions)
select_shape (ConnectedRegions, Defects, 'area', 'and', 10, 99999)
area_center (Defects, Area, Row, Column)
gen_circle (Circle, Row, Column, gen_tuple_const(|Row|,20.5))
* Display the defects in curvature image
dev_set_draw ('margin')
dev_set_color ('red')
dev_set_line_width (2)
dev_display (GaussCurvature)
dev_display (Circle)
Message := 'The defect can easily be detected'
Message[1] := 'in the surface curvature image'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
stop ()
* Display the defects in the albedo image
dev_set_draw ('margin')
dev_set_color ('red')
dev_display (Albedo)
dev_display (Circle)
disp_message (WindowHandle, 'Defect in albedo image', 'window', 12, 12, 'black', 'true')
参考博文:(7条消息) Halcon 光度立体法(photometric_stereo)详解_ZiLiangQin的博客-CSDN博客_photometric stereo