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,問題的關鍵就是理解如何經過StdDevScale和AbsThreshold來肯定用於分割的閾值。
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 不能設置得過小)
(網上關於這兩個算子的系統介紹不多,個人理解不免有不足之處,歡迎你們回覆討論)