上一篇介紹了 Threshold。
它的概念很簡單,只要設定一個 Threshold。
就可以把圖片分成前景和背景。
不過真正困難的地方,是 Threshold 到底要設多少?
如果每張圖片都要慢慢調整,實際使用起來真的不是很方便。
而有一種方法,可以讓電腦自動決定門檻值。
就是今天要介紹的 Otsu's Thresholding。
還記得 Day 6 的 Histogram 嗎?
Histogram 告訴我們:每個亮度值,在圖片中出現了多少次。
假設有一張圖片,Histogram 可能長得像這樣。

左邊那座山可能是黑色文字,右邊那座山則可能是白色背景。
如果把 Threshold 放在左邊,很多文字可能被當成背景。
相反,如果放在右邊,又可能把背景誤判成文字。
而真正合理的位置,其實就是:
兩座山之間的低谷。
因為這裡剛好最容易把兩群 Pixel 分開。
這也是 Otsu 的核心想法。
Otsu 做的事情其實非常的簡單粗暴。
它會把每一個可能的 Threshold 都試一次。
例如:
0
1
2
...
254
255
每試一個 Threshold 就把圖片分成兩群。
然後評估 這兩群分得夠不夠開?
如果兩群非常容易區分,代表這個 Threshold 很好。
如果兩群還混在一起,則代表 Threshold 不理想。
最後會選出分離效果最好的那一個。
最佳 Threshold 的「最佳」,其實不是指任何圖片都完美。
而是 讓前景和背景的亮度分布,盡可能分開。
因此,如果 Histogram 本來就有兩座明顯的山。
Otsu 通常能找到很不錯的 Threshold。
OpenCV 已經內建 Otsu。
import cv2
import matplotlib.pyplot as plt
img = cv2.imread("dog.jpeg", cv2.IMREAD_GRAYSCALE)
threshold, binary = cv2.threshold(
img,
0,
255,
cv2.THRESH_BINARY + cv2.THRESH_OTSU
)
可以看到。
我們把 Threshold 設成了 0。
這不是因為 Threshold 等於 0。
而是因為真正的 Threshold 會由 OpenCV 自己計算。
最後它會把計算出的 Threshold 回傳。
print(threshold)
例如可能得到
137
代表 OpenCV 判斷 137 是這張圖片比較適合的 Threshold。
其實,雖然 Otsu 好用,但並不是任何情況都有效。
例如,如果整張圖片亮度很平均。
根本沒有明顯的兩群。
這時候,就算讓 Otsu 自己找,也很難找到真正理想的位置。
因此,Otsu 比較適合用在:
Day 6 學的 Histogram,其實不是只可以畫長條圖而已。
Histogram 的資訊,可以直接決定 Threshold。
也就是說 Otsu 並不是憑空猜測 Threshold 的數值,而是根據圖片的真實亮度分布找出最適合的切割點。
今天介紹了 Otsu's Thresholding。
它最大的特色就是不需要手動設定 Threshold。
它利用 Histogram,分析前景和背景的亮度分布,自動找出一個適合的門檻值。
不過它有一個重要前提,就是整張圖片的光線要比較一致。
如果圖片左邊很亮右邊很暗。
即便找到一個全域最佳 Threshold,也可能沒有辦法同時兼顧整張圖片。
那遇到這種情況,又該怎麼辦?
下一篇,我們就來介紹 Adaptive Threshold。
看看電腦如何讓不同區域使用不同的 Threshold。