Halcon閾值化算子dual_threshold和var_threshold的理解


Halcon中閾值二值化的算子眾多,通常用得最多的有threshold、binary_threshold、dyn_threshold等。

 

threshold是最簡單的閾值分割算子,理解最為簡單;binary_threshold是自動閾值算子,它可以自動選出暗(dark)的區域,或者自動選出亮(light)的區域,理解起來也沒有難度。

 

動態閾值算子dyn_threshold理解起來稍微復雜一點,使用dyn_threshold算子的步驟基本是這樣的:

① 將原圖進行濾波平滑處理。

② 用原圖和平滑后的圖逐個像素做比較,它可以根據參數分割出原圖比平滑后的圖灰度高(或者低)若干個灰度值的區域。

舉例如下:

處理程序是這樣的:

1 read_image (Image, 'C:/Users/happy xia/Desktop/dynPic.png')
2 mean_image (Image, ImageMean, 9, 9) 3 dyn_threshold (Image, ImageMean, RegionDynThresh, 10, 'dark')

程序分析:本例中,將圖片模糊后,點陣字的黑色擴散了,隨之就是字的黑色不如原圖那么黑了,那么通過給定的限值“10”和“dark”,就可以將原圖比模糊后的圖暗10個灰階以上的區域(即黑色文字部分)選出來了。

 

 以上所說的三個算子並不是本文的重點,但卻是理解下面的兩個閾值分割算子的准備知識。

 

1、dual_threshold

先看程序和效果圖再分析。

 

1 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
2 dual_threshold (Image, RegionCrossings, 174, 200, 180)

dual_threshold(Image : RegionCrossings : MinSize, MinGray, Threshold : )

該算子簽名中:Threshold 表示用於分割的閾值數值,MinSize表示分割出來的區域的最小面積(即數像素的數目個數),MinGray表示分割出來的區域對應的原圖中圖像像素的最高灰度不能低於MinGray設定值。

 

注意圖中藍色矩形小色塊的面積是175個像素,因此當MinSize = 174時,它可以被分割出來。

 

OK,我知道這么說比較拗口。下面我邊改變參數邊觀察效果圖,並做簡要分析:

1 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
2 dual_threshold (Image, RegionCrossings, 176, 200, 180)

效果圖如下:

由於最小面積設置為176,那么面積為175像素的矩形小色塊就沒有被分割出來。

 

再來改變MinGray參數:

1 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
2 dual_threshold (Image, RegionCrossings, 176, 216, 180)

此時觀察到,最右邊那個齒輪本來分割出來的區域沒有了!

 

通過取色器觀察可知,這塊區域最亮的灰度大概比211高一點點。

 

我們把這個值略微調低再看看:

1 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
2 dual_threshold (Image, RegionCrossings, 176, 210, 180)

最右邊那個齒輪右下角那一塊又被分割出來了!

 

相信通過這樣參數的反復調節,大家已經徹底明白了dual_threshold算子的意義和用法。

 

我們看這個算子的名稱——dual是“雙”的意思,也就是雙閾值。如果我們讓參數列表中的MinGray = Threshold,那就是單閾值了。

1 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
2 dual_threshold (Image, RegionCrossings, 176, 180, 180)

這個算子是很高效的。如果要完成上面這個程序這樣的功能,用threshold算子的話,代碼要這樣寫:

1 read_image (Image, 'C:/Users/happy xia/Desktop/2.png')
2 threshold (Image, Region, 180, 255)
3 connection (Region, ConnectedRegions)
4 select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 176, 9999999)

也就是說dual_threshold一條算子頂這三條算子。

 

dual_threshold算子的缺陷:它只能分割出灰度值高的亮區域,不能分割出灰度值低的暗區域。

 

下面介紹var_threshold算子。

 

2、var_threshold

 

先看var_threshold算子的簽名:

var_threshold(Image : Region : MaskWidth, MaskHeight, StdDevScale, AbsThreshold, LightDark : )

MaskWidth、 MaskHeight是用於濾波平滑的掩膜單元;StdDevScale是標准差乘數因子(簡稱標准差因子);AbsThreshold是設定的絕對閾值;LightDark有4個值可選,'light'、'dark'、'equal'、'not_equal'

 

需要強調的是var_threshold算子和dyn_threshold算子極為類似。不同的是var_threshold集成度更高,並且加入了“標准差×標准差因子”這一變量。

舉例:

1 read_image (Image, 'C:/1.png')
2 var_threshold (Image, Region, 4, 4, 0.2, 12, 'dark')

在該程序中,先用4×4的掩膜在圖像上逐像素游走,用原圖中的當前像素和對應掩膜中16個像素的灰度均值對比,找出暗(dark)的區域。當原圖像素灰度比對應的掩膜灰度均值低(0.2,12)個灰階時,該區域被分割出來。本程序中StdDevScale = 0.2, AbsThreshold = 12,問題的關鍵就是理解如何通過StdDevScaleAbsThreshold來確定用於分割的閾值。

 

