halcon实例分析
1,测量液体线高度
本案例通过测量矩形测量液位线的位置来判断液体是装多了还是装少了。(测量矩形使用形状模板匹配定位跟随测量)
整体思路:
以瓶底为模板进行模板匹配
设定标准液线,高液线,低液线(瓶内液体在该范围内判定合格)
将测量矩形移动到测量位置进行测量
显示
dev_get_window (WindowHandle)
set_display_font (WindowHandle, 15, 'mono', 'true', 'false')
read_image (Image, 'ampoules/ampoules_01')
* 创建模板
get_image_size (Image, Width, Height)
gen_rectangle1 (ModelRegion, 264, 54, 321, 100)
reduce_domain (Image, ModelRegion, TemplateImage)
create_shape_model (TemplateImage, 3, rad(-5), rad(10), 'auto', ['none','no_pregeneration'], 'use_polarity', [25,54,4], 4, ModelID)
get_shape_model_contours (ModelContours, ModelID, 1)
NumImages := 8
for Index := 1 to NumImages by 1
read_image (Image, 'ampoules/ampoules_' + Index$'.2d')
* 寻找实例
find_shape_model (Image, ModelID, rad(-5), rad(10), 0.7, 0, 0.5, 'least_squares', [3,1], 0.75, Row, Column, Angle, Score)
MeanRows:=mean(Row)
Length1:=52
Length2:=20
gen_measure_rectangle2 (0, 0, rad(90), Length1, Length2,Width, Height, 'nearest_neighbor', MeasureHandle)
* 设置两条参考线
MeasureRow:=MeanRows-180
standard:=120//标准液线
offset:=20//允许液线偏移量
RefLineHigh:=standard-offset//高液线
RefLineLow:=standard+offset//低液线
dev_set_color ('cyan')
dev_set_line_width (1)
set_line_style (WindowHandle, 10)
gen_contour_polygon_xld (ContourLineHigh, [RefLineHigh,RefLineHigh], [0,Width])
gen_contour_polygon_xld (ContourLineLow, [RefLineLow,RefLineLow], [0,Width])
gen_contour_polygon_xld (ContourStand, [standard,standard], [0,Width])
dev_display (Image)
dev_display (ContourStand)
dev_display (ContourLineHigh)
dev_display (ContourLineLow)
for I := 0 to |Score| - 1 by 1
* 将测量矩形移动到测量位置
dev_set_line_width (3)
set_line_style (WindowHandle, 0)
* 转换度量对象
translate_measure (MeasureHandle, MeasureRow, Column[I])
measure_pos (Image, MeasureHandle, 2.6, 7, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance)
if(|RowEdge|>0)
if(RowEdge<RefLineHigh)
dev_set_color ('red')
gen_contour_polygon_xld (Contour, [RowEdge,RowEdge], [ColumnEdge-24,ColumnEdge+24])
dev_display (Contour)
disp_message (WindowHandle, '超出'+(RefLineHigh-RowEdge), 'image', RowEdge, ColumnEdge-30, 'red', 'false')
elseif(RowEdge>RefLineLow)
dev_set_color ('red')
gen_contour_polygon_xld (Contour, [RowEdge,RowEdge], [ColumnEdge-24,ColumnEdge+24])
dev_display (Contour)
disp_message (WindowHandle, '低出'+(RowEdge-RefLineLow), 'image', RowEdge, ColumnEdge-30, 'red', 'false')
else
dev_set_color ('green')
gen_contour_polygon_xld (Contour, [RowEdge,RowEdge], [ColumnEdge-24,ColumnEdge+24])
dev_display (Contour)
endif
endif
endfor
stop()
endfor
2,检测矩形通孔的缺陷
如图,该例程是对矩形区域的冲压通孔的缺陷检测,由图可以看到有的区域边缘有缺陷,具体表现就是边缘不齐整,向下突出了一块。
于是我们就自然想到了:提取矩形的实际轮廓xld,再拟合一个标准的轮廓xld,利用dist_rectangle2_contour_points_xld 这个算子求实际轮廓与理论轮廓点对点的距离,只要这个距离超过了我们的设定值,就认为边缘有缺陷了。而且还可以根据距离的大小和超出设定距离的点的数量来评价这个缺陷的严重程度。
dev_update_off ()
*读入图像
read_image (Image, 'punched_holes')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (Image)
*快速二值化(增加了被提取区域最小尺寸10个像素)
fast_threshold (Image, Region, 128, 255, 10)
*形态学求边界,inner代表内边界。内边界=原图-腐蚀后的图,外边界=膨胀后的图-原图
boundary (Region, Border, 'inner')
dilation_rectangle1 (Border, EdgeROI, 7, 7)
*抠图
reduce_domain (Image, EdgeROI, ImageReduced)
*边缘提取,输出XLD轮廓,平滑系数1.7
edges_sub_pix (ImageReduced, Edges, 'canny', 1.7, 40, 120)
* 选择周长在500-100000像素内的边界
select_shape_xld (Edges, RectangleEdges, 'contlength', 'and', 500, 100000)
* 拟合一个矩形的亚像素轮廓xld
fit_rectangle2_contour_xld (RectangleEdges, 'tukey', -1, 0, 0, 3, 2, Row, Column, Phi, Length1, Length2, PointOrder)
* 形成一个矩形的亚像素轮廓xld
gen_rectangle2_contour_xld (Rectangles, Row, Column, Phi, Length1, Length2)
dev_set_color ('yellow')
dev_display (Rectangles)
*计算所有边界的数量
count_obj (RectangleEdges, Number)
*开始计算轮廓上的点和最小外接矩形上的点之间的距离(会排除4个叫的距离)
for I := 0 to Number - 1 by 1
*开始选中第一个轮廓,索引从1开始
select_obj (RectangleEdges, RectangleEdge, I + 1)
*通过轮廓,得到轮廓上的点的坐标。会有很多点,这是实际边界上的点
get_contour_xld (RectangleEdge, Rows, Cols)
*形成XLD亚像素轮廓
gen_rectangle2_contour_xld (Rect, Row[I], Column[I], Phi[I], Length1[I], Length2[I])
* 获得拟合的轮廓上的点。这是标准矩形上的点
get_contour_xld (Rect, RowC, ColC)
*下面是横坐标的平方和+纵坐标的平方和,开跟号
*求的就是实际边界上的点和拟合矩形边界上的点的距离
*RowC,ColC从0-3,代表的是拟合的矩形的4个角的坐标值
D1 := sqrt((Rows - RowC) * (Rows - RowC) + (Cols - ColC) * (Cols - ColC))
D2 := sqrt((Rows - RowC) * (Rows - RowC) + (Cols - ColC) * (Cols - ColC))
D3 := sqrt((Rows - RowC) * (Rows - RowC) + (Cols - ColC) * (Cols - ColC))
D4 := sqrt((Rows - RowC) * (Rows - RowC) + (Cols - ColC) * (Cols - ColC))
* 轮廓上的点到最小外接矩形4个角点,上最小距离值
DistCorner := min2(min2(D1,D2),min2(D3,D4))
*求的是轮廓上的点到最小外接矩形间的距离。0代表不忽略任何点
dist_rectangle2_contour_points_xld (RectangleEdge, 0, Row[I], Column[I], Phi[I], Length1[I], Length2[I], Dist)
*假设距离都在规格范围内
* RectangleOK := true
* for J := 0 to |Dist| - 1 by 1
*从0开始,对于上面计算出的距离值进行判断
*对于某个点而言,到最近的角点的距离超过了7个像素,说明我们对于角落的部分点进行了筛选
*做对应计算的是不在角落7个像素以内的点
*如果这些点和最小外接矩形的区域距离超过1个像素,说明该点是NG的
* if (DistCorner[J] > 7.0 and Dist[J] > 1.0)
* RectangleOK := false
* break
* endif
* endfor
* sgn是符号函数,括号里面的值=0,Mask就等于0.里面的值>0,Mask就等于1。里面的值<0,Mask就等于-1。
*max2(DistCorner - 7.0,0.0),就代表角点的坐标,如果有超过7个像素的值,那么就>0;Mask就等于1
*如果没有超过7个像素的值,那么<0。max2(DistCorner - 7.0,0.0)就等于0,Mask就等于0
Mask := sgn(max2(DistCorner - 7.0,0.0))
* 如果等于1的话,1这个距离。如果距离的最大值<=1成立,就说明ok
RectangleOK := max(Dist * Mask) <= 1.0
* 显示那个孔洞是OK的
if (RectangleOK)
dev_set_color ('green')
*取一个字符串的空间大小
get_string_extents (WindowHandle, 'OK', Ascent, Descent, Width, Height)
*设置光标的位置
set_tposition (WindowHandle, Row[I] - Height / 2, Column[I] - Width / 2)
*写一个ok字符串
write_string (WindowHandle, 'OK')
else
dev_set_color ('red')
get_string_extents (WindowHandle, 'Not OK', Ascent, Descent, Width, Height)
set_tposition (WindowHandle, Row[I] - Height / 2, Column[I] - Width / 2)
write_string (WindowHandle, 'Not OK')
endif
endfor