缺陷检测,halcon案例入门篇。
常见缺陷:
1.凸凹结构(包含小毛刺)。
2.内部污点,表面不平整,瑕疵,孔洞,破损,烫伤,油啧。
3.划痕。
处理方法:
凸点,使用低角度环形光,把背景打暗,凸点打白。
凹点,使用垂直光(可环形),把背景打亮,背景打暗。
【可使用条光对打】
曲面字体(凸出部),使用瓦装曲型光板,侧面以一定角度打入,可把字体打亮。
2. 算法处理
Blob分析+特征检测
Blob分析+特征+差分
频率+空间
光度立体法
特征训练(分类器,深度学习)
测量+拟合
3. halcon缺陷案例。
案例一:例程:blob分析——check_hazelnut_wafers.hdev(检查饼干)
简述:inspect quality of hazelnut wafers(检查饼干的质量)
//表面大面积破损
Blob+特征检测
案例三:例程:blob分析——inspect_bottle_mouth.hdev(检查瓶口)
简述:check bottle mouths for defects(检查瓶口是否有缺陷)
Blob+特征检测
案例四:例程:blob分析——novelty_detection_dyn_threshold.hdev
简述:inspect a web using dyn_threshold(使用dyn_阈值检查网络)
//用于对光照稳定,环境简单
代码:
dev_update_window (‘off’)
read_image (Image, ‘plastic_mesh/plastic_mesh_01’)
dev_close_window ()
get_image_size (Image, Width, Height)
dev_open_window_fit_image (Image, 0, 0, Width, Height, WindowHandle)
set_display_font (WindowHandle, 18, ‘mono’, ‘true’, ‘false’)
dev_set_draw (‘margin’)
dev_set_line_width (3)
for J := 1 to 14 by 1
read_image (Image, ‘plastic_mesh/plastic_mesh_’ + J$‘02’)
mean_image (Image, ImageMean, 49, 49)
//均值滤波,将灰度值拉到平滑
dyn_threshold (Image, ImageMean, RegionDynThresh, 5, ‘dark’)
//使用局部阈值分割图像,
// Image:输入图像。ImageMean:输入比较图像。RegionDynThresh:输出图像。5,:阀值。‘dark’:选择暗的部分
//建立一个对图像灰度值的检测。5:为阀值。将输入图像与比较图像进行运算,可以之间选择出输入图像的亮暗部分。‘dark’:为获取暗的部分。‘light’:为选择亮的部分。Lightdark:为选择原图部分
//常用于均值滤波后
connection (RegionDynThresh, ConnectedRegions)
//特征提取
select_shape (ConnectedRegions, ErrorRegions, ‘area’, ‘and’, 500, 99999)
count_obj (ErrorRegions, NumErrors)
dev_display (Image)
dev_set_color (‘red’)
dev_display (ErrorRegions)
if (NumErrors > 0)
disp_message (WindowHandle, ‘Mesh not OK’, ‘window’, 24, 12, ‘black’, ‘true’)
else
disp_message (WindowHandle, ‘Mesh OK’, ‘window’, 24, 12, ‘black’, ‘true’)
endif
if (J < 14)
disp_continue_message (WindowHandle, ‘black’, ‘true’)
stop ()
endif
endfor
案例五:例程:blob分析——novelty_detection_dyn_threshold.hdev
简述:inspect a web using dyn_threshold(使用dyn_阈值检查网络)
//用于pcb的线路细小断裂的检测
代码
*blob+差分+特征
read_image (Image, ‘pcb’)
dev_close_window ()
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width, Height, ‘black’, WindowHandle)
dev_display (Image)
//灰度形态学
//灰度开运算,腐蚀,暗的像素点增加
gray_opening_shape (Image, ImageOpening, 7, 7, ‘octagon’)
//灰度闭运算,膨胀,亮的像素点增加
gray_closing_shape (Image, ImageClosing, 7, 7, ‘octagon’)
//差分
dyn_threshold (ImageOpening, ImageClosing, RegionDynThresh, 75, ‘not_equal’)
dev_display (Image)
dev_set_color (‘red’)
dev_set_draw (‘margin’)
dev_display (RegionDynThresh)
案例六:例程:blob分析——check_blister.hdev(检测一板药片)
//对一板药片进行检测是否有缺陷。
代码
dev_close_window ()
dev_update_off ()
read_image (ImageOrig, ‘blister/blister_reference’)
dev_open_window_fit_image (ImageOrig, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 14, ‘mono’, ‘true’, ‘false’)
dev_set_draw (‘margin’)
dev_set_line_width (3)
access_channel (ImageOrig, Image1, 1)
//与灰度转化效果相当
//访问多通道图像的一个通道。即为对RGB3通道的一个通道进行提取,相当于转化为灰度图像
threshold (Image1, Region, 90, 255)
//二值化
shape_trans (Region, Blister, ‘convex’)
orientation_region (Blister, Phi)
//检测角度
area_center (Blister, Area1, Row, Column)
vector_angle_to_rigid (Row, Column, Phi, Row, Column, 0, HomMat2D)
affine_trans_image (ImageOrig, Image2, HomMat2D, ‘constant’, ‘false’)
//仿射变化
gen_empty_obj (Chambers)
//计数
for I := 0 to 4 by 1
Row := 88 + I * 70
for J := 0 to 2 by 1
Column := 163 + J * 150
gen_rectangle2 (Rectangle, Row, Column, 0, 64, 30)
concat_obj (Chambers, Rectangle, Chambers)
//对药片的单个区域进行显示绘制图像和计数
//将单个药片提取出来的图像放在Chambers数组中,方便后续的去交集
endfor
endfor
affine_trans_region (Blister, Blister, HomMat2D, ‘nearest_neighbor’)
//对区域进行仿射变化
difference (Blister, Chambers, Pattern)
//求差值。将仿射变换的区域与药片的区域进行求取差值,用于提取药片区域
union1 (Chambers, ChambersUnion)
//形成一个连通域
orientation_region (Blister, PhiRef)
//将转正的区域进行求取角度
PhiRef := rad(180) + PhiRef
area_center (Blister, Area2, RowRef, ColumnRef)
//求取坐标
//定位结束
//缺陷检测(在标准位置寻找药片与原有的区域进行求交集)
Count := 6
for Index := 1 to Count by 1
read_image (Image, ‘blister/blister_’ + Index$‘02’)
threshold (Image, Region, 90, 255)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ‘area’, ‘and’, 5000, 9999999)
shape_trans (SelectedRegions, RegionTrans, ‘convex’)
orientation_region (RegionTrans, Phi)
area_center (RegionTrans, Area3, Row, Column)
vector_angle_to_rigid (Row, Column, Phi, RowRef, ColumnRef, PhiRef, HomMat2D)
affine_trans_image (Image, ImageAffineTrans, HomMat2D, ‘constant’, ‘false’)
//找到图像所在的区域,方便对图像进行裁剪
//药片分割
reduce_domain (ImageAffineTrans, ChambersUnion, ImageReduced)
//对图像的药片区域进行裁剪
decompose3 (ImageReduced, ImageR, ImageG, ImageB)
//hsv转化
var_threshold (ImageB, Region, 7, 7, 0.2, 2, ‘dark’)
//对v进行二值化
connection (Region, ConnectedRegions0)
//断开
closing_rectangle1 (ConnectedRegions0, ConnectedRegions, 3, 3)
//闭运算
fill_up (ConnectedRegions, RegionFillUp)
//填充
select_shape (RegionFillUp, SelectedRegions, ‘area’, ‘and’, 1000, 99999)
opening_circle (SelectedRegions, RegionOpening, 4.5)
connection (RegionOpening, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ‘area’, ‘and’, 1000, 99999)
shape_trans (SelectedRegions, Pills, ‘convex’)
*
* Classify segmentation results and display statistics
count_obj (Chambers, Number)
gen_empty_obj (WrongPill)
gen_empty_obj (MissingPill)
//创建2个空的计数数组
for I := 1 to Number by 1
select_obj (Chambers, Chamber, I)
intersection (Chamber, Pills, Pill)
//将药片和药片所在的区域进行取交集
area_center (Pill, Area, Row1, Column1)
if (Area > 0)
min_max_gray (Pill, ImageB, 0, Min, Max, Range)
//求取最小最大灰度值
if (Area < 3800 or Min < 60)
concat_obj (WrongPill, Pill, WrongPill)
endif
else
concat_obj (MissingPill, Chamber, MissingPill)
endif
endfor
*
dev_clear_window ()
dev_display (ImageAffineTrans)
dev_set_color (‘forest green’)
count_obj (Pills, NumberP)
count_obj (WrongPill, NumberWP)
count_obj (MissingPill, NumberMP)
dev_display (Pills)
if (NumberMP > 0 or NumberWP > 0)
disp_message (WindowHandle, ‘Not OK’, ‘window’, 12, 12 + 600, ‘red’, ‘true’)
else
disp_message (WindowHandle, ‘OK’, ‘window’, 12, 12 + 600, ‘forest green’, ‘true’)
endif
*
Message := '# Correct pills: ’ + (NumberP - NumberWP)
Message[1] := '# Wrong pills : ’ + NumberWP
Message[2] := '# Missing pills: ’ + NumberMP
*
Colors := gen_tuple_const(3,‘black’)
if (NumberWP > 0)
Colors[1] := ‘red’
endif
if (NumberMP > 0)
Colors[2] := ‘red’
endif
disp_message (WindowHandle, Message, ‘window’, 12, 12, Colors, ‘true’)
dev_set_color (‘red’)
dev_display (WrongPill)
dev_display (MissingPill)
if (Index < Count)
disp_continue_message (WindowHandle, ‘black’, ‘true’)
endif
stop ()
endfor
案例七:例程:模板匹配(基于相关性)——measure_fill_level.hdev(检测液体液面)
//对瓶装液体进行检测是否有过多或者过少。
代码:
//先进行定位,然后设定一个固定高度,对高度继续测量
//采集图像
dev_close_window ()
dev_update_off ()
read_image (Image, ‘ampoules/ampoules_01’)
get_image_size (Image, Width, Height)
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_set_line_width (2)
dev_set_draw (‘margin’)
set_display_font (WindowHandle, 16, ‘mono’, ‘true’, ‘false’)
//模板匹配
//抠图
gen_rectangle1 (Rectangle, 230, 280, 317, 330)
reduce_domain (Image, Rectangle, ImageModel)
create_shape_model (ImageModel, ‘auto’, 0, 0, ‘auto’, ‘auto’, ‘use_polarity’, ‘auto’, ‘auto’, ModelID)
//创建模板
gen_measure_rectangle2 (0, 0, rad(90), 75, 20, Width, Height, ‘bilinear’, MeasureHandle)
//形成测量矩形
Tolerance := 15
NumImages := 8
for Index := 1 to NumImages by 1
read_image (Image, ‘ampoules/ampoules_’ + Index$’.2d’)
ColumnEdges := []
FillLevelHeight := []
//定义数组
find_shape_model (Image, ModelID, 0, 0, 0.7, 0, 0.1, ‘least_squares’, 0, 0.9, Row, Column, Angle, Score)
//找到模板坐标
MeanRow := mean(Row)
//对行坐标取均值
RefLevel := MeanRow - 160
* Display tolerance area
dev_display (Image)
dev_set_line_width (1)
dev_set_color (‘white’)
gen_rectangle2 (AcceptLevel, RefLevel, mean(Column), 0, 30 + (max(Column) - min(Column)) / 2, Tolerance)
//形成参考矩形
dev_display (AcceptLevel)
dev_set_line_width (2)
Errors := 0
for Idx := 0 to |Score| - 1 by 1
translate_measure (MeasureHandle, MeanRow - 135, Column[Idx])
//测量矩形平行
measure_pos (Image, MeasureHandle, 2, 7, ‘all’, ‘first’, RowEdge, ColumnEdge, Amplitude, Distance)
//找到测量边
//对液面进行液面的边缘和参考线继续相减大于或者小于一定值用于检测是否错误。
FillLevelHeight := [FillLevelHeight,RowEdge]
ColumnEdges := [ColumnEdges,ColumnEdge]
gen_cross_contour_xld (Cross, RowEdge, ColumnEdge, 15, 0)
//形成x标记
gen_rectangle2 (FillLevel, RowEdge, ColumnEdge, 0, 28, 20)
//形成矩形
if (abs(FillLevelHeight[Idx] - RefLevel) >= Tolerance)
gen_rectangle2 (ChamberSingle, MeanRow - 133, Column[Idx], 0, 35, 90)
gen_cross_contour_xld (Cross, FillLevelHeight[Idx], ColumnEdges[Idx], 15, 0)
gen_rectangle2 (FillLevel, FillLevelHeight[Idx], ColumnEdges[Idx], 0, 28, 20)
//绘制错误的区域
Errors := Errors + 1
dev_set_color (‘red’)
dev_display (ChamberSingle)
disp_message (WindowHandle, ‘NG’, ‘image’, FillLevelHeight[Idx] - 50, ColumnEdges[Idx] - 10, ‘red’, ‘false’)
else
disp_message (WindowHandle, ‘OK’, ‘image’, FillLevelHeight[Idx] - 50, ColumnEdges[Idx] - 10, ‘green’, ‘false’)
dev_set_color (‘green’)
endif
dev_display (FillLevel)
dev_display (Cross)
endfor
if (Errors > 0)
disp_message (WindowHandle, Errors + ’ BAD’, ‘window’, 10, 12, ‘red’, ‘true’)
else
disp_message (WindowHandle, ‘All OK’, ‘window’, 10, 12, ‘forest green’, ‘true’)
endif
if (Index < NumImages)
disp_continue_message (WindowHandle, ‘black’, ‘true’)
stop ()
endif
endfor