Python 影象處理 OpenCV (6):影象的閾值處理
阿新 • • 發佈:2020-06-05
![](https://cdn.geekdigging.com/opencv/opencv_header.png)
前文傳送門:
[「Python 影象處理 OpenCV (1):入門」](https://www.geekdigging.com/2020/05/17/5513454552/)
[「Python 影象處理 OpenCV (2):畫素處理與 Numpy 操作以及 Matplotlib 顯示影象」](https://www.geekdigging.com/2020/05/18/4936041986/)
[「Python 影象處理 OpenCV (3):影象屬性、影象感興趣 ROI 區域及通道處理」](https://www.geekdigging.com/2020/05/19/1227329671/)
[「Python 影象處理 OpenCV (4):影象算數運算以及修改顏色空間」](https://www.geekdigging.com/2020/05/21/1757913240/)
[「Python 影象處理 OpenCV (5):影象的幾何變換」](https://www.geekdigging.com/2020/05/23/4331122737/)
## 影象的閾值
看到這個詞可能大家都很懵,為啥在影象處理裡面還會有閾值。
影象的閾值處理用大白話講就是將影象轉化為二值影象(黑白圖),目的是用來提取影象中的目標物體,將背景和噪聲區分開(可以近似的認為除了目標全是噪聲)。
通常會設定一個閾值 T ,通過 T 將影象的畫素劃分為兩類:大於 T 的畫素群和小於 T 的畫素群。
首先可以先將影象轉化為灰度影象,因為在灰度影象中,每個畫素都只有一個灰度值用來表示當前畫素的亮度。
接下來二值化處理可以將影象中的畫素劃分為兩類顏色,一種是大於閾值 T 的,另一種是小於閾值 T 的。
比如最常見的二值影象:
當灰度值小於閾值 T 的時候,可以將其畫素設定為 0 ,表示為黑色。
當灰度值大於閾值 T 的時候,可以將其畫素設定為 255 ,表示為白色。
在 OpenCV 中,為我們提供了閾值函式 `threshold()` 來幫助我們實現二值影象的處理。
函式如下:
```python
retval, dst = threshold(src, thresh, maxval, type, dst=None)
```
* retval: 閾值
* dst: 處理後的影象
* src: 原影象
* thresh: 閾值
* maxval: 最大值
* type: 處理型別
常用的 5 中處理型別如下:
* cv.THRESH_BINARY: 二值處理
* cv.THRESH_BINARY_INV: 反二值處理
* cv.THRESH_TRUNC: 截斷閾值化
* cv.THRESH_TOZERO: 閾值化為 0
* cv.THRESH_TOZERO_INV: 反閾值化為 0
接下來這幾種處理型別有啥不同,我們一個一個來看。
## 二值處理
這種二值處理方式最開始需要選定一個閾值 T ,從 0 ~ 255 之間,我這裡選擇出於中間的那個數 127 。
接下來的處理規則就是這樣的:
* 大於等於 127 的畫素點的灰度值設定為最大值,也就是 255 白色
* 小於 127 的畫素點的灰度值設定為 0 ,也就是黑色
接下來開始寫程式碼,看我們的馬里奧同學(不知道你們還記不記得我們的馬里奧同學):
```python
import cv2 as cv
src = cv.imread("maliao.jpg")
# BGR 影象轉灰度
gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 二值影象處理
r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY)
# 顯示影象
cv.imshow("src", src)
cv.imshow("result", b)
# 等待顯示
cv.waitKey(0)
cv.destroyAllWindows()
```
![](https://cdn.geekdigging.com/opencv/06/binary_result.png)
## 反二值處理
這種方式和上面的二值處理非常相似,只是把處理規則給反了一下:
* 大於等於 127 的畫素點的灰度值設定為 0 ,也就是白色
* 小於 127 的畫素點的灰度值設定為最大值,也就是 255 白色
完整程式碼如下:
```python
import cv2 as cv
src = cv.imread("maliao.jpg")
# BGR 影象轉灰度
gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 二值影象處理
r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY_INV)
# 顯示影象
cv.imshow("src", src)
cv.imshow("result", b)
# 等待顯示
cv.waitKey(0)
cv.destroyAllWindows()
```
![](https://cdn.geekdigging.com/opencv/06/binary_inv_result.png)
從影象上可以看到,顏色和上面的二值影象正好相反,大部分的位置都變成了白色。
## 截斷閾值化
這種方法還是需要先選定一個閾值 T ,影象中大於該閾值的畫素點被設定為該閾值,小於該閾值的保持不變。
完整程式碼如下:
```python
import cv2 as cv
src = cv.imread("maliao.jpg")
# BGR 影象轉灰度
gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 二值影象處理
r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_TRUNC)
# 顯示影象
cv.imshow("src", src)
cv.imshow("result", b)
# 等待顯示
cv.waitKey(0)
cv.destroyAllWindows()
```
![](https://cdn.geekdigging.com/opencv/06/trunc_result.png)
這種方式實際上是把圖片比較亮的畫素處理成為閾值,其他部分保持不變。
## 閾值化為 0
這種方式還是需要先選定一個閾值 T ,將小於 T 的畫素點設定為 0 黑色,其他的保持不變。
完整程式碼如下:
```python
import cv2 as cv
src = cv.imread("maliao.jpg")
# BGR 影象轉灰度
gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 二值影象處理
r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO)
# 顯示影象
cv.imshow("src", src)
cv.imshow("result", b)
# 等待顯示
cv.waitKey(0)
cv.destroyAllWindows()
```
![](https://cdn.geekdigging.com/opencv/06/tozero_result.png)
這個方法是亮的部分不改,把比較暗的部分修改為 0 。
## 反閾值化為 0
這個和前面的反二值影象很像,同樣是反閾值化為 0 ,將大於等於 T 的畫素點變為 0 ,其餘保持不變。
完整程式碼如下:
```python
import cv2 as cv
src = cv.imread("maliao.jpg")
# BGR 影象轉灰度
gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# 二值影象處理
r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO_INV)
# 顯示影象
cv.imshow("src", src)
cv.imshow("result", b)
# 等待顯示
cv.waitKey(0)
cv.destroyAllWindows()
```
![](https://cdn.geekdigging.com/opencv/06/tozero_inv_result.png)
這個方法是暗的部分不改,把比較亮的部分修改為 0 。
## 全家福
接下來還是給這幾種閾值處理後的影象來個全家福,讓大家能有一個直觀的感受,程式碼我也給出來,如下:
```python
import cv2 as cv
import matplotlib.pyplot as plt
# 讀取影象
img=cv.imread('maliao.jpg')
lenna_img = cv.cvtColor(img,cv.COLOR_BGR2RGB)
gray_img=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 閾值化處理
ret1, thresh1=cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY)
ret2, thresh2=cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY_INV)
ret3, thresh3=cv.threshold(gray_img, 127, 255, cv.THRESH_TRUNC)
ret4, thresh4=cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO)
ret5, thresh5=cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO_INV)
# 顯示結果
titles = ['Gray Img','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [gray_img, thresh1, thresh2, thresh3, thresh4, thresh5]
# matplotlib 繪圖
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()
```
![](https://cdn.geekdigging.com/opencv/06/quanjiafu_result.png)
## 示例程式碼
如果有需要獲取原始碼的同學可以在公眾號回覆「OpenCV」進行獲取。
## 參考
https://blog.csdn.net/Eastmount/article/details/83548652
http://www.woshic