1.簡單閾值
使用的函數:cv2.threshold (src, thresh, maxval, type)
注釋:
與名字一樣,這種方法非常簡單。但像素值高於閾值時,我們給這個像素賦予一個新值(可能是白色),否則我們給它賦予另外一種顏色(也許是黑色)。這個函數就是cv2.threshhold()。這個函數的第一個參數就是原圖像,原圖像應該是灰度圖。第二個參數就是用來對像素值進行分類的閾值。第三個參數就是當像素值高於(有時是小於)閾值時應該被賦予的新的像素值。OpenCV提供了多種不同的閾值方法,這是有第四個參數來決定的。這些方法包括:
• cv2.THRESH_BINARY
• cv2.THRESH_BINARY_INV
• cv2.THRESH_TRUNC
• cv2.THRESH_TOZERO
• cv2.THRESH_TOZERO_INV
代碼:
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('test.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()
運行結果如下圖所示:
2.自適應閾值
使用的函數:dst = cv2.adaptiveThreshold(src, maxval, thresh_type, type, Block Size, C)
注釋:
在前面的部分我們使用是全局閾值,整幅圖像采用同一個數作為閾值。當時這種方法並不適應與所有情況,尤其是當同一幅圖像上的不同部分的具有不同亮度時。這種情況下我們需要采用自適應閾值。此時的閾值是根據圖像上的每一個小區域計算與其對應的閾值。因此在同一幅圖像上的不同區域采用的是不同的閾值,從而使我們能在亮度不同的情況下得到更好的結果。這種方法需要我們指定三個參數,返回值只有一個。
• Adaptive Method- 指定計算閾值的方法。
– cv2.ADPTIVE_THRESH_MEAN_C:閾值取自相鄰區域的平
均值
– cv2.ADPTIVE_THRESH_GAUSSIAN_C:閾值取值相鄰區域
的加權和,權重為一個高斯窗口。
• Block Size - 鄰域大小(用來計算閾值的區域大小)。
• C - 這就是是一個常數,閾值就等於的平均值或者加權平均值減去這個常
數。
代碼:
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('test.jpg', 0) #中值濾波 img = cv2.medianBlur(img, 5) ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_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', 'Adaptivw 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 二值化
在第一部分中我們提到過retVal,當我們使用Otsu 二值化時會用到它。那么它到底是什么呢?在使用全局閾值時,我們就是隨便給了一個數來做閾值,那我們怎么知道我們選取的這個數的好壞呢?答案就是不停的嘗試。如果是一副雙峰圖像(簡單來說雙峰圖像是指圖像直方圖中存在兩個峰)呢?我們豈不是應該在兩個峰之間的峰谷選一個值作為閾值?這就是Otsu 二值化要做的。簡單來說就是對一副雙峰圖像自動根據其直方圖計算出一個閾值。(對於非雙峰圖像,這種方法得到的結果可能會不理想)。這里用到到的函數還是cv2.threshold(),但是需要多傳入一個參數(flag):cv2.THRESH_OTSU。這時要把閾值設為0。然后算法會找到最優閾值,這個最優閾值就是返回值retVal。如果不使用Otsu 二值化,返回的retVal 值與設定的閾值相等。
下面的例子中,輸入圖像是一副帶有噪聲的圖像。第一種方法,我們設127 為全局閾值。第二種方法,我們直接使用Otsu 二值化。第三種方法,我們首先使用一個5x5 的高斯核除去噪音,然后再使用Otsu 二值化。看看噪音去除對結果的影響有多大吧。
代碼:
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('test.jpg', 0) ret,th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) ret,th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) 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, blur, 0, th3] titles = ['Original Noisy Images', '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()
結果如圖所示:
使用的原圖如下: