1. 程式人生 > >初識OpenCV 練習筆記整理--學習九。【影象閾值】

初識OpenCV 練習筆記整理--學習九。【影象閾值】

#  影象閾值
"""
目標:
    本節將學習到簡單閾值,自適應閾值,Otsu's二值化等。
    將要學習的函式有CV2.threshold, cv2.adaptiveThreshold等。
"""
# 第一小節 簡單閾值 2018/11/05 10:35
"""
與名字一樣,這種方法非常簡單。但畫素值高於閾值時,我們給這個畫素賦予一個新值(可能是白色),否則我們給它賦予另外一種顏色(也許是黑色)
這個函式就是cv2.threshhold()。這個函式的第一個引數就是原影象,原影象應該是灰度圖。第二個引數就是用來對畫素進行分類的閾值。
第三個引數就是當畫素值高於(有時候是小於)閾值時 應該被賦予新的畫素值OpenCV提供了多種不同的閾值方法,這是有第四個引數來決定的。
這些方法包括:
    cv2.THRESH_BINARY
    cv2.THRESH_BINARY_INV
    cv2.THRESH_TRUNC
    cv2.THRESH_TOZERO
    cv2.THRESH_TOZERO_INV
ret, dst = cv2.threshold(src, thresh, maxval, type)
    各個引數以及代表意思:
        src:輸入圖,只能輸入單通道影象,通常來說為灰度圖
        dst:輸出圖
        maxval:當畫素值超過了閾值(或者小於閾值,根據type來決定),所賦予的值
        type:二值化操作的型別上邊已經寫過了。
"""
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('./66.jpg', 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 range(6):
    plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()
# 第二小節 adaptiveThreshold:自適應閾值二值化 2018/11/06 11:02
"""
自適應閾值二值化函式根據圖片一小塊區域的值來計算對應區域的閾值,從而帶到也許更為合適的圖片
dst = cv2.adaptiveThreshold(src, maxval, thresh_type, type, Block Size, C)
    src:輸入圖,只能輸入單通道影象,通常來說為灰度圖
    dst:輸出圖
    maxval:當畫素值超過了閾值(或者小於閾值,根據type來決定),所賦予的值
    thresh_type:閾值的計算方法,包含以下2種類型: cv2.ASAPTIVE_THRESH_MEAN_C;cv2.ADAPTIVE_THRESH_GAUSSIAN_C
    type:二值化的操作型別,與固定閾值函式相同,包含以下五種型別(同上)。
    Block Size:圖片中分塊的大小
    C:閾值計算方法中的常數項
"""
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('./66.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', 'Adaptive Mean Thresholding', 'Adaptibe Gaussian Thersholding']
images = [img, th1, th2, th3]
for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()
# 第三小節 Otsu's二值化 2018/11/06 11:44
"""
在第一部分中我們提到過retVal ,當我們使用Otsu二值化時候會用到它。那麼它到底是什麼呢?
    在使用全域性閾值的時候,我們就是隨便給了一個數來做閾值,那我們怎麼知道我們選取的這個數的好壞呢?答案就是不停的嘗試。
    如果是一幅雙峰影象,那我們豈不是應該在兩個峰之間的峰谷選一個值來作為閾值?這就是Otsu二值化要做的。
    這裡用到的函式還是cv2.threshold(),但是多傳入一個引數:cv2.THRESH_OTSU。這時就要把閾值設為0。然後通過演算法找到最優的閾值,
    這個最優閾值就是返回值retVal。如果不使用Otsu二值化,返回的retVal值與設定的閾值相等。
Otsu過程:
    1. 計算影象直方圖;
    2. 設定一閾值,把直方圖強度大於閾值的畫素分成一組,把小於閾值的畫素分成另外 一組;
    3. 分別計算兩組內的偏移數,並把偏移數相加;
    4. 把0~255依照順序多為閾值,重複1-3的步驟,直到得到最小的偏移數,其所對應的值即為結果閾值。
"""
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('./66.jpg', 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
# (5, 5)為高斯核的大小,0為標準差
blur = cv2.GaussianBlur(img, (5, 5), 0)
# 閾值一定要設為 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 range(3):
    plt.subplot(3, 3, i * 3 + 1), plt.imshow(images[i * 3], 'gray')
    # 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()