Halcon表面缺陷檢測-光度立體法

鯨魚的尾巴發表於2020-01-14

來自halcon中的simple.相關介紹光度立體演算法.

相關的例子:

inspect_blister_photometric_stereo.hdev

inspect_flooring_photometric_stereo.hdev

inspect_flooring_uncalib_photometric_stereo.hdev

inspect_leather_photometric_stereo.hdev

inspect_shampoo_label_photometric_stereo.hdev

主要涉及的運算元 photometric_stereo -- 通過光度立體技術重建表面

photometric_stereo(Images : HeightFieldGradient,Albedo : SlantsTiltsResultType,ReconstructionMethodGenParamNameGenParamValue : )

  • 描述:
    photometric_stereo可以用來從一個物體的兩維紋理,例如它的列印照片,來區分出它的三維形狀。這個運算元需要至少需要三張使用已知的不同方向的光源拍攝的相同物體的影像。注意,拍攝這些照片時,相機的視角應該是固定的。(譯者注:即固定相機和物體,從多個已知的不同方向打光拍攝)
    物體的這種三維形狀從根本上來說是通過計算3維表面的區域性梯度。這些梯度可以被進一步綜合起來獲取到一個高度場,也就是說,一張圖片的每個畫素都與一個相對高度相關聯。(譯者注:計算得出的)二維的紋理被稱為反照率,與對區域性光源的吸收和反射表面特徵有關,把所有的陰影都排除在外。

    • 光照立體法的典型應用
      光照立體法的典型應用是用來檢測表面的變化,這種變化可能意味著缺陷,或者被用來將拍照時光照角度的影響排除在外,例如用於非扁平字元的列印檢查。注意,光度立體法不適用於重建絕對高度,也就是說,它不能替代傳統的3D重建演算法,如對焦測距和鐳射三角測量。

    • 光度立體法的侷限性
      光度立體法是基於Woodham演算法,因此假設相機表現為無畸變的投影。這也就意味著,你必須使用一個遠心鏡頭或者長焦鏡頭。另一方面,它假設了每個光源發出的都是平行的等截面的光。這也就是說,你使用的照明必須是遠心光源,有著均勻的強度,或者作為替代,遠距離的點光源。此外,這個物體必須有朗伯反射特性,也就是說它對光的反射是漫反射。有鏡面反射的物體或者區域(鏡子或者光滑的表面)不能被正確處理,會得到一個錯誤的結果。

    • 照片採集設定
      這個使用遠心鏡頭的相機必須被放置得和被重建的平面正交,即互相垂直。相機和平面的角度在採集過程中一定不能改變。相反,光源和平面的夾角必須至少改變三次來獲取三張灰度圖片。

    • 具體說明光照的角度
      對每張圖片,光線的方向用兩個角度來表示,使用引數Slants和Tilts,這兩個引數描述了光線和平面的方向。來理解一下這兩個引數,記住,光源被假設發出的是平行光,照相機有一個遠心鏡頭,相機被放置在重建表面的正交方向。
      • Slants
        這個角度指的是相機的光軸和光線的夾角。如圖:
        技術分享圖片

      • Tilts
        這個角度使用物體平面或者其他與之平行的平面,例如圖片表面來進行測量。特別的,它描述了圖片中心點向右延伸和光線方向投影到平面上的夾角。也即,當在看圖片或者相關的平面時,一個0度的角意味著光從右邊來,90度意味著光從頂上來,180度意味著光從左邊來,等等。如圖:
        技術分享圖片

      正如之前所說的,光度立體法需要至少三張光線不同情況下拍攝的照片。然而,一個三維的幾何體通常會有陰影。在陰影區域,光線有效方向的數量(the number of effectively available directions of illumination)被削減了,這會導致不明確(譯者注:ambiguities?模稜兩可?)。儘管如此,獲取一個魯棒性好的結果,贅餘是需要的。因此,通常會使用超過三個不同方向的光源。但是記住,光線方向的增加,會導致更多的圖片需要被處理,因此需要花費更多的處理時間。在絕大多數應用中,4-6個光源是合理的。根據經驗法則,slant角度會在30°-60°之間選擇。Tilt角度通常會均等得分佈在被測物體的周圍。請記住,光線的角度必須是經過選擇的,以使得他們(譯者注:他們是指?)能夠不在同一平面上(即:光線的方向必須是獨立的)。否則,計算會失敗,程式會丟擲一個異常。

    • 輸入圖片和定義的區域
      圖片必須以一個圖片陣列輸入。如前所述:每張圖片必須是使用不同的光線角度的。如果圖片是通過儲存在多通道圖片中的,通過 image_to_channels 可以容易地轉換為圖片陣列。作為替代,圖片陣列可以通過 concat_obj 來建立。
      光度立體法依賴於對光度測定資訊的評估,也就是儲存在影像中的灰度值。因此,這些資訊應當是無偏並且是準確的。我們建議保證用來採集影像的相機有線性特徵。如果有非線性特徵,你可以使用運算元 radiometric_self_calibration 來測定你的相機的特徵,使用 lut_trans 來校正灰度資訊。此外,如果需要精確的測量,我們建議運用相機的全動態範圍,因為這可以獲得更精確的灰度資訊。為了相同的原因,使用高於8位深度(bit-depth)的影像(例如:使用uint2的影像(譯者注:灰度範圍0~65535)而不是byte(0~255)型別的影像)可以帶來更高的準確率。
      輸入影像的定義域決定了內部會使用哪一種演算法來處理影像。有三種可用的演算法:
      * 如果整個影像都是定義域(譯者注:可以理解為這張圖的每個畫素點都有灰度值),會使用最快的演算法。這被推薦使用在大多數的應用中。
      * 如果輸入的影像共享了相同的削減過的定義域,只有定義域內的畫素會被處理。這種模式會被用來排除影像上的某些區域。通常的,已知顯示出非朗伯反射特性或者不感興趣的區域會被排除,例如表面的孔洞。(譯者注:每張圖的定義域都是相同的)
      * 如果提供了包含清晰定義域的影像,每張影像上包含在範圍內的灰度值會被使用。只有在三張影像上擁有獨立的slant和tilt角度的畫素會被處理(譯者注:?only those pixels are processed that have independent slant and tilt angles in at least three images)。這種模式在某些情況下是合適的,例如在影像處理時排除個別影像上的特別的區域。這些區域可能是已知的表現出非朗伯反射特性的區域或者包含了偏光資訊的區域,例如影子。排除這些點可以導致更準確的結果。請注意,最後一種模式與前兩種相比,顯著需要更多的處理時間。(譯者注:這種情況下每張圖片的定義域都有可能不同)

    • 輸出圖片
      這個運算元輸出了重建影像的梯度,反射率,和表面的高度場影像。
      * 梯度影像是一個向量場,包含了表面的偏導數。記住,梯度可以被用作運算元 reconstruct_height_field_from_gradient 的輸入引數。為了更直觀的目的,替代表面梯度,可以返回標準化之後的表面梯度。為了達到這樣的目的,‘ResulltType‘ 必須被設定為 normalized_gradient 而不是 gradient。這裡,行和列元素代表了標準化之後的行和列。如果 ResultType被設定為了 all ,就會使用gradient 而不是 normalized_gradient 。
      * 反射率影像描述了反射輻射和入射輻射的比例,數值在1(白色表面)-0(黑色表面)之間。因此,反射率是表面的一個特徵。舉個例子,對一個印刷表面來說,反射率與把所有入射光排除在外(陰影,明暗)的印刷圖片有關。
      * 高度場影像的每個畫素與相對高度相關。

    預設情況下,上面這些物件都會返回,也就是說,引數ResultType設定為all。在只需要某些結果的情況下,這個引數可以設定為陣列,僅將一些需要的值放在其中,可以放的值有‘gradient‘, ‘albedo‘, 和 ‘height_field‘。記住,在特定的應用中,像表面檢測任務,只有梯度和反射率影像是有需要的。這裡,不構建高度場影像可以顯著得增快重建的速度。
    記住,在光度立體法內部,最先計算出梯度值,如果有需要,結合這些值來獲取高度場。這個結合操作與 reconstruct_height_field_from_gradient 使用的是相同的演算法,他們可以通過引數ReconstructionMethod, GenParamName, 和 GenParamValue進行控制。請參閱reconstruct_height_field_from_gradient的幫助來獲取更多關於這些引數的資訊。如果ResultType中沒有height_field,那麼這幾個引數會被忽略。

  • 注意
    photometric_stereo基於方形畫素的假定。此外,它假定在物體空間內,高度在步幅是1的格子上計算出來的。如果不是這種情況,相機的畫素投射到物體表面不是1,返回的高度場必須乘上實際的步長(畫素尺寸投射都物體空間的值)。畫素在物體空間的尺寸通過相機中的畫素尺寸除以被鏡頭放大的倍數得到。

  • 執行資訊
    • 多執行緒型別:可重入(可以和非排他性運算元並行執行)
    • 多執行緒作用域:全域性(可能在任意執行緒中呼叫)
    • 在內部資料層級上自動並行處理
  • 引數
    略。

  • 結果
    如果引數是有效的,返回2。如果有必要,會丟擲異常。

  • 可能的前調函式
    optimize_fft_speed

  • 所屬模組
    三維計量

