halcon實例分析
1,測量液體線高度
本案例通過測量矩形測量液位線的位置來判斷液體是裝多了還是裝少了。(測量矩形使用形狀模板匹配定位跟隨測量)
整體思路:
以瓶底為模板進(jìn)行模板匹配
設(shè)定標(biāo)準(zhǔn)液線,高液線,低液線(瓶內(nèi)液體在該范圍內(nèi)判定合格)
將測量矩形移動到測量位置進(jìn)行測量
顯示
dev_get_window (WindowHandle)
set_display_font (WindowHandle, 15, 'mono', 'true', 'false')
read_image (Image, 'ampoules/ampoules_01')
* 創(chuàng)建模板
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)
* 設(shè)置兩條參考線
MeasureRow:=MeanRows-180
standard:=120//標(biāo)準(zhǔn)液線
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)
* 轉(zhuǎn)換度量對象
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,檢測矩形通孔的缺陷
如圖,該例程是對矩形區(qū)域的沖壓通孔的缺陷檢測,由圖可以看到有的區(qū)域邊緣有缺陷,具體表現(xiàn)就是邊緣不齊整,向下突出了一塊。
于是我們就自然想到了:提取矩形的實際輪廓xld,再擬合一個標(biāo)準(zhǔn)的輪廓xld,利用dist_rectangle2_contour_points_xld 這個算子求實際輪廓與理論輪廓點對點的距離,只要這個距離超過了我們的設(shè)定值,就認(rèn)為邊緣有缺陷了。而且還可以根據(jù)距離的大小和超出設(shè)定距離的點的數(shù)量來評價這個缺陷的嚴(yán)重程度。
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)
*快速二值化(增加了被提取區(qū)域最小尺寸10個像素)
fast_threshold (Image, Region, 128, 255, 10)
*形態(tài)學(xué)求邊界,inner代表內(nèi)邊界。內(nèi)邊界=原圖-腐蝕后的圖,外邊界=膨脹后的圖-原圖
boundary (Region, Border, 'inner')
dilation_rectangle1 (Border, EdgeROI, 7, 7)
*摳圖
reduce_domain (Image, EdgeROI, ImageReduced)
*邊緣提取,輸出XLD輪廓,平滑系數(shù)1.7
edges_sub_pix (ImageReduced, Edges, 'canny', 1.7, 40, 120)
* 選擇周長在500-100000像素內(nèi)的邊界
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)
*計算所有邊界的數(shù)量
count_obj (RectangleEdges, Number)
*開始計算輪廓上的點和最小外接矩形上的點之間的距離(會排除4個叫的距離)
for I := 0 to Number - 1 by 1
*開始選中第一個輪廓,索引從1開始
select_obj (RectangleEdges, RectangleEdge, I + 1)
*通過輪廓,得到輪廓上的點的坐標(biāo)。會有很多點,這是實際邊界上的點
get_contour_xld (RectangleEdge, Rows, Cols)
*形成XLD亞像素輪廓
gen_rectangle2_contour_xld (Rect, Row[I], Column[I], Phi[I], Length1[I], Length2[I])
* 獲得擬合的輪廓上的點。這是標(biāo)準(zhǔn)矩形上的點
get_contour_xld (Rect, RowC, ColC)
*下面是橫坐標(biāo)的平方和+縱坐標(biāo)的平方和,開跟號
*求的就是實際邊界上的點和擬合矩形邊界上的點的距離
*RowC,ColC從0-3,代表的是擬合的矩形的4個角的坐標(biāo)值
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)
*假設(shè)距離都在規(guī)格范圍內(nèi)
* RectangleOK := true
* for J := 0 to |Dist| - 1 by 1
*從0開始,對于上面計算出的距離值進(jìn)行判斷
*對于某個點而言,到最近的角點的距離超過了7個像素,說明我們對于角落的部分點進(jìn)行了篩選
*做對應(yīng)計算的是不在角落7個像素以內(nèi)的點
*如果這些點和最小外接矩形的區(qū)域距離超過1個像素,說明該點是NG的
* if (DistCorner[J] > 7.0 and Dist[J] > 1.0)
* RectangleOK := false
* break
* endif
* endfor
* sgn是符號函數(shù),括號里面的值=0,Mask就等于0.里面的值>0,Mask就等于1。里面的值<0,Mask就等于-1。
*max2(DistCorner - 7.0,0.0),就代表角點的坐標(biāo),如果有超過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)
*設(shè)置光標(biāo)的位置
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