引言

機器視覺中缺陷檢測分為一下幾種:

本篇主要總結一下缺陷檢測中測量擬合的方法。通過測量被測物的尺寸(長短粗細、高矮胖瘦、間隙寬窄,包括我以前做過的平面度、平行度、輪廓度)等問題來檢測產品是否合格。


測量擬合

在產品生產過程中會不可避免的產生尺寸缺陷和表面外觀缺陷,前幾篇的缺陷著重於表面外觀的檢測,本篇基於尺寸缺陷檢測用測量擬合的方法來實現。

halcon中測量運算元分析:

在機器視覺中,測量是必不可少的一個分支。測量主要包括有物體大小的測量、距離的測量以及物體完整度檢測等。在工業機器視覺裡面常用的有1維測量和2維測量,不過大部分的測量都是要基於標定之後(需要獲取環境引數,比如得到pixel的物理大小)不經過標定的測量都只是測量物體的相對大小(畫素大小)。

1️⃣維測量:

像點到點的距離,邊緣對的距離等沿著一維方向的測量都屬於1D測量範疇。Halocn的一維測量的步驟:

  1. 建立測量矩形或者測量扇形區域(gen_measure_rectangle2,gen_measure_arc)
  2. 測量單邊緣或邊緣對(measure_pos,measure_pairs)
  3. 顯示

相關運算元:

  • gen_measure_rectangle2(形成測量矩形)
gen_measure_rectangle2( Row, Column, Phi, Length1, Length2, Width, Height, Interpolation : MeasureHandle)

引數列表:
Row//仿射矩形中心行座標
Column//仿射矩形中心列座標
Phi//仿射矩形的縱軸水平角,單位弧度 ,注意:測量矩形的測量方向的選擇
Length1//仿射矩形寬度的一半
Length2//仿射矩形高度的一半
Width//影象的寬度
Height//影象的高度
Interpolation //插值型別('bicubic', 'bilinear', 'nearest_neighbor')
MeasureHandle//測量物件控制代碼

  • gen_measure_arc(形成測量扇形)
gen_measure_arc( Row, Col, Radius, AngleStart, AngleExtent, Radius, Width, Height, Interpolation :MeasureHandle)

引數列表:
Row//中心點行座標
Col//中心點列座標
AngleStart//起始角度
AngleExtent//角度範圍
Radius//半徑
Width//影象寬
Height//影象高
Interpolation //插值方法
MeasureHandle//控制代碼

  • measure_pos(測量單邊緣)
measure_pos (Image, MeasureHandle, Sigma, Threshold, Transition, Select, RowEdge, ColumnEdge, Amplitude, Distance)

引數列表:
Sigma//高斯平滑係數(影象上可能會有噪點,影響我們對邊緣的判斷)
Threshold//閾值(代表閾值超過該值把它當做邊緣)
Transition//極性
Select//邊緣選擇
RowEdge//找到的邊緣中心的行座標
ColumnEdge//找到的邊緣中心列座標
Amplitude//邊緣幅度
Distance//相鄰邊緣之間的距離
  • measure_pairs(測量邊緣對)
measure_pairs(Image ,MeasureHandle, Sigma, Threshold, Transition, Select : RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)

引數列表:
Image//輸入影象
MeasureHandle//測量物件控制代碼
Sigma//高斯平滑引數
Threshold最//小邊緣幅度
Transition//邊緣對極性,
Select //選擇邊緣對
RowEdgeFirst//邊緣點對的第一個邊緣的中心行座標
ColumnEdgeFirst//邊緣點對的第一個邊緣的中心列座標
AmplitudeFirst//第一個邊緣的幅度
RowEdgeSecond//第二個邊緣中心行座標
ColumnEdgeSecond//第二個邊緣中心列座標
AmplitudeSecond//第二個邊緣幅度
IntraDistance//兩個邊緣對之間的距離
InterDistance//相鄰邊緣對之間的距離

二者區別:

  • translate_measure(轉換度量物件)
描述:一般用於一個程式中有很多測量矩形的情況,當使用第二個測量矩形時,不需要重新gen_measure_rectangle2生成,將第二個測量矩形的中心座標放到該運算元的第二、三個引數當中即可。
translate_measure(  MeasureHandle, Row, Column )(選用)

引數列表:
MeasureHandle//測量控制代碼
Row//新參考點的行座標
Column //新參考點的列座標

halcon例項分析


1,測量液體線高度


本案例通過測量矩形測量液位線的位置來判斷液體是裝多了還是裝少了。(測量矩形使用形狀模板匹配定位跟隨測量)

整體思路:

  1. 以瓶底為模板進行模板匹配
  2. 設定標準液線,高液線,低液線(瓶內液體在該範圍內判定合格)
  3. 將測量矩形移動到測量位置進行測量
  4. 顯示
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[0]) * (Rows - RowC[0]) + (Cols - ColC[0]) * (Cols - ColC[0]))
D2 := sqrt((Rows - RowC[1]) * (Rows - RowC[1]) + (Cols - ColC[1]) * (Cols - ColC[1]))
D3 := sqrt((Rows - RowC[2]) * (Rows - RowC[2]) + (Cols - ColC[2]) * (Cols - ColC[2]))
D4 := sqrt((Rows - RowC[3]) * (Rows - RowC[3]) + (Cols - ColC[3]) * (Cols - ColC[3]))
* 輪廓上的點到最小外接矩形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

參考博文:(2條訊息) Halcon:測量擬合法檢測缺陷_yangsen001122的部落格-CSDN部落格