var_threshold的幫助文檔中是這么寫的:

說明:

1、d(x,y)指的是遍歷每個像素時,掩膜覆蓋的那些像素塊(本例中是4×4 = 16個像素)灰度的標准差;StdDevScale 是標准差因子。

2、當標准差因子StdDevScale ≥ 0 時,v(x,y) 取(StdDevScale ×標准差)和AbsThreshold 中較大的那個。

3、當標准差因子StdDevScale < 0 時,v(x,y) 取(StdDevScale ×標准差)和AbsThreshold 中較小的那個。實測發現,這里的比較大小是帶符號比較,由於標准差是非負數,當StdDevScale < 0 時,(StdDevScale ×標准差)≤ 0恆成立。所以此時的取值就是(StdDevScale ×標准差)。

 

文檔是這么說的:

If StdDevScale*dev(x,y) is below AbsThreshold for positive values of StdDevScale or above for negative values StdDevScale, AbsThreshold is taken instead.

大致意思是:

當StdDevScale為正時,如果StdDevScale*dev(x,y) 低於 AbsThreshold,則采用AbsThreshold。

當StdDevScale為負時,如果StdDevScale*dev(x,y) 高於 AbsThreshold,則采用AbsThreshold。

 

我找了一塊黑白過渡處4×4的像素塊,求得它的灰度標准差為51.16(或49.53):

 

幫助文檔中StdDevScale 的推薦值范圍是-1~1,一般通過上面的例子可知,一般的明顯的黑白過度處的標准差在50左右,乘以StdDevScale即-50 ~ 50 ,50的灰度差異,對於分割來說一般是夠了的。

文檔還說:推薦的值是0.2,如果參數StdDevScale太大,可能分割不出任何東西;如果參數StdDevScale太小(例如-2),可能會把整個圖像區域全部輸出,也就說達不到有效分割的目的。(……with 0.2 as a suggested value. If the parameter is too high or too low, an empty or full region may be returned.)

 

最后再看看是怎么分割像素的:

 

其中g(x,y)指的是原始圖像當前像素的灰度值;m(x,y)指的是遍歷像素時,掩膜覆蓋的像素的平均灰度值(mean)。

LightDark = ‘dark’為例,當滿足m(x,y) - g(x,y) ≥ v(x,y)時(即原始圖像對應像素灰度比掩膜像素灰度均值低v(x,y)個灰度值以上),相應的灰度值低的暗像素被分割出來。

 

最后看幾個例子體會一下:(對比之前的例子var_threshold (Image, Region, 4, 4, 0.2, 12, 'dark')的效果)

① 將AbsThreshold 由12改成30,此時分割出的區域變小。

1 read_image (Image, 'C:/1.png')
2 var_threshold (Image, Region, 4, 4, 0.2, 30, 'dark')

 

② AbsThreshold 保持12不變,將StdDevScale由0.2改成0.7,此時分割出的區域變小。

 

③ 將參數改為var_threshold (Image, Region, 4, 4, -0.01, 12, 'dark'),此時分割出的區域大大增加,由前面的分析可知,此時參數AbsThreshold = 12無效,事實上,此時將AbsThreshold 改為1、50甚至200都對最終結果沒有任何影響。

 

通過本人的分析,我認為StdDevScale取負值意義不大,因為它會分割出大量的不需要的區域,故一般推薦使用該算子時,StdDevScale取正值。

 

需要強調的是:在黑白過渡處,一般掩膜覆蓋的像素的標准差較大,而在其他平緩的地方,標准差較小;因此最終采用的分割閾值隨着掩膜在不斷遍歷像素的過程中,在(StdDevScale×標准差)和AbsThreshold 之間不斷切換。

 

var_threshold和dyn_threshold的區別和聯系:

 

dyn_threshold是將原圖和濾波平滑后的圖對比,var_threshold是將原圖和對應像素掩膜覆蓋的像素的平均灰度值對比。

在算子var_threshold中,如果參數StdDevScale = 0,那么就可以用動態閾值的方式非常近似地模擬。以下兩種算法的效果極為類似:

1 read_image (Image, 'C:/1.png')
2 var_threshold (Image, Region, 4, 4, 0, 12, 'dark')
1 read_image (Image, 'C:/1.png')
2 mean_image (Image, ImageMean, 4, 4)
3 dyn_threshold (Image, ImageMean, RegionDynThresh, 12, 'dark')

兩種方法的效果圖:

 

那么當StdDevScale > 0 時,var_threshold對比dyn_threshold還存在什么優點呢?我認為是在黑白過渡處能減少分割出不需要的區域的概率。(因為黑白過渡處標准差大,當然前提是StdDevScale 不能設置得太小)

 

(網上關於這兩個算子的系統介紹很少,我的理解難免有不足之處,歡迎大家回復討論)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM