halcon——缺陷檢測常用方法總結(光度立體)

引言

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

前一篇總結了頻域與空間域的結合使用,本篇就光度立體的缺陷檢測做一個總結。


 光度立體

在工業領域,表面檢測是一個非常廣泛的應用領域。在halcon中,使用增強的光度立體視覺方法,三維表面檢測被加強。利用陰影可方便快速的檢測物體表面的缺口或凹痕。 使用光度立體視覺方法可在複雜圖像中輕鬆找到表面缺陷 。

  • 適用場景:光度立體法可以看作是2.5維,適用於檢測金屬物料上面的凹凸特徵。
  • 函數原理:
         1.通過photometric_stereo算子獲得表面梯度圖像,該算子可以得到表面梯度圖像和反照率圖像。需要輸入多張從不同角度照明所得到的圖像。
          2.通過derivate_vector_field算子獲得高斯(平均)曲率圖像,該算子中需要輸入表面梯度圖像。
  • 光源:光度立體法不需要特殊的光源,只需要從不同的角度打光而已。

1️⃣光度立體法的典型應用:
光度立體法的典型應用是檢測物體表面微小變化,例如,受打光方向影響的缺陷。比如非平面的打印檢測(個人理解:普通打光方式受光線影響特徵成像不理想,可以通過光度立體法檢測)。值得注意的是:光度立體法不適用於絕對高度的重建,也就是說,它不能替代傳統的3D重建算法,如對焦測距和激光三角測量。

2️⃣光度立體法的局限性:
光度立體法基於Woodham算法。因此:

  • 一方面假定相機是無畸變成像,也就是說必須使用遠心鏡頭或者長焦鏡頭
  • 另一方面假定每一個光源發射的光束都是平行且均勻的,也就是說必須使用具有均勻強度的遠心照明光源,或者使用遠距離的點光源代替

此外,物體必須具有朗伯反射特性,即它必須以漫反射的方式反射入射光。有鏡面反射的物體或者區域(鏡子或者光滑的表面)不能使用此方法,會得到一個錯誤的結果。

3️⃣採集圖像設置:
帶有遠心鏡頭的相機必須與被測物體表面垂直安裝,在採集多幅圖像時,一定要保證相機和物體不被移動。相反,對於採集至少三張的灰度圖像,其每次取像的照明方向必須改變(相對於相機)。


 🧡光度立體核心算子:(注意:光度立體法需要使用灰度圖,而且至少需要3張圖像,最好是4張)


  •  photometric_stereo (根據光度立體技術重建曲面)
photometric_stereo (Images ,HeightField, Gradient, Albedo : Slant, Tilt, ResultType, ReconstructionMethod, GenParamName, GenParamValue )

