opencv 图像阈值分割图像
-
最簡單的圖像分割的方法。
-
應用舉例:從一副圖像中利用閾值分割出我們需要的物體部分(當然這里的物體可以是一部分或者整體)。這樣的圖像分割方法是基于圖像中物體與背景之間的灰度差異,而且此分割屬于像素級的分割。
-
為了從一副圖像中提取出我們需要的部分,應該用圖像中的每一個像素點的灰度值與選取的閾值進行比較,并作出相應的判斷。(注意:閾值的選取依賴于具體的問題。即:物體在不同的圖像中有可能會有不同的灰度值。
-
一旦找到了需要分割的物體的像素點,我們可以對這些像素點設定一些特定的值來表示。(例如:可以將該物體的像素點的灰度值設定為:‘0’(黑色),其他的像素點的灰度值為:‘255’(白色);當然像素點的灰度值可以任意,但最好設定的兩種顏色對比度較強,方便觀察結果)。
閾值化的類型:
-
OpenCV中提供了閾值(threshold)函數:?threshold?。
-
這個函數有5種閾值化類型,在接下來的章節中將會具體介紹。
-
為了解釋閾值分割的過程,我們來看一個簡單有關像素灰度的圖片,該圖如下。該圖中的藍色水平線代表著具體的一個閾值。
閾值類型1:二進制閾值化
-
該閾值化類型如下式所示:
-
解釋:在運用該閾值類型的時候,先要選定一個特定的閾值量,比如:125,這樣,新的閾值產生規則可以解釋為大于125的像素點的灰度值設定為最大值(如8位灰度值最大為255),灰度值小于125的像素點的灰度值設定為0。
閾值類型2:反二進制閾值化
-
該閾值類型如下式所示:
-
解釋:該閾值化與二進制閾值化相似,先選定一個特定的灰度值作為閾值,不過最后的設定值相反。(在8位灰度圖中,例如大于閾值的設定為0,而小于該閾值的設定為255)。
閾值類型3:截斷閾值化
-
該閾值化類型如下式所示:
-
解釋:同樣首先需要選定一個閾值,圖像中大于該閾值的像素點被設定為該閾值,小于該閾值的保持不變。(例如:閾值選取為125,那小于125的閾值不改變,大于125的灰度值(230)的像素點就設定為該閾值)。
閾值類型4:閾值化為0
-
該閾值類型如下式所示:
-
解釋:先選定一個閾值,然后對圖像做如下處理:1 像素點的灰度值大于該閾值的不進行任何改變;2 像素點的灰度值小于該閾值的,其灰度值全部變為0。
閾值類型5:反閾值化為0
-
該閾值類型如下式所示:
-
解釋:原理類似于0閾值,但是在對圖像做處理的時候相反,即:像素點的灰度值小于該閾值的不進行任何改變,而大于該閾值的部分,其灰度值全部變為0。
代碼示范:
簡單的代碼如下。同樣也可以在網站中?下載?以下代碼。
#include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <stdlib.h> #include <stdio.h>using namespace cv;/// 全局變量定義及賦值int threshold_value = 0; int threshold_type = 3;; int const max_value = 255; int const max_type = 4; int const max_BINARY_value = 255;Mat src, src_gray, dst; char* window_name = "Threshold Demo";char* trackbar_type = "Type: \n 0: Binary \n 1: Binary Inverted \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted"; char* trackbar_value = "Value";/// 自定義函數聲明 void Threshold_Demo( int, void* );/** * @主函數 */ int main( int argc, char** argv ) {/// 讀取一副圖片,不改變圖片本身的顏色類型(該讀取方式為DOS運行模式)src = imread( argv[1], 1 );/// 將圖片轉換成灰度圖片cvtColor( src, src_gray, CV_RGB2GRAY );/// 創建一個窗口顯示圖片namedWindow( window_name, CV_WINDOW_AUTOSIZE );/// 創建滑動條來控制閾值createTrackbar( trackbar_type,window_name, &threshold_type,max_type, Threshold_Demo );createTrackbar( trackbar_value,window_name, &threshold_value,max_value, Threshold_Demo );/// 初始化自定義的閾值函數Threshold_Demo( 0, 0 );/// 等待用戶按鍵。如果是ESC健則退出等待過程。while(true){int c;c = waitKey( 20 );if( (char)c == 27 ){ break; }}}/** * @自定義的閾值函數 */ void Threshold_Demo( int, void* ) {/* 0: 二進制閾值 1: 反二進制閾值 2: 截斷閾值 3: 0閾值 4: 反0閾值 */threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );imshow( window_name, dst ); }解釋:
先看一下整個程序的結構:
-
先讀取一副圖片,如果是圖片顏色類型是RGB3色類型,則轉換成灰度類型的圖像。轉換顏色類型可以運用OpenCV中的 cvtColor<> 函數。
src = imread( argv[1], 1 );/// 顏色類型從RGB 轉換成灰度 cvtColor( src, src_gray, CV_RGB2GRAY ); -
然后創建一個窗口來顯示該圖片可以檢驗轉換結果
namedWindow( window_name, CV_WINDOW_AUTOSIZE ); -
接著該程序創建兩個滾動條來等待用戶的輸入:
- 第一個滾動條作用:選擇閾值類型:二進制,反二進制,截斷,0,反0。
- 第二個滾動條作用:選擇閾值的大小。
-
在這里等到用戶拖動滾動條來輸入閾值類型以及閾值的大小,或者是用戶鍵入ESC健退出程序。
-
無論何時拖動滾動條,用戶自定義的閾值函數都將會被調用。
/** * @自定義的閾值函數 */ void Threshold_Demo( int, void* ) {/* 0: 二進制閾值 1: 反二進制閾值 2: 截斷閾值 3: 0閾值 4: 反0閾值 */threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );imshow( window_name, dst ); }就像你看到的那樣,在這樣的過程中,函數 threshold<> 會接受到5個參數:
- src_gray: 輸入的灰度圖像的地址。
- dst: 輸出圖像的地址。
- threshold_value: 進行閾值操作時閾值的大小。
- max_BINARY_value: 設定的最大灰度值(該參數運用在二進制與反二進制閾值操作中)。
- threshold_type: 閾值的類型。從上面提到的5種中選擇出的結果。
結果:
程序編譯過后,從正確的路徑中讀取一張圖片。例如,該輸入圖片如下所示:
首先,閾值類型選擇為反二進制閾值類型。我們希望灰度值大于閾值的變暗,即這一部分像素的灰度值設定為0。從下圖中可以很清楚的看到這樣的變化。(在原圖中,狗的嘴和眼睛部分比圖像中的其他部分要亮,在結果圖中可以看到由于反二進制閾值分割,這兩部分變的比其他圖像的都要暗。原理具體參見本節中反二進制閾值部分解釋)
現在,閾值的類型選擇為0閾值。在這種情況下,我們希望那些在圖像中最黑的像素點徹底的變成黑色,而其他大于閾值的像素保持原來的面貌。其結果如下圖所示:
總結
以上是生活随笔為你收集整理的opencv 图像阈值分割图像的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: opencv 其他形态学变换
- 下一篇: opencv 线性滤波器