圖片來源於官方文件

 

* 該示例通過使用光度立體技術檢測藥片包裝背面的缺陷
* 輸入是4張不同的藥片包裝背面圖片,光從不同的角度照射

* Initialization
dev_close_window ()
dev_update_off ()
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
Message := 'Inspect the backside of a blister'
Message[1] := 'using photometric stereo. In this case four'
Message[2] := 'different light orientations were used.'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 
* Show input images with different illumination
* 1 讀影像,依次讀取多張影像
* 下面的for迴圈,依次顯示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
* 
* Apply photometric stereo to determine the albedo
* and the surface gradient.
* 2. 應用光度立體得到反照率影像和表面梯度影像

* 描述了從影像中心指向右側的方向與投射到平面中的光的方向之間的角度。 
* 也就是說,當觀察影像(或相應的場景)時,傾斜角度為0表示光線來自右側,
* 傾斜角度為90表示光線來自頂部,傾斜角度為180表示 光是從左邊來的
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', [], [])
* 
* Display the albedo image
* 顯示反照率影像
dev_display (Albedo)
disp_message (WindowHandle, 'Albedo image', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 
* Calculate the gaussian curvature of the surface
* using the gradient field as input for the operator
* 3. 使用之前得到的表面梯度,計算表面的高斯曲率,得到高斯曲率影像
* derivate_vector_field.
* Defects are usually easy to detect in the curvature image.
* 在曲率影像上能更容易的進行檢測
* 該運算元通過之前得到的表面梯度得到高斯曲率影像
derivate_vector_field (Gradient, GaussCurvature, 1, 'gauss_curvature')
* 
* Detect defects
* 檢測缺陷
* 
* Segment the tablet areas in the curvature image
* 4. 對高斯曲率影像進行預處理和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
* 5. 接下來在高斯曲率影像中標記缺陷區域
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
* 6. 在反照率影像中標記出缺陷
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')

 

相關文章