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)