在這一章我們將要學習圖像閾值的相關知識,包括簡單閾值,自適應閾值, Otsu’s 二值化 。
簡單閾值
構造函數爲:
cv2.threshold(img,thresh,maxval,type,dst=None)
參數解釋:
- img是等待進行處理的圖像
- thresh是一個標記,凡是高於(低於)這個閾值的像素值都會被賦予黑色(或者白色)
- maxval這個值就是高於或者低於thresh時要賦予的值
- type這裏控制的是閾值化操作的類型
• cv2.THRESH_BINARY
• cv2.THRESH_BINARY_INV
• cv2.THRESH_TRUNC
• cv2.THRESH_TOZERO
• cv2.THRESH_TOZERO_INV
具體這五種操作有什麼不同,我們還是得用例子來說明。
原圖
ret,mask=cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
可以看出cv2.THRESH_BINARY_INV
表示小於‘127’的賦值‘255’
ret,mask=cv2.threshold(img,127,255,cv2.THRESH_BINARY)
可以看出cv2.THRESH_BINARY
表示大於‘127’的地方賦值‘255’
ret,mask=cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
這個就很迷惑了,第三個參數好像沒用,大於第二個參數都被賦值賦成127了
ret,mask=cv2.threshold(img,127,0,cv2.THRESH_TOZERO)
小於127的全被黑了
ret,mask=cv2.threshold(img,127,0,cv2.THRESH_TOZERO_INV)
大於127的全黑
自適應閾值
簡單閾值對整張圖像只有一個閾值,這必然是不精準的,在圖像各個部位光照不同的情況下就會產生很大誤差,這時候我們就需要用自適應閾值。此時的閾值是根據圖像上的 每一個小區域計算與其對應的閾值。
cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
-
src:原圖像
-
maxValue:當閾值類型(thresholdType)採用cv2.THRESH_BINARY和cv2.THRESH_BINARY_INV時像素點被賦予的新值
-
adaptiveMethod:自適應閾值的計算方法,包括兩種:
- cv2.ADPTIVE_THRESH_MEAN_C:閾值取自相鄰區域的平均值
- cv2.ADPTIVE_THRESH_GAUSSIAN_C:閾值取值相鄰區域的加權和,權重爲一個高斯窗口。
-
thresholdType:閾值分割類型,共5種,同cv2.threshold()的閾值分割類型參數
-
blockSize:用來計算閾值的鄰域大小
-
C:常數,adaptiveMethod方法計算出的數值減去這個常數C就爲閾值
import numpy as np
import cv2
img=cv2.imread('D://zopencv//jianpan.jpg',cv2.IMREAD_GRAYSCALE)
mask=cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,3)
th1 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\ cv2.THRESH_BINARY,11,2)
th1 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\ cv2.THRESH_BINARY,11,2)
cv2.imshow('mask1',th1)
cv2.imshow('mask2,th2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Otsu 二值化
在第一部分中我們提到過 retVal,當我們使用 Otsu 二值化時會用到它。 那麼它到底是什麼呢? 在使用全局閾值時,我們就是隨便給了一個數來做閾值,那我們怎麼知道 我們選取的這個數的好壞呢?答案就是不停的嘗試。如果是一副雙峯圖像(簡 單來說雙峯圖像是指圖像直方圖中存在兩個峯)呢?我們豈不是應該在兩個峯 之間的峯谷選一個值作爲閾值?這就是 Otsu 二值化要做的。簡單來說就是對 一副雙峯圖像自動根據其直方圖計算出一個閾值。(對於非雙峯圖像,這種方法 得到的結果可能會不理想)。 這裏用到到的函數還是 cv2.threshold(),但是需要多傳入一個參數 (flag):cv2.THRESH_OTSU。這時要把閾值設爲 0。然後算法會找到最 優閾值,這個最優閾值就是返回值 retVal。如果不使用 Otsu 二值化,返回的 retVal 值與設定的閾值相等。
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
很明顯我不咋明白。。。