OpenCV-Python教程:11.圖片閾值
簡單閾值
這裡,問題很簡單,如果畫素值超過閾值,就給分配一個值(可能是白色),否則給分配另一個值(可能是黑色)。用的方法是cv2.threshold。第一個引數是源圖片,應該是個灰度圖片,第二個引數是閾值,用來分類畫素值的。第三個引數是在畫素值大於閾值時的最大值。OpenCV提供了不同風格的閾值,由第四個引數決定。不同型別由:
·cv2.THRESH_BINARY
·cv2.THRESH_BINARY_INV
·cv2.THRESH_TRUNC
·cv2.THRESH_TOZERO
·cv2.THRESH_TOZERO_INV
文件裡有解釋每個型別的意義。
會得到兩個輸出。第一個是retval,第二個是閾值過濾過的影象。
程式碼:
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('gradient.png', 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 xrange(6):
plt.subplot(2,3,i+1), plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
注意:
要畫多個圖片,我們可以使用plt.subplot()函式。
結果是:
適應性閾值
在前面我們使用了全域性的值作為閾值。但是它可能不是在所有條件下都好使,有事圖片在不同區域有不同的光線條件。在這種情況下,我們使用適應性閾值。演算法計算圖片裡一個小區域的閾值。我們在同一張圖片裡的不同區域可以有不同閾值。這會給我們多種光照下更好的結果.
它有三個“特殊”的輸入引數,只有一個輸出引數。
適應性方法 - 它來決定閾值如何計算出來。
·cv2.ADAPTIVE_THRESH_MEAN_C:閾值是周圍區域的差
·cv2.ADAPTIVE_THRESH_GAUSSIAN_C:閾值是周圍權重符合高斯分佈的區域的權重之和。
塊大小 - 它決定了周圍區域的大小
C - 它是一個常量,從差值裡減出來的或者計算出來的權重差。
下面的程式碼比較了全域性閾值和適應性閾值在處理一個變化光線的圖片的差別。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('dave.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_MEAN_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', '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()
結果:
Otsu二值法
在前面說過第二個引數retVal。在我們用到大津二值法的時候會用到。
在全域性閾值裡,我們使用一個固定值作為閾值,那麼我們怎麼知道這個值是好還是不好呢?答案是,反覆試驗,不斷探索。但是要注意雙峰圖片(簡單說,雙峰圖片是頻率分佈峰值有兩個的圖片),對於這種圖片,我們近似的可以用兩個峰的中間的值作為閾值,這就是Otsu二值法的做法。所以簡單來說,它自動計算雙峰圖片的頻率分佈的閾值。(對於非雙峰圖片,二值法不準確)
這裡用到cv2.threashold()函式,但是傳入一個額外的標誌位,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('noisy2.png',0)
# global thresholding
ret1, th1= cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# Otsu's thresholding
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering
blur = cv2.GaussianBlur(img,(5,5), 0)
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1, img, 0, th2, blur, 0, th3]
titles = ['Original Noisy Image', 'Histogram', 'Global Thresholding (v=127)', 'Original Noisy Image', 'Histogram', "Otsu's Thresholding", 'Gaussian filtered 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()
結果:
Otsu二值法是如何工作的
我們通過一個Otsu二值法的Python實現來展示它實際是如何工作的。
由於我們是處理雙峰圖片,Otsu演算法會通過下面的關係式嘗試找到能使帶權類內方差最小的閾值。
其中:
它實際上找到雙峰之間的t值使得兩個類都取得最小值。可以像下面這樣用Python實現:
img = cv2.imread('noisy2.png',0)
blur = cv2.GaussianBlur(img,(5,5),0)
# find normalized_histogram, and its cumulative distribution function
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]) # probabilities
q1, q2 = Q[i], Q[255]-Q[i] # cum sum of classes
b1, b2 = np.hsplit(bins,[i]) # weights
# finding means and variances
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
# calculates the minimization function
fn = v1*q1 + v2*q2
if fn < fn_min:
fn_min = fn
thresh = i
# find otsu's threshold value with OpenCV function
ret, otsu = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
print thresh, ret
相關文章
- opencv-python簡易文件(一)圖片基本操作OpenCVPython
- “閥值”與“閾值”的區別
- 【學習圖片】11.描述性語法
- 機器學習之分類:指定閾值機器學習
- 閾值PSI程式碼
- OpenCV(iOS)閾值化(15)OpenCViOS
- 迭代閾值分割演算法演算法
- 網格缺陷檢測(二值化閾值分析)
- 閾值分割及 threshold 實現
- MySQL 配置索引頁的合併閾值MySql索引
- 雙閾值對抗資料抖動
- python OpenCV中的閾值是什麼PythonOpenCV
- openCV中的影像處理 3 影像閾值OpenCV
- 最新openCV-Python安裝教程(opencv-python版本4.4.0, Python版本: 3.9)OpenCVPython
- 圖片怎麼轉換成PDF,圖片轉PDF教程
- JavaScript獲取背景圖片定位值JavaScript
- opencv——自適應閾值Canny邊緣檢測OpenCV
- python - 圖片灰度化、二值化Python
- lc2334 元素值大於變化閾值的子陣列陣列
- 美圖秀秀怎麼給圖片新增背景?美圖秀秀給圖片新增背景的教程
- 線上圖片製作網站哪個好 PS圖片處理教程網站
- Python 影像處理 OpenCV (6):影像的閾值處理PythonOpenCV
- 設定資料庫映象監視器的警告閾值資料庫
- 將警告閾值和警報用於映象效能指標指標
- Excel函式應用例項:位次閾值統計(轉)Excel函式
- 教程:怎麼轉換heic格式圖片
- SwiftUI 簡明教程之文字與圖片SwiftUI
- Metal入門教程(一)圖片繪製
- 新手教程:如何為網站搭配圖片網站
- 用ps製作動態圖片教程
- PS拍照圖片清晰化處理教程
- Java後臺Html轉圖片和獲取頁面屬性值,及圖片拼接JavaHTML
- WPF 讀取圖片 賦值Image控制元件 解決圖片佔用問題賦值控制元件
- 跟著教程做主圖,教你輕鬆去除圖片背景!
- 【ARCH】Oracle 判斷asm磁碟組大小,超過閾值清理指令碼OracleASM指令碼
- python改變單通道圖片的畫素值Python
- jQuery修改和獲取圖片的src屬性值jQuery
- 利用javascript獲取圖片的top N主色值JavaScript