opencv——threshold閾值處理、自適應閾值處理、otsu處理(大津法) ...
threshold函數
retval, dst = cv2.threshold(src, thresh, maxval, type) ''' retval:返回的閾值;dst:閾值分割結果圖像 src:輸入圖像 thresh:閾值;maxval:需設定的最大值 type:閾值分割類型 '''
簡單的閾值分割類型有:
- cv.THRESH_BINARY
- cv.THRESH_BINARY_INV
- cv.THRESH_TRUNC
- cv.THRESH_TOZERO
- cv.THRESH_TOZERO_INV
1 import matplotlib.pyplot as plt 2 import numpy as np 3 import cv2 as cv 4 5 img = cv.imread(r'Lena.png') 6 imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) 7 t1, rst1 = cv.threshold(imgray,127,255,cv.THRESH_BINARY) # 二值化閾值處理。大於127的像素點會被處理為255,其餘處理為0 8 t2, rst2 = cv.threshold(imgray,127,255,cv.THRESH_BINARY_INV) # 反二值化閾值處理。灰度值大於127的像素點處理為0,其餘為255 9 t3, rst3 = cv.threshold(imgray,127,255,cv.THRESH_TRUNC) # 截斷閾值化處理。大於127的像素點處理為127,其餘保持不變 10 t4, rst4 = cv.threshold(imgray,127,255,cv.THRESH_TOZERO_INV) # 超閾值零處理。大於127的像素點處理為0,其餘保持不變 11 t5, rst5 = cv.threshold(imgray,127,255,cv.THRESH_TOZERO) # 低閾值零處理。大於127的像素點保持不變,其餘處理為0 12 titles = ['Original','BINARY','BINARY_INV','TRUNC','TOZERO_INV','TOZERO'] 13 images = [imgray,rst1,rst2,rst3,rst4,rst5] 14 for i in range(6): 15 plt.subplot(2,3,i+1), plt.imshow(images[i],'gray') 16 plt.title(titles[i]) 17 plt.xticks([]), plt.yticks([]) 18 plt.show()
效果圖
自適應閾值處理
上述閾值處理對於色彩均衡的圖像來說結果較為理想,但對於色彩不均衡的圖像來說,只使用一個閾值,無法得到較理想的閾值分割結果。自適應閾值處理通過計算每個像素點周圍臨近的加權平均值獲得閾值,能夠更好的處理由光照變化帶來影響的圖像。
dst = cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C) ''' src:輸入圖像。該圖像須是8位單通道圖像 maxValue:最大值 adaptiveMethod:自適應方法 thresholdType:閾值處理方式 blockSize:像素在計算其閾值時參考的鄰域尺寸大小,通常為3,5,7 C:常量 '''
閾值處理方法須為 cv2.THRESH_BINARY 或 cv2.THRESH_BINARY_INV
自適應方法有 cv2.ADAPTIVE_THRESH_MEAN_C 和 cv2.ADAPTIVE_THRESH_GAUSSIAN_C 。前者領域所有像素點的權重值一致;後者與鄰域各個像素點到中心點的距離有關,通過高斯方程獲得各點的權重。
1 import matplotlib.pyplot as plt 2 import numpy as np 3 import cv2 as cv 4 5 img = cv.imread(r'exc.png') 6 imgray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) 7 t, rst = cv.threshold(imgray,127,255,cv.THRESH_BINARY) 8 athdMEAN = cv.adaptiveThreshold(imgray,255,cv.ADAPTIVE_THRESH_MEAN_C,cv.THRESH_BINARY,5,3) 9 athdGAUS = cv.adaptiveThreshold(imgray,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY,5,3) 10 titles = ['Original','Glbal Thresholding(v=127)','AdaptiveMean','AdaptiveGaussian'] 11 images = [imgray,rst,athdMEAN,athdGAUS] 12 for i in range(4): 13 plt.subplot(2,2,i+1) 14 plt.imshow(images[i],'gray') 15 plt.title(titles[i]) 16 plt.xticks([]), plt.yticks([]) 17 plt.show()
對一幅圖像分別使用二值化閾值處理和自適應閾值處理,效果圖:
Otsu處理(大津法)
當我們有一個圖像,其像素值矩陣如下矩陣時,此時將閾值設置為127時閾值處理的結果是失敗的。
但我們並不能觀察出最合適的閾值,Otsu處理能夠根據圖像給出最佳的分割閾值。
通過在函數 cv2.threshold() 中對 type 的類型多傳遞一個參數 cv2.THRESH_OTSU 即可實現Otsu。
註意在使用Otsu處理時需將閾值設為0。
1 import numpy as np 2 import cv2 as cv 3 4 img = np.zeros((5,5),dtype=np.uint8) 5 img[0:2,0:5] = 123 6 img[2:5,0:5] = 126 7 print('img=\n', img) 8 t1, thd = cv.threshold(img,127,255,cv.THRESH_BINARY) 9 t2, otsu = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU) 10 print('thd=\n', thd) 11 print('otsu=\n', otsu)
對上述像素矩陣進行直觀處理
另外Otsu處理也返回了最佳閾值,上述該閾值為 t2 = 123。