引言
機器視覺中缺陷檢測分為一下幾種:
- blob分析+特徵
- 模板匹配(定位)+差分
- 光度立體
- 特徵訓練
- 測量擬合
- 頻域+空間域結合:halcon——缺陷檢測常用方法總結(頻域空間域結合) - 唯有自己強大 - 部落格園 (cnblogs.com)
- 深度學習
前一篇總結了頻域與空間域的結合使用,本篇就光度立體的缺陷檢測做一個總結。
光度立體
在工業領域,表面檢測是一個非常廣泛的應用領域。在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°。
正常情況下一般都是至少採集三張不同方向打光的圖。但對於一些特殊的產品,因為陰影的原因,三個方向打光不能很好的表徵缺陷特徵,造成重建的影像特徵不明顯,這個時候就需要在原來基礎上增加打光方向,避免死角。隨著打光方向增加採集影像也跟著增加,那麼演算法處理時間也變長。根據經驗:
- 4-6個不同方向打光能滿足大部分應用;
- Slant角度一般選擇30度-60度;
- 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引數:(有四個值可選,後兩個值專用於光度立體)
- curl,向量場的旋度。旋度的一個應用是分析光流場。旋度是如果向量場是流體,小船會旋轉多少。
- divergence,向量場的散度。“divergence”的一個應用是分析光流場。打個比方,如果向量場是流體,散度就是源和匯的位置。
- mean_curvature,當輸入向量場 VectorField為梯度場時,下墊面的平均曲率H。用於處理photometric_stereo返回的向量場。
- 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)
思路如下:
- 讀入4張各角度影像
- 光度立體法求梯度圖以及反射率圖(photometric_stereo)
- 用得到的梯度圖,計算表面的高斯曲率,得到高斯曲率影像(在曲率影像上能更容易的進行檢測)(derivate_vector_field)
- 對高斯曲率影像進行預處理和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')