【CV】基于閾值處理的圖像分割算法!
圖像處理
Author:louwill
Machine Learning Lab
? ? ?
基于閾值的圖像分割因其處理直觀、實(shí)現(xiàn)簡(jiǎn)單和計(jì)算速度快,是一種更為常用的傳統(tǒng)圖像分割算法。本文基于圖像灰度閾值處理的基本原理,對(duì)全局閾值處理方法和大津法進(jìn)行介紹,并用一些圖像實(shí)例進(jìn)行展示。
灰度閾值基礎(chǔ)
給定灰度圖像,假設(shè)該圖像有目標(biāo)物體和背景像素所構(gòu)成,現(xiàn)在要從圖像中提取目標(biāo)物體,一個(gè)最為直接的方法就是使用一個(gè)固定閾值將目標(biāo)物體像素與背景像素分開(kāi),以區(qū)域?yàn)槟繕?biāo)物體區(qū)域,否則為背景區(qū)域。
那么什么樣的圖像容易用閾值法進(jìn)行分割呢?簡(jiǎn)單來(lái)說(shuō),就是目標(biāo)區(qū)域與背景區(qū)域具有較大圖像灰度差異時(shí),用閾值法分割效果可能會(huì)比較好。這種較大的圖像灰度差異體現(xiàn)到圖像直方圖上時(shí),就呈現(xiàn)處圖像灰度直方圖雙峰的特征。如圖1所示。

圖1 雙峰圖像直方圖
圖像使用閾值分割方法取得好的分割效果取決于如下關(guān)鍵因素:
直方圖波峰之間的間隔; 圖像的噪聲情況; 目標(biāo)物體和背景的相對(duì)尺寸; 圖像光源的均勻性; 圖像反射的均勻性。
全局閾值處理
當(dāng)圖像中存在較大的灰度變化時(shí),使用全局閾值處理的方法一般就能夠取得較好的效果。但我們?nèi)韵M麑?duì)于一幅圖像,能夠找到一個(gè)相對(duì)合理的閾值來(lái)作為全局閾值。因而就有迭代的閾值圖像分割算法。算法流程如下:
初始化全局閾值 基于分割該圖像,產(chǎn)生兩組像素:由灰度值大于的像素組成,由灰度值小于等于的像素組成 對(duì)和像素分別計(jì)算平均灰度值和 計(jì)算一個(gè)新的閾值 重復(fù)第2到第4步,直到連續(xù)迭代中的值間的差小于一個(gè)預(yù)定的參數(shù)為止。
下面來(lái)看一個(gè)使用全局閾值的圖像分割例子。直接讀入圖像,先基于Numpy進(jìn)行灰度化和二值化處理。
img?=?cv2.imread('./harden.png')
#?灰度化
y?=?0.2126*img[:,:,2]?+?0.7152*img[:,:,1]?+?0.0722*img[:,:,0]
img[:,:,0]?=?y
img[:,:,1]?=?y
img[:,:,2]?=?y
#?以128為閾值進(jìn)行二值化
y[y>=128]?=?255
y[y<128]?=?0
img[:,:,0]?=?y
img[:,:,1]?=?y
img[:,:,2]?=?y
plt.imshow(img);
原圖和分割效果分別如圖2和3所示。

圖2?原圖

圖3 全局閾值分割效果圖
opencv也提供了全局閾值的分割方法,處理代碼如下:
import?cv2
import?numpy?as?np
from?matplotlib?import?pyplot?as?plt
img?=?cv2.imread('harden.png',?0)
img?=?cv2.cvtColor(img,?cv2.COLOR_BGR2RGB)
ret,?thresh1?=?cv2.threshold(img,?128,?255,?cv2.THRESH_BINARY)
plt.imshow(thresh1);
分割效果如圖4所示。

