轉自http://blog.csdn.net/poem_qianmo/article/details/21479533
本系列文章由@淺墨_毛星雲 出品,轉載請註明出處。
文章鏈接: http://blog.csdn.net/poem_qianmo/article/details/21479533
作者:毛星雲(淺墨) 郵箱: [email protected]
寫作當前博文時配套使用的OpenCV版本: 2.4.8
這篇文章中我們一起學習瞭如何在OpenCV中用createTrackbar函數創建和使用軌跡條,以及圖像對比度、亮度值的動態調整。
文章首先詳細講解了OpenCV2.0中的新版創建軌跡條的函數createTrackbar,並給上一個詳細註釋的示例。
然後講解圖像的對比度、亮度值調整的細節,最後放出了一個利用createTrackbar函數創建軌跡條來輔助進行圖像對比度、亮度值調整的程序源碼。
依然是先放一張運行截圖:
好了,下面正式開始我們的講解。
一、OpenCV中軌跡條(Trackbar)的創建和使用
<1>創建軌跡條——createTrackbar函數詳解
createTrackbar這個函數我們以後會經常用到,它創建一個可以調整數值的軌跡條,並將軌跡條附加到指定的窗口上,使用起來很方便。首先大家要記住,它往往會和一個回調函數配合起來使用。先看下他的函數原型:
- C++: int createTrackbar(conststring& trackbarname, conststring& winname,
- int* value, int count, TrackbarCallback onChange=0,void* userdata=0);
C++: int createTrackbar(conststring& trackbarname, conststring& winname, int* value, int count, TrackbarCallback onChange=0,void* userdata=0);
- 第一個參數,const string&類型的trackbarname,表示軌跡條的名字,用來代表我們創建的軌跡條。
- 第二個參數,const string&類型的winname,填窗口的名字,表示這個軌跡條會依附到哪個窗口上,即對應namedWindow()創建窗口時填的某一個窗口名。
- 第三個參數,int* 類型的value,一個指向整型的指針,表示滑塊的位置。並且在創建時,滑塊的初始位置就是該變量當前的值。
- 第四個參數,int類型的count,表示滑塊可以達到的最大位置的值。PS:滑塊最小的位置的值始終爲0。
- 第五個參數,TrackbarCallback類型的onChange,首先注意他有默認值0。這是一個指向回調函數的指針,每次滑塊位置改變時,這個函數都會進行回調。並且這個函數的原型必須爲void XXXX(int,void*);其中第一個參數是軌跡條的位置,第二個參數是用戶數據(看下面的第六個參數)。如果回調是NULL指針,表示沒有回調函數的調用,僅第三個參數value有變化。
- 第六個參數,void*類型的userdata,他也有默認值0。這個參數是用戶傳給回調函數的數據,用來處理軌跡條事件。如果使用的第三個參數value實參是全局變量的話,完全可以不去管這個userdata參數。
這個createTrackbar函數,爲我們創建一個具有特定名稱和範圍的軌跡條(Trackbar,或者說是滑塊範圍控制工具),指定一個和軌跡條位置同步的變量。而且要指定回調函數onChange(第五個參數),在軌跡條位置改變的時候來調用這個回調函數。並且我們知道,創建的軌跡條顯示在指定的winname(第二個參數)所代表的窗口上。
看完函數講解,先給大家一個函數使用小示例:
- //創建軌跡條
- createTrackbar("對比度:", "【效果圖窗口】",&g_nContrastValue,
- 300,ContrastAndBright );// g_nContrastValue爲全局的整型變量,ContrastAndBright爲回調函數的函數名(即指向函數地址的指針)
//創建軌跡條 createTrackbar("對比度:", "【效果圖窗口】",&g_nContrastValue, 300,ContrastAndBright );// g_nContrastValue爲全局的整型變量,ContrastAndBright爲回調函數的函數名(即指向函數地址的指針)
然給大家一個完整的使用示例。這是OpenCV官方的sample示例程序,一個演示了用軌跡條來控制輪廓檢測,輪廓填充的程序。淺墨將其修改、代碼簡潔化和詳細註釋,放出來供大家消化研習。稍後更新的博文會有關於輪廓檢測更詳細的講解。
- //-----------------------------------【頭文件包含部分】---------------------------------------
- // 描述:包含程序所依賴的頭文件
- //----------------------------------------------------------------------------------------------
- #include "opencv2/imgproc/imgproc.hpp"
- #include "opencv2/highgui/highgui.hpp"
- #include <iostream>
- //-----------------------------------【命名空間聲明部分】---------------------------------------
- // 描述:包含程序所使用的命名空間
- //-----------------------------------------------------------------------------------------------
- using namespace cv;
- using namespace std;
- //-----------------------------------【全局函數聲明部分】--------------------------------------
- // 描述:全局函數聲明
- //-----------------------------------------------------------------------------------------------
- Mat img;
- int threshval = 160; //軌跡條滑塊對應的值,給初值160
- //-----------------------------【on_trackbar( )函數】------------------------------------
- // 描述:軌跡條的回調函數
- //-----------------------------------------------------------------------------------------------
- static void on_trackbar(int, void*)
- {
- Mat bw = threshval < 128 ? (img < threshval) : (img > threshval);
- //定義點和向量
- vector<vector<Point> > contours;
- vector<Vec4i> hierarchy;
- //查找輪廓
- findContours( bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
- //初始化dst
- Mat dst = Mat::zeros(img.size(), CV_8UC3);
- //開始處理
- if( !contours.empty() && !hierarchy.empty() )
- {
- //遍歷所有頂層輪廓,隨機生成顏色值繪製給各連接組成部分
- int idx = 0;
- for( ; idx >= 0; idx = hierarchy[idx][0] )
- {
- Scalar color( (rand()&255), (rand()&255), (rand()&255) );
- //繪製填充輪廓
- drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );
- }
- }
- //顯示窗口
- imshow( "Connected Components", dst );
- }
- //-----------------------------------【main( )函數】--------------------------------------------
- // 描述:控制檯應用程序的入口函數,我們的程序從這裏開始
- //-----------------------------------------------------------------------------------------------
- int main( )
- {
- system("color 5F");
- //載入圖片
- img = imread("1.jpg", 0);
- if( !img.data ) { printf("Oh,no,讀取img圖片文件錯誤~! \n"); return -1; }
- //顯示原圖
- namedWindow( "Image", 1 );
- imshow( "Image", img );
- //創建處理窗口
- namedWindow( "Connected Components", 1 );
- //創建軌跡條
- createTrackbar( "Threshold", "Connected Components", &threshval, 255, on_trackbar );
- on_trackbar(threshval, 0);//軌跡條回調函數
- waitKey(0);
- return 0;
- }
//-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> //-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace cv; using namespace std; //-----------------------------------【全局函數聲明部分】-------------------------------------- // 描述:全局函數聲明 //----------------------------------------------------------------------------------------------- Mat img; int threshval = 160; //軌跡條滑塊對應的值,給初值160 //-----------------------------【on_trackbar( )函數】------------------------------------ // 描述:軌跡條的回調函數 //----------------------------------------------------------------------------------------------- static void on_trackbar(int, void*) { Mat bw = threshval < 128 ? (img < threshval) : (img > threshval); //定義點和向量 vector<vector<Point> > contours; vector<Vec4i> hierarchy; //查找輪廓 findContours( bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); //初始化dst Mat dst = Mat::zeros(img.size(), CV_8UC3); //開始處理 if( !contours.empty() && !hierarchy.empty() ) { //遍歷所有頂層輪廓,隨機生成顏色值繪製給各連接組成部分 int idx = 0; for( ; idx >= 0; idx = hierarchy[idx][0] ) { Scalar color( (rand()&255), (rand()&255), (rand()&255) ); //繪製填充輪廓 drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy ); } } //顯示窗口 imshow( "Connected Components", dst ); } //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制檯應用程序的入口函數,我們的程序從這裏開始 //----------------------------------------------------------------------------------------------- int main( ) { system("color 5F"); //載入圖片 img = imread("1.jpg", 0); if( !img.data ) { printf("Oh,no,讀取img圖片文件錯誤~! \n"); return -1; } //顯示原圖 namedWindow( "Image", 1 ); imshow( "Image", img ); //創建處理窗口 namedWindow( "Connected Components", 1 ); //創建軌跡條 createTrackbar( "Threshold", "Connected Components", &threshval, 255, on_trackbar ); on_trackbar(threshval, 0);//軌跡條回調函數 waitKey(0); return 0; }
原圖:
運行效果圖:
拖動滾動條,改變threshval(閾值)的值,得到效果迥異的圖片:
想要下載這個程序源工程的童鞋請點擊這裏:
createTrackbarDemo【 淺墨優化&詳細註釋版】下載
另外,在OpenCV路徑opencv_source_code/samples/cpp/connected_components.cpp下,可以找到原版的官方代碼。
接着順便講一個配合createTrackbar使用的函數,用於獲取當前軌跡條的位置的getTrackbarPos函數吧。
<2>獲取當前軌跡條的位置——getTrackbarPos函數
這個函數用於獲取當前軌跡條的位置並返回。
C++: int getTrackbarPos(conststring& trackbarname, conststring& winname);
- 第一個參數,const string&類型的trackbarname,表示軌跡條的名字。
- 第二個參數,const string&類型的winname,表示軌跡條的父窗口的名稱。
這部分大概就是這些了。馬不停蹄地向下一部分進發吧:)
二、亮度和對比度調整的理論依據
首先我們給出算子的概念。一般的圖像處理算子都是一個函數,它接受一個或多個輸入圖像,併產生輸出圖像。下式給出了算子的一般形式:
或者
今天我們所講解的圖像亮度和對比度的調整操作,其實屬於圖像處理變換中比較簡單的一種——點操作(pointoperators)。點操作有一個特點,僅僅根據輸入像素值(有時可加上某些全局信息或參數),來計算相應的輸出像素值。這類算子包括亮度(brightness)和對比度(contrast)調整,以及顏色校正(colorcorrection)和變換(transformations)。
最兩種常用的點操作(或者說點算子),很顯然,是乘上一個常數(對應對比度的調節)以及加上一個常數(對應亮度值的調節)。用公式表示出來就是這樣:
看到這個式子,我們關於圖像亮度和對比度調整的策略就呼之欲出了。
其中:
- 參數f(x)表示源圖像像素。
- 參數g(x) 表示輸出圖像像素。
- 參數a(需要滿足a>0)被稱爲增益(gain),常常被用來控制圖像的對比度。
- 參數b通常被稱爲偏置(bias),常常被用來控制圖像的亮度。
而更近一步,我們這樣改寫這個式子:
其中,i 和 j 表示像素位於第i行 和 第j列 。
那麼,這個式子就可以用來作爲我們在OpenCV中控制圖像的亮度和對比度的理論公式了。
三、關於訪問圖片中的像素
訪問圖片中的像素有很多種方式,以後有機會淺墨會用個專題來講解。目前我們可以先了解下面的這一種。
而爲了執行 這個運算 ,我們需要訪問圖像的每一個像素。因爲是對GBR圖像進行運算,每個像素有三個值(G、B、R),所以我們必須分別訪問它們(PS:OpenCV中的圖像存儲模式爲GBR)。以下是訪問像素的代碼片段,三個for循環解決問題:
- //三個for循環,執行運算 new_image(i,j) =a*image(i,j) + b
- for(int y = 0; y < image.rows; y++ )
- {
- for(int x = 0; x < image.cols; x++ )
- {
- for(int c = 0; c < 3; c++ )
- {
- new_image.at<Vec3b>(y,x)[c]= saturate_cast<uchar>( (g_nContrastValue*0.01)*(image.at<Vec3b>(y,x)[c] ) + g_nBrightValue );
- }
- }
- }
//三個for循環,執行運算 new_image(i,j) =a*image(i,j) + b for(int y = 0; y < image.rows; y++ ) { for(int x = 0; x < image.cols; x++ ) { for(int c = 0; c < 3; c++ ) { new_image.at<Vec3b>(y,x)[c]= saturate_cast<uchar>( (g_nContrastValue*0.01)*(image.at<Vec3b>(y,x)[c] ) + g_nBrightValue ); } } }
讓我們分三個方面進行講解:
- 爲了訪問圖像的每一個像素,我們使用這樣的語法: image.at<Vec3b>(y,x)[c]
- 其中,y是像素所在的行, x是像素所在的列, c是R、G、B(對應0、1、2)其中之一。
- 因爲我們的運算結果可能超出像素取值範圍(溢出),還可能是非整數(如果是浮點數的話),所以我們要用saturate_cast對結果進行轉換,以確保它爲有效值。
- 這裏的a也就是對比度,一般爲了觀察的效果,取值爲0.0到3.0的浮點值,但是我們的軌跡條一般取值都會整數,所以在這裏我們可以,將其代表對比度值的nContrastValue參數設爲0到300之間的整型,在最後的式子中乘以一個0.01,這樣就可以完成軌跡條中300個不同取值的變化。所以在式子中,我們會看到saturate_cast<uchar>( (g_nContrastValue*0.01)*(image.at<Vec3b>(y,x)[c] ) + g_nBrightValue )中的g_nContrastValue*0.01。
四、圖像對比度、亮度值調整示例程序
依然是每篇文章都會配給大家的一個詳細註釋的博文配套示例程序,把這篇文章中介紹的知識點以代碼爲載體,展現給大家。
這個示例程序用兩個軌跡條分別控制對比度和亮度值,有一定的可玩性。廢話不多說,上代碼吧:
- //-----------------------------------【程序說明】----------------------------------------------
- // 程序名稱::【OpenCV入門教程之四】 創建Trackbar&圖像對比度、亮度值調整 配套博文源碼
- // VS2010版 OpenCV版本:2.4.8
- // 2014年3月18 日 Create by 淺墨
- //------------------------------------------------------------------------------------------------
- //-----------------------------------【頭文件包含部分】---------------------------------------
- // 描述:包含程序所依賴的頭文件
- //----------------------------------------------------------------------------------------------
- #include <opencv2/core/core.hpp>
- #include<opencv2/highgui/highgui.hpp>
- #include"opencv2/imgproc/imgproc.hpp"
- #include <iostream>
- //-----------------------------------【命名空間聲明部分】---------------------------------------
- // 描述:包含程序所使用的命名空間
- //-----------------------------------------------------------------------------------------------
- using namespace std;
- using namespace cv;
- //-----------------------------------【全局函數聲明部分】--------------------------------------
- // 描述:全局函數聲明
- //-----------------------------------------------------------------------------------------------
- static void ContrastAndBright(int, void *);
- //-----------------------------------【全局變量聲明部分】--------------------------------------
- // 描述:全局變量聲明
- //-----------------------------------------------------------------------------------------------
- int g_nContrastValue; //對比度值
- int g_nBrightValue; //亮度值
- Mat g_srcImage,g_dstImage;
- //-----------------------------------【main( )函數】--------------------------------------------
- // 描述:控制檯應用程序的入口函數,我們的程序從這裏開始
- //-----------------------------------------------------------------------------------------------
- int main( )
- {
- //改變控制檯前景色和背景色
- system("color5F");
- //讀入用戶提供的圖像
- g_srcImage= imread( "pic1.jpg");
- if(!g_srcImage.data ) { printf("Oh,no,讀取g_srcImage圖片錯誤~!\n"); return false; }
- g_dstImage= Mat::zeros( g_srcImage.size(), g_srcImage.type() );
- //設定對比度和亮度的初值
- g_nContrastValue=80;
- g_nBrightValue=80;
- //創建窗口
- namedWindow("【效果圖窗口】", 1);
- //創建軌跡條
- createTrackbar("對比度:", "【效果圖窗口】",&g_nContrastValue,300,ContrastAndBright );
- createTrackbar("亮 度:","【效果圖窗口】",&g_nBrightValue,200,ContrastAndBright );
- //調用回調函數
- ContrastAndBright(g_nContrastValue,0);
- ContrastAndBright(g_nBrightValue,0);
- //輸出一些幫助信息
- cout<<endl<<"\t嗯。好了,請調整滾動條觀察圖像效果~\n\n"
- <<"\t按下“q”鍵時,程序退出~!\n"
- <<"\n\n\t\t\t\tby淺墨";
- //按下“q”鍵時,程序退出
- while(char(waitKey(1)) != 'q') {}
- return0;
- }
- //-----------------------------【ContrastAndBright( )函數】------------------------------------
- // 描述:改變圖像對比度和亮度值的回調函數
- //-----------------------------------------------------------------------------------------------
- static void ContrastAndBright(int, void *)
- {
- //創建窗口
- namedWindow("【原始圖窗口】", 1);
- //三個for循環,執行運算 g_dstImage(i,j) =a*g_srcImage(i,j) + b
- for(int y = 0; y < g_srcImage.rows; y++ )
- {
- for(int x = 0; x < g_srcImage.cols; x++ )
- {
- for(int c = 0; c < 3; c++ )
- {
- g_dstImage.at<Vec3b>(y,x)[c]= saturate_cast<uchar>( (g_nContrastValue*0.01)*(g_srcImage.at<Vec3b>(y,x)[c] ) + g_nBrightValue );
- }
- }
- }
- //顯示圖像
- imshow("【原始圖窗口】", g_srcImage);
- imshow("【效果圖窗口】", g_dstImage);
- }
//-----------------------------------【程序說明】---------------------------------------------- // 程序名稱::【OpenCV入門教程之四】 創建Trackbar&圖像對比度、亮度值調整 配套博文源碼 // VS2010版 OpenCV版本:2.4.8 // 2014年3月18 日 Create by 淺墨 //------------------------------------------------------------------------------------------------ //-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include"opencv2/imgproc/imgproc.hpp" #include <iostream> //-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace std; using namespace cv; //-----------------------------------【全局函數聲明部分】-------------------------------------- // 描述:全局函數聲明 //----------------------------------------------------------------------------------------------- static void ContrastAndBright(int, void *); //-----------------------------------【全局變量聲明部分】-------------------------------------- // 描述:全局變量聲明 //----------------------------------------------------------------------------------------------- int g_nContrastValue; //對比度值 int g_nBrightValue; //亮度值 Mat g_srcImage,g_dstImage; //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制檯應用程序的入口函數,我們的程序從這裏開始 //----------------------------------------------------------------------------------------------- int main( ) { //改變控制檯前景色和背景色 system("color5F"); //讀入用戶提供的圖像 g_srcImage= imread( "pic1.jpg"); if(!g_srcImage.data ) { printf("Oh,no,讀取g_srcImage圖片錯誤~!\n"); return false; } g_dstImage= Mat::zeros( g_srcImage.size(), g_srcImage.type() ); //設定對比度和亮度的初值 g_nContrastValue=80; g_nBrightValue=80; //創建窗口 namedWindow("【效果圖窗口】", 1); //創建軌跡條 createTrackbar("對比度:", "【效果圖窗口】",&g_nContrastValue,300,ContrastAndBright ); createTrackbar("亮 度:","【效果圖窗口】",&g_nBrightValue,200,ContrastAndBright ); //調用回調函數 ContrastAndBright(g_nContrastValue,0); ContrastAndBright(g_nBrightValue,0); //輸出一些幫助信息 cout<<endl<<"\t嗯。好了,請調整滾動條觀察圖像效果~\n\n" <<"\t按下“q”鍵時,程序退出~!\n" <<"\n\n\t\t\t\tby淺墨"; //按下“q”鍵時,程序退出 while(char(waitKey(1)) != 'q') {} return0; } //-----------------------------【ContrastAndBright( )函數】------------------------------------ // 描述:改變圖像對比度和亮度值的回調函數 //----------------------------------------------------------------------------------------------- static void ContrastAndBright(int, void *) { //創建窗口 namedWindow("【原始圖窗口】", 1); //三個for循環,執行運算 g_dstImage(i,j) =a*g_srcImage(i,j) + b for(int y = 0; y < g_srcImage.rows; y++ ) { for(int x = 0; x < g_srcImage.cols; x++ ) { for(int c = 0; c < 3; c++ ) { g_dstImage.at<Vec3b>(y,x)[c]= saturate_cast<uchar>( (g_nContrastValue*0.01)*(g_srcImage.at<Vec3b>(y,x)[c] ) + g_nBrightValue ); } } } //顯示圖像 imshow("【原始圖窗口】", g_srcImage); imshow("【效果圖窗口】", g_dstImage); }
最後看一下運行截圖,運行這個程序會得到兩個圖片顯示窗口。第一個爲原圖窗口,第二個爲效果圖窗口。在效果圖窗口中可以調節兩個軌跡條,來改變當前圖片的對比度和亮度。
原圖:
可調節的效果圖:
本篇文章到這裏就基本結束了,最後放出本篇文章配套示例程序的下載地址。
本篇文章的配套源代碼請點擊這裏下載:
OK,本節的內容大概就是這些,我們下篇文章見:)
【OpenCV入門教程之六】 創建Trackbar & 圖像對比度、亮度值調整
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.