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

Halcon中閾值二值化的算子衆多,一般用得最多的有threshold、binary_threshold、dyn_threshold等。算法

 

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

 

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

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

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

舉例以下:blog

處理程序是這樣的:圖片

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個灰階以上的區域(即黑色文字部分)選出來了。文檔

 

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

 

一、dual_thresholdio

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

 

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算子。

 

二、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的幫助文檔中是這麼寫的:

說明:

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

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

三、當標準差因子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 改成一、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 不能設置得過小)

 

(網上關於這兩個算子的系統介紹不多,個人理解不免有不足之處,歡迎你們回覆討論)

相關文章
相關標籤/搜索