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


1、簡單閾值設置

  像素值高於閾值時,給這個像素賦予一個新值(可能是白色),否則我們給它賦予另外一種顏色(也許是黑色)。這個函數就是 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 的文檔獲得更多詳細信息

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 二值化。看看噪音去除對結果的影響有多大吧。

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()

結果圖:
這里寫圖片描述

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

  在這一部分演示怎樣使用 Python 來實現 Otsu 二值化算法,從而告訴大家它是如何工作的。因為是雙峰圖, Otsu 算法就是要找到一個閾值(t), 使得同一類加權方差最小,需要滿足下列關系式:
這里寫圖片描述
  其實就是在兩個峰之間找到一個閾值 t,將這兩個峰分開,並且使每一個峰內的方差最小。實現這個算法的 Python 代碼如下:

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
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM