halcon實(shí)例分析
1,測(cè)量液體線高度
本案例通過(guò)測(cè)量矩形測(cè)量液位線的位置來(lái)判斷液體是裝多了還是裝少了。(測(cè)量矩形使用形狀模板匹配定位跟隨測(cè)量)
整體思路:
以瓶底為模板進(jìn)行模板匹配
設(shè)定標(biāo)準(zhǔn)液線,高液線,低液線(瓶?jī)?nèi)液體在該范圍內(nèi)判定合格)
將測(cè)量矩形移動(dòng)到測(cè)量位置進(jìn)行測(cè)量
顯示
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')
* 尋找實(shí)例
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
* 將測(cè)量矩形移動(dòng)到測(cè)量位置
dev_set_line_width (3)
set_line_style (WindowHandle, 0)
* 轉(zhuǎn)換度量對(duì)象
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,檢測(cè)矩形通孔的缺陷
如圖,該例程是對(duì)矩形區(qū)域的沖壓通孔的缺陷檢測(cè),由圖可以看到有的區(qū)域邊緣有缺陷,具體表現(xiàn)就是邊緣不齊整,向下突出了一塊。
于是我們就自然想到了:提取矩形的實(shí)際輪廓xld,再擬合一個(gè)標(biāo)準(zhǔn)的輪廓xld,利用dist_rectangle2_contour_points_xld 這個(gè)算子求實(shí)際輪廓與理論輪廓點(diǎn)對(duì)點(diǎn)的距離,只要這個(gè)距離超過(guò)了我們的設(shè)定值,就認(rèn)為邊緣有缺陷了。而且還可以根據(jù)距離的大小和超出設(shè)定距離的點(diǎn)的數(shù)量來(lái)評(píng)價(jià)這個(gè)缺陷的嚴(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個(gè)像素)
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)
* 選擇周長(zhǎng)在500-100000像素內(nèi)的邊界
select_shape_xld (Edges, RectangleEdges, 'contlength', 'and', 500, 100000)
* 擬合一個(gè)矩形的亞像素輪廓xld
fit_rectangle2_contour_xld (RectangleEdges, 'tukey', -1, 0, 0, 3, 2, Row, Column, Phi, Length1, Length2, PointOrder)
* 形成一個(gè)矩形的亞像素輪廓xld
gen_rectangle2_contour_xld (Rectangles, Row, Column, Phi, Length1, Length2)
dev_set_color ('yellow')
dev_display (Rectangles)
*計(jì)算所有邊界的數(shù)量
count_obj (RectangleEdges, Number)
*開(kāi)始計(jì)算輪廓上的點(diǎn)和最小外接矩形上的點(diǎn)之間的距離(會(huì)排除4個(gè)叫的距離)
for I := 0 to Number - 1 by 1
*開(kāi)始選中第一個(gè)輪廓,索引從1開(kāi)始
select_obj (RectangleEdges, RectangleEdge, I + 1)
*通過(guò)輪廓,得到輪廓上的點(diǎn)的坐標(biāo)。會(huì)有很多點(diǎn),這是實(shí)際邊界上的點(diǎn)
get_contour_xld (RectangleEdge, Rows, Cols)
*形成XLD亞像素輪廓
gen_rectangle2_contour_xld (Rect, Row[I], Column[I], Phi[I], Length1[I], Length2[I])
* 獲得擬合的輪廓上的點(diǎn)。這是標(biāo)準(zhǔn)矩形上的點(diǎn)
get_contour_xld (Rect, RowC, ColC)
*下面是橫坐標(biāo)的平方和+縱坐標(biāo)的平方和,開(kāi)跟號(hào)
*求的就是實(shí)際邊界上的點(diǎn)和擬合矩形邊界上的點(diǎn)的距離
*RowC,ColC從0-3,代表的是擬合的矩形的4個(gè)角的坐標(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))
* 輪廓上的點(diǎn)到最小外接矩形4個(gè)角點(diǎn),上最小距離值
DistCorner := min2(min2(D1,D2),min2(D3,D4))
*求的是輪廓上的點(diǎn)到最小外接矩形間的距離。0代表不忽略任何點(diǎn)
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開(kāi)始,對(duì)于上面計(jì)算出的距離值進(jìn)行判斷
*對(duì)于某個(gè)點(diǎn)而言,到最近的角點(diǎn)的距離超過(guò)了7個(gè)像素,說(shuō)明我們對(duì)于角落的部分點(diǎn)進(jìn)行了篩選
*做對(duì)應(yīng)計(jì)算的是不在角落7個(gè)像素以內(nèi)的點(diǎn)
*如果這些點(diǎn)和最小外接矩形的區(qū)域距離超過(guò)1個(gè)像素,說(shuō)明該點(diǎn)是NG的
* if (DistCorner[J] > 7.0 and Dist[J] > 1.0)
* RectangleOK := false
* break
* endif
* endfor
* sgn是符號(hào)函數(shù),括號(hào)里面的值=0,Mask就等于0.里面的值>0,Mask就等于1。里面的值<0,Mask就等于-1。
*max2(DistCorner - 7.0,0.0),就代表角點(diǎn)的坐標(biāo),如果有超過(guò)7個(gè)像素的值,那么就>0;Mask就等于1
*如果沒(méi)有超過(guò)7個(gè)像素的值,那么<0。max2(DistCorner - 7.0,0.0)就等于0,Mask就等于0
Mask := sgn(max2(DistCorner - 7.0,0.0))
* 如果等于1的話,1這個(gè)距離。如果距離的最大值<=1成立,就說(shuō)明ok
RectangleOK := max(Dist * Mask) <= 1.0
* 顯示那個(gè)孔洞是OK的
if (RectangleOK)
dev_set_color ('green')
*取一個(gè)字符串的空間大小
get_string_extents (WindowHandle, 'OK', Ascent, Descent, Width, Height)
*設(shè)置光標(biāo)的位置
set_tposition (WindowHandle, Row[I] - Height / 2, Column[I] - Width / 2)
*寫一個(gè)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