opencv圖像閾值

1.簡單閥值cv2.threshold()

當像素值高于閥值時,我們給這個像素賦予一個新值(可能是白色),否則我們給它賦予另外一種顏色(也許是黑色)。這個函數(shù)就是cv2.threshold()。函數(shù)的第一個參數(shù)就是原圖像,原圖像應(yīng)該是灰度圖。第二個參數(shù)就是用來對像素值進行分類的閥值,第三個參數(shù)就是當像素值高于(有時小于)閥值時,應(yīng)該被賦予新的像素值。OpenCV提供了多種不同的閥值方法,這是由第四個參數(shù)來決定的。方法主要包括:

cv2.THRESH_BINARY

cv2.THRESH_BINARY_INV

cv2.THRESH_TRUNC

cv2.THRESH_TOZERO

cv2.THRESH_TOZERO_INV

img = cv2.imread('NBA.png')

ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)

ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)

ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)

ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)

titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']

images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6):

????plt.subplot(2,3,i+1)

????plt.imshow(images[i],'gray')

????plt.title(titles[i])

????plt.xticks([])

????plt.yticks([])

plt.show()


2.自適應(yīng)閾值???cv2.adaptiveThreshold()

在上面,我們使用全局值作為閾值。但是圖像在不同區(qū)域中具有不同亮度,用一樣的閾值處理,結(jié)果是不太良好的。在這種情況下,我們進行自適應(yīng)閾值處理。根據(jù)圖像上的每一個小區(qū)域計算與其對應(yīng)的閥值。因此在同一幅圖像上的不同區(qū)域采用的是不同的閥值,從而使我們能在亮度不同的情況下得到更好的結(jié)果。

這種方法需要我們指定三個參數(shù),返回值只有一個。

Adaptive Method 指定計算閥值的方法

? ? cv2.ADAPTIVE_THRESH_MEAN_C:閥值取自相鄰區(qū)域的平均值

? ? cv2.ADAPTIVE_THRESH_GAUSSIAN_C:閥值取自相鄰區(qū)域的加權(quán)和,權(quán)重為一個高斯窗口

Block Size 鄰域大小(用來計算閥值的區(qū)域大?。?/p>

C這就是一個常數(shù),閥值就等于的平均值或者加權(quán)平均值減去這個常數(shù)

img = cv2.imread('NBA.png',0)

img = cv2.medianBlur(img,5)? ?#中值濾波

ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

# 11為block size,2為C值

th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,2)

th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)

titles = ['Original Image', 'Global Thresholding (v = 127)', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']

images = [img, th1, th2, th3]

for i in range(4):

????plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')

????plt.title(titles[i])

????plt.xticks([]),plt.yticks([])

plt.show()


3.Otsu's二值化

我們前面說到,cv2.threshold函數(shù)是有兩個返回值的,前面一直用的第二個返回值,也就是閾值處理后的圖像,那么第一個返回值(得到圖像的閾值)將會在這里用到。

前面對于閾值的處理上,我們選擇的閾值都是127,那么實際情況下,怎么去選擇這個127呢?有的圖像可能閾值不是127得到的效果更好。那么這里我們需要算法自己去尋找到一個閾值,而Otsu’s就可以自己找到一個認為最好的閾值。并且Otsu’s非常適合于圖像灰度直方圖具有雙峰的情況,他會在雙峰之間找到一個值作為閾值,對于非雙峰圖像,可能并不是很好用。那么經(jīng)過Otsu’s得到的那個閾值就是函數(shù)cv2.threshold的第一個參數(shù)了。因為Otsu’s方法會產(chǎn)生一個閾值,那么函數(shù)cv2.threshold的的第二個參數(shù)(設(shè)置閾值)就是0了,并且在cv2.threshold的方法參數(shù)中還得加上語句cv2.THRESH_OTSU

img = cv2.imread('rectangle.jpg',0)? #建議找一張簡單點的圖片,這樣更容易看出不同的地方在哪里

# global thresholding

ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

# Otsu's thresholding

ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering

blur = cv2.GaussianBlur(img,(5,5),0)

ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

# plot all the images and their histograms

images = [img, 0, th1, img, 0, th2, blur, 0, th3]

titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)', 'Original Noisy Image','Histogram',"Otsu's Thresholding", 'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]

for i in range(3):

????plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')

????plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])

????plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)

????plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])

????plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')

????plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])

plt.show()


上面演示Otsu二進制化的Python實現(xiàn),以顯示它實際上是如何工作的。如果你不感興趣,你可以跳過這個。

由于我們正在處理雙峰圖像,Otsu的算法試圖找到閾值( t ),該閾值最小化由以下關(guān)系式給出的加權(quán)類內(nèi)方差:


它實際上找到位于兩個峰值之間的t值,使得兩個類別的方差最小。它可以簡單地用Python實現(xiàn),如下所示:

img = cv2.imread('NBA.jpg',0)

blur = cv2.GaussianBlur(img,(5,5),0)

# find normalized_histogram, and its cumulative distribution function

hist = cv2.calcHist([blur],[0],None,[256],[0,256])

hist_norm = hist.ravel()/hist.max()

Q = hist_norm.cumsum()

bins = np.arange(256)

fn_min = np.inf

thresh = -1

for i in range(1,256):

????p1,p2 = np.hsplit(hist_norm,[i]) # probabilities

????q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes

????b1,b2 = np.hsplit(bins,[i]) # weights?

????# finding means and variances

????m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2

????v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2

????# calculates the minimization function

????fn = v1*q1 + v2*q2

????if fn < fn_min:

????????fn_min = fn

????????thresh = i

# find otsu's threshold value with OpenCV function

ret, otsu = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

print(thresh,ret)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容