1. 程式人生 > >Python 影象處理 OpenCV (6):影象的閾值處理

Python 影象處理 OpenCV (6):影象的閾值處理

![](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