圖4 opencv閾值法分割
大津法(OTSU)
基于閾值的圖像二值化方法的一個(gè)關(guān)鍵在于如何選定閾值,這可以視作為一個(gè)全局尋優(yōu)問(wèn)題。大津法也即OTSU法,是由日本學(xué)者大津展之于1979年提出的一種圖像閾值分割方法。該方法將閾值劃分視作是一個(gè)統(tǒng)計(jì)決策問(wèn)題,其目的在于將像素分配給兩組或多組的過(guò)程中使得引入的平均誤差最小。大津法給出的方案是使得兩組之間的類間方差最大時(shí)的閾值為最優(yōu)閾值。所以大津法也叫最大類間方差法。
先來(lái)看一下大津法的基本原理。假設(shè)劃分閾值為,小于閾值的像素區(qū)域?yàn)?span style="cursor:pointer;">,大于閾值的像素區(qū)域?yàn)?span style="cursor:pointer;">。和分別為被閾值分開(kāi)的兩類像素占總像素的比值。和分別為這兩個(gè)類像素均值,和分別為這兩個(gè)類中像素值的方差。
圖像的類內(nèi)方差和類間方差為:
圖像的整體方差為:
圖像的可分離度定義為:
最大化圖像分離度即可,所以使得:
最大化即可。
基于NumPy的大津法實(shí)現(xiàn)例子如下代碼所示。
img?=?cv2.imread('./harden.png')
img?=?img.astype(np.float)
H,?W,?C?=?img.shape
#?灰度化
out?=?0.2126*img[:,:,2]?+?0.7152*img[:,:,1]?+?0.0722*img[:,:,0]
out?=?out.astype(np.uint8)
#?初始化類間方差和最佳閾值
max_sigma?=?0
max_t?=?0
#?遍歷迭代
for?_t?in?range(1,?255):
????#?小于閾值t的類v0
????v0?=?out[np.where(out<_t)]
????#?計(jì)算v0均值
????M0?=?np.mean(v0)?if?len(v0)?>?0?else?0.
????#?v0類像素占比
????w0?=?len(v0)/(H*W)
????#?大于閾值t的類v1
????v1?=?out[np.where(out>=_t)]
????#?計(jì)算v1均值
????M1?=?np.mean(v1)?if?len(v1)?>?0?else?0.
????#?v1類像素占比
????w1?=?len(v1)/(H*W)
????#?類間方差
????Sb2?=?w0*w1*((M0-M1)**2)
????#?尋優(yōu)
????if?Sb2?>?max_sigma:
????????max_sigma?=?Sb2
????????max_t?=?_t
????????
#?打印最佳閾值????????
print(max_t)
通過(guò)大津法尋優(yōu)可知示例圖片的最佳劃分閾值為。然后以為閾值進(jìn)行二值化。效果如圖5所示。

圖5?大津法閾值分割
opencv中直接提供了大津法的實(shí)現(xiàn)方法,如下代碼所示。
img?=?cv2.imread('./harden.png')
#?灰度化
img?=?cv2.cvtColor(img,?cv2.COLOR_BGR2GRAY)
#?大津法閾值化處理
ret,?th?=?cv2.threshold(img,?0,?255,?cv2.THRESH_BINARY+cv2.THRESH_OTSU)
plt.imshow(th);
小結(jié)
本文對(duì)基于閾值的圖像分割方法進(jìn)行了簡(jiǎn)單的介紹,并給出了相應(yīng)的圖像實(shí)例。基于閾值的圖像分割方法簡(jiǎn)單直接,計(jì)算速度快,在圖像灰度差異較大的情況下,是首選的分割方法。但閾值分割方法本身也存在抗噪能力弱、使用條件嚴(yán)格等缺點(diǎn),所以往往會(huì)配合圖像濾波去噪等方法一起使用。
? ?參考資料
? ? [1]?數(shù)字圖像處理第四版
? ? [2]?https://opencv24-python-tutorials.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_thresholding/py_thresholding.html
往期精彩回顧 本站qq群851320808,加入微信群請(qǐng)掃碼:
