1.簡單閥值cv2.threshold()
當(dāng)像素值高于閥值時(shí)字管,我們給這個(gè)像素賦予一個(gè)新值(可能是白色)拓诸,否則我們給它賦予另外一種顏色(也許是黑色)蒙秒。這個(gè)函數(shù)就是cv2.threshold()。函數(shù)的第一個(gè)參數(shù)就是原圖像剃幌,原圖像應(yīng)該是灰度圖聋涨。第二個(gè)參數(shù)就是用來對(duì)像素值進(jìn)行分類的閥值,第三個(gè)參數(shù)就是當(dāng)像素值高于(有時(shí)小于)閥值時(shí)负乡,應(yīng)該被賦予新的像素值。OpenCV提供了多種不同的閥值方法脊凰,這是由第四個(gè)參數(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é)果是不太良好的。在這種情況下朝捆,我們進(jìn)行自適應(yīng)閾值處理般渡。根據(jù)圖像上的每一個(gè)小區(qū)域計(jì)算與其對(duì)應(yīng)的閥值。因此在同一幅圖像上的不同區(qū)域采用的是不同的閥值芙盘,從而使我們能在亮度不同的情況下得到更好的結(jié)果驯用。
這種方法需要我們指定三個(gè)參數(shù),返回值只有一個(gè)儒老。
Adaptive Method 指定計(jì)算閥值的方法
? ? cv2.ADAPTIVE_THRESH_MEAN_C:閥值取自相鄰區(qū)域的平均值
? ? cv2.ADAPTIVE_THRESH_GAUSSIAN_C:閥值取自相鄰區(qū)域的加權(quán)和蝴乔,權(quán)重為一個(gè)高斯窗口
Block Size 鄰域大小(用來計(jì)算閥值的區(qū)域大型苑)
C這就是一個(gè)常數(shù)薇正,閥值就等于的平均值或者加權(quán)平均值減去這個(gè)常數(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ù)是有兩個(gè)返回值的挖腰,前面一直用的第二個(gè)返回值,也就是閾值處理后的圖像练湿,那么第一個(gè)返回值(得到圖像的閾值)將會(huì)在這里用到曙聂。
前面對(duì)于閾值的處理上,我們選擇的閾值都是127鞠鲜,那么實(shí)際情況下宁脊,怎么去選擇這個(gè)127呢?有的圖像可能閾值不是127得到的效果更好贤姆。那么這里我們需要算法自己去尋找到一個(gè)閾值榆苞,而Otsu’s就可以自己找到一個(gè)認(rèn)為最好的閾值。并且Otsu’s非常適合于圖像灰度直方圖具有雙峰的情況霞捡,他會(huì)在雙峰之間找到一個(gè)值作為閾值坐漏,對(duì)于非雙峰圖像,可能并不是很好用碧信。那么經(jīng)過Otsu’s得到的那個(gè)閾值就是函數(shù)cv2.threshold的第一個(gè)參數(shù)了赊琳。因?yàn)镺tsu’s方法會(huì)產(chǎn)生一個(gè)閾值,那么函數(shù)cv2.threshold的的第二個(gè)參數(shù)(設(shè)置閾值)就是0了砰碴,并且在cv2.threshold的方法參數(shù)中還得加上語句cv2.THRESH_OTSU躏筏。
img = cv2.imread('rectangle.jpg',0)? #建議找一張簡單點(diǎn)的圖片,這樣更容易看出不同的地方在哪里
# 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二進(jìn)制化的Python實(shí)現(xiàn)呈枉,以顯示它實(shí)際上是如何工作的趁尼。如果你不感興趣埃碱,你可以跳過這個(gè)。
由于我們正在處理雙峰圖像酥泞,Otsu的算法試圖找到閾值( t )砚殿,該閾值最小化由以下關(guān)系式給出的加權(quán)類內(nèi)方差:
在
它實(shí)際上找到位于兩個(gè)峰值之間的t值,使得兩個(gè)類別的方差最小芝囤。它可以簡單地用Python實(shí)現(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)