使用工具:Python3.5
使用庫:cv2
原始圖像

1.簡單閾值
cv2.threshold , cv2.adaptiveThreshold
當像素值高于閾值時,我們給這個像素賦予一個新值(可能是白色),否則我們給它賦予另外一種顏色(也許是黑色)。這個函數就是cv2.threshold()。這個函數的第一個參數就是原圖像,原圖像應該是灰度圖。第二個參數就是用來對像素值進行分類的閾值,第三個參數就是當像素值高于(或者小于)閾值時,應該被賦予新的像素值。OpenCV提供了多種不同的閾值方法,這是有第四個參數來決定的。方法包括:
cv2.THRESH_BINARY
cv2.THRESH_BINARY_INV
cv2.THRESH_TRUNC
cv2.THRESH_TOZERO
cv2.THRESH_TOZERO_INV

上圖摘選自《學習 OpenCV》中文版,其實這些在文檔中都有詳細介紹了,你也可以直接查看文檔。
這個函數有兩個返回值,第一個為retVal,后面會解釋,第二個就是閾值化之后的結果圖像了。
~~~
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('719100.jpg',0)
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()
~~~
為了在同一個窗口顯示更多的圖像,使用plt.subplot()。**這里不推薦plt顯示,由上圖可以看出,與原圖相差太多,具體原因暫未找出,以后找出會及時更新。**

2.自適應閾值
根據圖像上的每一個小區域計算與其對應的閾值。因此在同一幅圖像上的不同區域采用的是不同的閾值,從而使我們能在亮度不同的情況下得到更好的結果。
這種方法需要我們指定三個參數,返回值只有一個。
Adaptive Method 指定計算閾值的方法
-cv2.ADAPTIVE_THRESH_MEAN_C:閾值取自相鄰區域的平均值
-cv2.ADAPTIVE_THRESH_GAUSSIAN_C:閾值取自相鄰區域的加權和,權重為一個高斯窗口
Block Size 鄰域大小(用來計算閾值的區域大小)
C這就是一個常數,閾值就等于的平均值或者加權平均值減去這個常數
~~~
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('719100.jpg',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()
~~~
**這里不推薦plt顯示,由上圖可以看出,與原圖相差太多,具體原因暫未找出,以后找出會及時更新。**

3.Otsu's二值化
我們前面說到,cv2.threshold函數是有兩個返回值的,前面一直用的第二個返回值,也就是閾值處理后的圖像,那么第一個返回值(得到圖像的閾值)將會在這里用到。
前面對于閾值的處理上,我們選擇的閾值都是127,那么實際情況下,怎么去選擇這個127呢?有的圖像可能閾值不是127得到的效果更好。那么這里我們需要算法自己去尋找到一個閾值,而Otsu’s就可以自己找到一個認為最好的閾值。并且Otsu’s非常適合于圖像灰度直方圖具有雙峰的情況,他會在雙峰之間找到一個值作為閾值,對于非雙峰圖像,可能并不是很好用。那么經過Otsu’s得到的那個閾值就是函數cv2.threshold的第一個參數了。因為Otsu’s方法會產生一個閾值,那么函數cv2.threshold的的第二個參數(設置閾值)就是0了,并且在cv2.threshold的方法參數中還得加上語句cv2.THRESH_OTSU。
~~~
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('719100.jpg',0)
ret1,th1=cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret2,th2=cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
#(5,5)為高斯核的大小,0為標準差
blur= cv2.GaussianBlur(img,(5,5),0)
#閾值一定要設為0
ret3,th3=cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
images=[img,0,th1,
img,0,th2,
img,0,th3]
titles =['original noisy image','histogram','global thresholding(v=127)',
'original noisy image','histogram',"otsu's thresholding",
'gaussian giltered image','histogram',"otus's thresholding"]
#這里使用了pyplot中畫直方圖的方法,plt.hist要注意的是他的參數是一維數組
#所以這里使用了(numpy)ravel方法,將多維數組轉換成一維,也可以使用flatten方法
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()
~~~
**這里不推薦plt顯示,由上圖可以看出,與原圖相差太多,具體原因暫未找出,以后找出會及時更新。**