參數列表:
Images(in//輸入灰度圖像(4張)
HeightField(out//返回重建高度信息圖
Gradient(out//返回表面的梯度信息圖
Albedo(out//返回表面的反射率信息圖
Slant//光源光線與攝像機光軸的夾角(下面有示意圖)
 Tilt//光源光線投影與被測物主軸的夾角
 ResultType//請求結果類型(高度場/梯度場/反射率)
ReconstructionMethod//重建方法類型
GenParamName//一般參數名稱
GenParamValue// 一般參數設置

photometric_stereo 函數詳解:

光度立體法可以根據二維紋理信息提取出三維模型(實際只有2.5維)。photometric_stereo算子至少需要三張圖(最好四張圖),這些圖是在相機和物體相對位置不變條件下(Note),通過不同方向打光獲取的。

物體的三維模型主要是根據三維表面的局部梯度計算提取的。三維表面的局部梯度信息可以進一步整合獲得高度信息圖,灰度值與高度值一一對應。二維紋理被稱為反照率,它對應於物體表面局部光吸收和反射特性,被遮擋的部分沒有此特性。

1️⃣光照方向說明:
對於採集的多張圖像中的每一幅圖,照明方向必須指定Slants和Tilts兩個參數角度,其描述了相對於當前場景的光照角度。為了更好的理解這兩個參數含義,我們假定光源射出的光束是平行光,鏡頭是遠心鏡頭,相機垂直於物體表面。

Slant參數:                                                     

 

Tilt參數:

 

 

這個角度是以圖像為準的,比如光從圖像右側打過來,角度就是0°,從上面打過來,角度是90°,從左面打過來,角度是180°,下邊打過來是270°。

 正常情況下一般都是至少採集三張不同方向打光的圖。但對於一些特殊的產品,因為陰影的原因,三個方向打光不能很好的表徵缺陷特徵,造成重建的圖像特徵不明顯,這個時候就需要在原來基礎上增加打光方向,避免死角。隨着打光方向增加採集圖像也跟着增加,那麼算法處理時間也變長。根據經驗:

  1. 4-6個不同方向打光能滿足大部分應用;
  2. Slant角度一般選擇30度-60度;
  3. Tilt角度通常都是均勻分佈在被測物體周圍,比如3個方向打光,Tilt角度應該是[0,120,240]OR[0,120,-120],4個方向打光是[0,90,180,-90]。需要注意的是,打光方向不能相同,否則重構的圖像結果達不到預期效果。

2️⃣輸入圖像:

輸入圖像是一個圖像數組,其中每張圖像都是在不同打光方向下採集的。如果採集的是多通道圖像,可以通過算子 image_to_channels轉換成單通道圖像,採集的多張圖像可以通過算子concat_obj合併成一個數組圖像。

光度立體法依託於對光度信息的評估,也就是圖像中的灰度值。因此,圖像質量的好壞決定了結果。要保證好的圖像質量,首先要確保相機採集的圖像具有線性特徵,可以使用算子radiometric_self_calibration確認相機特性,如果相機採集的圖像是非線性的,可以利用算子 lut_trans 矯正灰度信息。此外,如果需要更高精度,可以從以下兩點着手:(1)、使用相機的全部動態範圍;(2)、使用高於8位深度的圖像(灰度範圍0-65535而不是0-255類型的圖像)

3️⃣輸出圖像:
算子輸出重建後的梯度、反射率、以及高度場圖像。
1、梯度圖(矢量場)是根據對圖像求偏導數獲取,它可以作為算子reconstruct_height_field_from_gradient的輸入。
為了視覺觀看更直觀,將表面梯度進行歸一化處理。因此ResultType類型需要設置成「normalized_gradient」,而不是「gradient」。如果ResultType設置成默認模式「all」,處理方式是「gradient」,而不是「normalized_gradient」,所以在參數設置時要根據需要設置。
2、Albedo 圖像描述的是物體的反射率,其值介於0(黑色)-1(白色)之間。因此,Albedo反應了物體表面特性。比如對於印刷表面表面,Albedo反應的是表面明暗程度的特性。

3,HeightField 圖像中每個像素值以某種關係與其高度一一對應。

4️⃣ResultType參數:

默認情況下,ResultType設置成「all」。假如在應用中僅僅需要部分結果,可以通過數組的形式在『gradient』, 『albedo』, and 『height_field』中選擇設置ResultType參數,例如ResultType := [『gradient』,『albedo』]。對於特定的表面檢測應用,如果只需要『gradient』, 『albedo』,那麼將ResultType設置成『gradient』, ‘albedo』不進行三維重構(『height_field』),處理速度將會有效提升。

5️⃣photometric_stereo 函數:

photometric_stereo算子首先會計算出梯度矢量場,如果需要高度場,光度立體法內部會採用reconstruct_height_field_from_gradient算子進行整合處理,通過 ReconstructionMethod, GenParamName, and GenParamValue這三個參數控制效果。如果參數ResultType參數中沒有設置『height_field』,可以忽略這三個參數。

  • derivate_vector_field(處理photometric_stereo 函數輸出的重建後的梯度、反射率、以及高度場信息圖)
derivate_vector_field(VectorField ,Result , Sigma, Component )

參數列表: VectorField(in)
// 梯度場圖像 Result(out) // 返回平均曲率場圖像 Sigma(in) // 高斯係數 Component(in) //組件計算

derivate_vector_field函數詳解:

將向量場的分量與高斯函數的導數進行卷積,並計算由此得到的各種特徵。在光度立體項目中,專門用於處理photometric_stereo 函數輸出的重建後的梯度、反射率、以及高度場圖像。

1️⃣Sigma參數:

如果在Sigma中傳遞一個值,那麼在列和行方向上的平滑量是相同的。

如果在Sigma中傳遞兩個值,第一個值指定列方向的平滑量,第二個值指定行方向的平滑量。

2️⃣Component參數:(有四個值可選,後兩個值專用於光度立體)

  1. curl,向量場的旋度。旋度的一個應用是分析光流場。旋度是如果向量場是流體,小船會旋轉多少。
  2. divergence,向量場的散度。「divergence」的一個應用是分析光流場。打個比方,如果向量場是流體,散度就是源和匯的位置。
  3. mean_curvature,當輸入向量場 VectorField為梯度場時,下墊面的平均曲率H。用於處理photometric_stereo返回的向量場。
  4. gauss_curvature,當輸入向量場 VectorField 為梯度場時,下墊面的高斯曲率K。用於處理photometric_stereo返回的向量場。

 🤎halcon實例分析


 1,皮革表面缺陷檢測(inspect_leather_photometric_stereo.hdev)

在實際應用中,有些產品缺陷對光源角度有要求,且方向不固定(比如:帶方向的缺陷,需要多角度打光才能凸顯缺陷的產品)那麼就可以考慮光度立體法。

💙利用反射率圖像梯度圖像檢測皮革表面缺陷

下面是兩種皮革表面拍攝圖像:

 

dev_close_window ()
dev_open_window (0, 0, 640, 480, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
* Part 1利用反射率圖像檢測皮革表面缺陷
read_image (Images, 'photometric_stereo/leather_1_0' + [1:4])
write_image (Images, 'tiff', 0, 'D:/1.tiff')
** 展示不同方向光源成像圖像
for I := 1 to 4 by 1
    Message := 'Sample 1: Acquire image ' + I + ' of 4'
    select_obj (Images, ObjectSelected, I)
    dev_display (ObjectSelected)
    disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
    wait_seconds (0.5)
endfor
* 應用光度立體法生成的反射率圖進行缺陷檢測
Tilts := [6.1,95.0,-176.1,-86.8]
Slants := [41.4,42.6,41.7,40.9]
ResultType := ['gradient','albedo']
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, ResultType, 'poisson', [], [])
* 顯示反射率圖
dev_display (Albedo)
*檢測缺陷
var_threshold (Albedo, Region, 15, 15, 0.4, 0.4, 'light')
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 10, 99999)
union1 (SelectedRegions, RegionUnion)
closing_circle (RegionUnion, RegionClosing, 3.5)
connection (RegionClosing, Defects)
area_center (Defects, Area, Row, Column)
gen_circle (Circle, Row, Column, gen_tuple_const(|Row|,sqrt(Area) + 30))
*顯示缺陷
dev_display (Albedo)
dev_set_color ('red')
dev_set_draw ('margin')
dev_set_line_width (4)
dev_display (Circle)

* Part 2 利用梯度圖像檢測皮革表面缺陷
read_image (Images, 'photometric_stereo/leather_2_0' + [1:4])
for I := 1 to 4 by 1
    Message := 'Sample 2: Acquire image ' + I + ' of 4'
    select_obj (Images, ObjectSelected, I)
    dev_display (ObjectSelected)
    disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
    wait_seconds (0.5)
endfor

* 應用光度立體法生成的反射率圖
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, ResultType, 'poisson', [], [])
*對反射率圖二值化(發現無法二值化)
threshold (Albedo, Region1, 128, 255)
* 顯示反射率圖
dev_display (Albedo)
derivate_vector_field (Gradient, Curl, 1, 'curl')
derivate_gauss (Curl, CurlGradient, 1, 'gradient')
* 顯示梯度圖
dev_display (CurlGradient)
Message := 'Changes in the gradient curl'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

* 用梯度圖尋找缺陷
threshold (CurlGradient, Region, 0, 0.01)
rank_region (Region, RegionCount, 10, 10, 30)//歸類區域
connection (RegionCount, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 2000, 99999)
union1 (SelectedRegions, RegionUnion)
rank_region (RegionUnion, RegionCount1, 25, 25, 170)
connection (RegionCount1, NoTextured)

* 顯示
dev_display (Albedo)
dev_set_draw ('margin')
dev_set_color ('red')
dev_set_line_width (3)
dev_display (NoTextured)
disp_message (WindowHandle, 'Non-textured areas on leather', 'window', 12, 12, 'black', 'true')
stop ()

 Part1:反射率圖找缺陷                                                                                                    Part2:梯度圖找缺陷

 

 思考:Part1利用反射率圖檢測皮革表面缺陷,而Part2卻利用梯度信息圖檢測缺陷,Why?

[分析]

 仔細觀察不難發現,Part1中的缺陷區域(左圖)展現的都是高亮特性。缺陷特徵比背景區域具有較高的反光特性,所以反射率圖能很好的凸顯缺陷特徵,所以用反射率圖檢測缺陷。

如果用梯度圖去檢測Part1中的缺陷會怎樣呢?如下圖:(可以看出缺陷和紋理對比度很差,所以不能用梯度信息圖檢測Part1中的缺陷。)

 對於Part2,可以發現,缺陷為細條狀,是比較明顯的劃痕因此利用梯度信息圖檢測這種缺陷是一種不錯的選擇。

2,洗髮水瓶身缺陷檢測(inspect_shampoo_label_photometric_stereo.hdev)

該例程的Tilts參數構建:

 

 這個例子展示的是利用光度立體法檢測洗髮水瓶的標籤缺陷:

dev_close_window ()
dev_update_off ()
dev_open_window (0, 0, 640, 512, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')

*讀入4幅由四個不同光照方向所成的圖像
read_image (Images, 'photometric_stereo/shampoo_label_0' + [1:4])
for I := 1 to 4 by 1
    Message := 'Acquire image ' + I + ' of 4'
    select_obj (Images, ObjectSelected, I)
    dev_display (ObjectSelected)
    disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
    wait_seconds (0.5)
endfor
* 
*設置參數,用光度立體法生成梯度以及反射率圖
Tilts := [6.1,95.0,-176.1,-86.8]
Slants := [41.4,42.6,41.7,40.9]
ResultType := ['gradient','albedo']
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, ResultType, 'poisson', [], [])
* 顯示反射率圖
dev_display (Albedo)
stop ()
* 對梯度圖像進行高斯導數卷積操作
derivate_vector_field (Gradient, MeanCurvature, 1.0, 'mean_curvature')
* 
*缺陷檢測
threshold (MeanCurvature, Region, -10, -0.07)
opening_circle (Region, RegionOpening, 1)
connection (RegionOpening, ConnectedRegions)
select_shape (ConnectedRegions, Defects, 'area', 'and', 50, 99999)
shape_trans (Defects, Circle, 'outer_circle')
stop ()
*顯示
dev_set_draw ('margin')
dev_set_color ('red')
dev_display (Albedo)
dev_display (Circle)
disp_message (WindowHandle, 'Defect in albedo image', 'window', 12, 12, 'black', 'true')

 

 3,藥片外包裝破損的檢測(inspect_blister_photometric_stereo.hdev)

思路如下:

  1. 讀入4張各角度圖像
  2. 光度立體法求梯度圖以及反射率圖(photometric_stereo)
  3. 用得到的梯度圖,計算表面的高斯曲率,得到高斯曲率圖像(在曲率圖像上能更容易的進行檢測)(derivate_vector_field)
  4. 對高斯曲率圖像進行預處理和Blob分析,從而得到缺陷區域(區域分割(區域生長法),特徵提取)
dev_close_window ()
dev_update_off ()
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
stop ()
* 
* 讀入4張各角度圖像
read_image (Images, 'photometric_stereo/blister_back_0' + [1:4])
for I := 1 to 4 by 1
    Message := 'Acquire image ' + I + ' of 4'
    select_obj (Images, ObjectSelected, I)
    dev_display (ObjectSelected)
    disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
    wait_seconds (0.5)
endfor
* 
*用光度立體法得到梯度圖和反射率圖
Tilts := [6.1,95.0,-176.1,-86.8]
Slants := [41.4,42.6,41.7,40.9]
ResultType := ['gradient','albedo']
photometric_stereo (Images, HeightField, Gradient, Albedo, Slants, Tilts, ResultType, 'poisson', [], [])
* 
*顯示反射率圖
dev_display (Albedo)
stop ()
* 
* 使用之前得到的梯度圖,計算表面的高斯曲率,得到高斯曲率圖像(在曲率圖像上能更容易的進行檢測)
derivate_vector_field (Gradient, GaussCurvature, 1, 'gauss_curvature') 
* 對高斯曲率圖像進行預處理和Blob分析,從而得到缺陷區域
  *圖像分割(區域生長)
regiongrowing (GaussCurvature, Regions, 1, 1, 0.001, 250)
select_shape (Regions, TabletRegions, ['width','height'], 'and', [150,150], [200,200])
shape_trans (TabletRegions, TabletRegions, 'convex')
union1 (TabletRegions, TabletRegions)
erosion_circle (TabletRegions, TabletRegions, 3.5)
* Search for defects inside the tablet areas
reduce_domain (GaussCurvature, TabletRegions, ImageReduced)
abs_image (ImageReduced, ImageAbs)
threshold (ImageAbs, Region, 0.03, 255)
closing_circle (Region, RegionClosing, 10.5)
connection (RegionClosing, ConnectedRegions)
select_shape (ConnectedRegions, Defects, 'area', 'and', 10, 99999)
area_center (Defects, Area, Row, Column)
gen_circle (Circle, Row, Column, gen_tuple_const(|Row|,20.5))
* Display the defects in curvature image
dev_set_draw ('margin')
dev_set_color ('red')
dev_set_line_width (2)
dev_display (GaussCurvature)
dev_display (Circle)
Message := 'The defect can easily be detected'
Message[1] := 'in the surface curvature image'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
stop ()
* Display the defects in the albedo image
dev_set_draw ('margin')
dev_set_color ('red')
dev_display (Albedo)
dev_display (Circle)
disp_message (WindowHandle, 'Defect in albedo image', 'window', 12, 12, 'black', 'true')