opencv圖像閾值設置的三種方法

一、簡單閾值設置

  像素值高於閾值時,給這個像素賦予一個新值(多是白色),不然咱們給它賦予另一種顏色(也許是黑色)。這個函數就是 cv2.threshhold()。這個函數的第一個參數就是原圖像,原圖像應該是灰度圖。第二個參數就是用來對像素值進行分類的閾值。第三個參數就是當像素值高於(有時是小於)閾值時應該被賦予的新的像素值。 OpenCV提供了多種不一樣的閾值方法,這是有第四個參數來決定的。這些方法包括:
• cv2.THRESH_BINARY
• cv2.THRESH_BINARY_INV
• cv2.THRESH_TRUNC
• cv2.THRESH_TOZERO
• cv2.THRESH_TOZERO_INV
這裏寫圖片描述
上圖摘選自《學習 OpenCV》中文版
  這個函數有兩個返回值,第一個爲 retVal,咱們後面會解釋。第二個就是閾值化以後的結果圖像了.
  爲了同時在一個窗口中顯示多個圖像,咱們使用函數 plt.subplot(),能夠經過查看 Matplotlib 的文檔得到更多詳細信息python

import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('image/lufei.jpeg',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','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV'] images = [img,thresh1,thresh2,thresh3,thresh4,thresh5] for i in xrange(6): plt.subplot(2,3,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()

結果圖:
這裏寫圖片描述算法

2 、自適應閾值

  在前面的部分咱們使用是全局閾值,整幅圖像採用同一個數做爲閾值。可是這種方法並不適應與全部狀況,尤爲是當同一幅圖像上的不一樣部分的具備不一樣亮度時。這種狀況下咱們須要採用自適應閾值。此時的閾值是根據圖像上的每個小區域計算與其對應的閾值。所以在同一幅圖像上的不一樣區域採用的是不一樣的閾值,從而使咱們能在亮度不一樣的狀況下獲得更好的結果。這種方法須要咱們指定三個參數,返回值只有一個。
• 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('image/lufei.jpeg',0) img = cv2.medianBlur(img, 5) ret,th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) 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','Global Thresholding(v = 127)','Adaptive Mean Thresholding','Adaptive Gaussian Thresholding'] images = [img,th1,th2,th3] for i in xrange(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 二值化。看看噪音去除對結果的影響有多大吧。ui

import cv2
import numpy as np 
from matplotlib import pyplot as plt 

img = cv2.imread('image/lufei.jpeg',0) ret1,th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) ret2,th2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) blur = cv2.GaussianBlur(img, (5,5), 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 Image','Histogram','Global Threshilding(v = 127)', 'Original Noisy Image','Histogram',"Otsu's Thresholding", 'Gaussian fifltered Image','Histogram',"Otsu's Thresholding",] for i in xrange(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()

結果圖:
這裏寫圖片描述spa

4 、Otsu’s 二值化是如何工做的

  在這一部分演示怎樣使用 Python 來實現 Otsu 二值化算法,從而告訴你們它是如何工做的。由於是雙峯圖, Otsu 算法就是要找到一個閾值(t), 使得同一類加權方差最小,須要知足下列關係式:
這裏寫圖片描述
  其實就是在兩個峯之間找到一個閾值 t,將這兩個峯分開,而且使每個峯內的方差最小。實現這個算法的 Python 代碼以下:code

import cv2
import numpy as np img = cv2.imread('image/lufei.jpeg',0) blur = cv2.GaussianBlur(img, (5,5), 0) 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 xrange(1,256): p1,p2 = np.hsplit(hist_norm, [i]) q1,q2 = Q[i],Q[255]-Q[i] b1,b2 = np.hsplit(bins, [i]) 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 fn = v1*q1 + v2*q2 if fn < fn_min: fn_min = fn thresh = i ret,otsu = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) print thresh,ret
相關文章
相關標籤/搜索