1. 程式人生 > 其它 >OpenCV-Python系列之OTSU演算法

OpenCV-Python系列之OTSU演算法

上一個教程中,我們談到了關於影象二值化的兩種方法,一種是固定閾值法,另一種是自適應閾值法,總的來說,自適應閾值法在某些方面要由於固定閾值法,但還沒完,這次我們將隆重介紹我們的重量級選手,也就是OTSU演算法(又稱為大津演算法和最大類間方差法)。

最大類間方差法是1979年由日本學者大津提出的,是一種自適應閾值確定的方法,又叫大津法,簡稱OTSU,是一種基於全域性的二值化演算法,它是根據影象的灰度特性,將影象分為前景和背景兩個部分。當取最佳閾值時,兩部分之間的差別應該是最大的,在OTSU演算法中所採用的衡量差別的標準就是較為常見的最大類間方差。前景和背景之間的類間方差如果越大,就說明構成影象的兩個部分之間的差別越大,當部分目標被錯分為背景或部分背景被錯分為目標,都會導致兩部分差別變小,當所取閾值的分割使類間方差最大時就意味著錯分概率最小。

OSTU原理

在大津演算法中,我們窮舉搜尋能使類內方差最小的閾值,定義為兩個類的方差的加權和:

權重 是被閾值 t分開的兩個類的概率,而 是這兩個類的方差

大津證明了最小化類內方差和最大化類間方差是相同的:

用類概率 和類均值 來表示。

類概率 用閾值為t 的直方圖計算:

而類均值 為:

類概率和類均值可以迭代計算,大津演算法得出了0:1範圍上的一個閾值。這個閾值用於影象中出現的畫素強度的動態範圍。例如,若影象只包含155到255之間的畫素強度,大津閾值0.75會對映到灰度閾值230(而不是192,因為影象包含的畫素不是0–255全範圍的)。

對於影象I(x,y),前景(即目標)和背景的分割閾值記作T,屬於前景的畫素點數佔整幅影象的比例記為ω0,其平均灰度μ0;背景畫素點數佔整幅影象的比例為ω1,其平均灰度為μ1。影象的總平均灰度記為μ,類間方差記為g。

假設影象的背景較暗,並且影象的大小為M×N,影象中畫素的灰度值小於閾值T的畫素個數記作N0,畫素灰度大於閾值T的畫素個數記作N1,則有:

      (1) ω0=N0/ (M×N)

      (2) ω1=N1/ (M×N)

      (3) N0 + N1 = M×N

      (4) ω0 + ω1 = 1

      (5) μ = ω0 * μ0 + ω1 * μ1

      (6) g = ω0 * (μ0 - μ)2 + ω1 * (μ1 - μ)2

將式(5)代入式(6),得到等價公式:

      (7) g = ω0 *ω1 * (μ0 - μ1)2

採用遍歷的方法得到使類間方差g最大的閾值T。

OTSU演算法的實現

OTSU使用於雙峰影象,固定閾值化通常適用的影象的灰度化直方圖是單峰的:

而如果碰到了這種直方圖的影象,那麼就會過濾掉極為重要的資訊:

OTSU適用於這種雙峰圖片,它可以自己尋找最優閾值,為了表現測試的效果,我們找了一張雙峰的圖片:

首先使用固定閾值法進行實驗:

import cv2 as cv
import matplotlib.pyplot as plt

img = cv.imread('sh.jpg',0)
ret,threshold = cv.threshold(img,60,127,cv.THRESH_BINARY)
cv.imshow("res",threshold)
cv.waitKey(0)

我們再用OTSU的方法實驗一下:

import cv2 as cv
import matplotlib.pyplot as plt

img = cv.imread('sh.jpg',0)
ret,threshold = cv.threshold(img,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
cv.imshow("res",threshold)
cv.waitKey(0)

關於程式碼,需要說明的是,我們在使用OTSU時,不需要設定閾值,只需要設定一個最小值0和最大值255,該演算法會自動尋找最優的閾值進行計算:

可以看到,效果還是比較不錯的,總結一下,OTSU的優缺點:

優點:演算法簡單,當目標與背景的面積相差不大時,能夠有效地對影象進行分割。

缺點:當影象中的目標與背景的面積相差很大時,表現為直方圖沒有明顯的雙峰,或者兩個峰的大小相差很大,分割效果不佳,或者目標與背景的灰度有較大的重疊時也不能準確的將目標與背景分開。

原因:該方法忽略了影象的空間資訊,同時將影象的灰度分佈作為分割影象的依據,對噪聲也相當敏感。

天道酬勤 循序漸進 技壓群雄