學習 opencv---(5) 創建Trackbar(活動條) &圖像對比度,亮度值調整


    學習如何在opencv 中用trackbar 函數創建和使用 軌跡條,以及圖像對比度,亮度值的動態調整

   

  

    一、OpenCV中軌跡條(Trackbar)的創建和使用

       【1】創建軌跡條-----createTrackbar 函數詳解

      createTrackbar這個函數我們以后會經常用到,它創建一個可以調整的軌跡條,並將軌跡條附加到指定的窗口上,使用起來方便,首先,它往往會和一個回調函數 配合起來使用,先看它的函數原型:

1 int createTrackbar(conststring &trackerbarname,conststring &winname,int *value,int count ,TrackerbarCallback 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 (第二個參數)所代表的窗口上。

 

    看完函數講解,先給大家一個函數使用小示例:

    

1 //創建軌跡條
2 createTrackbar("對比度:“,”【效果圖窗口】",&g_nContrastVaule,300,ContrasAndBright); 3 //g_nContrastVaule為全局的整形變量,ContrasAndBright為回調函數的函數名(即指向函數地址的指針)

 

     

 

  然給大家一個完整的使用示例。這是OpenCV官方的sample示例程序,

 1 #include <opencv2/core/utility.hpp>
 2 #include "opencv2/imgproc.hpp"
 3 #include "opencv2/imgcodecs.hpp"
 4 #include "opencv2/highgui.hpp"
 5 #include <iostream>
 6 
 7 using namespace cv;  8 using namespace std;  9 
10 Mat img; 11 int threshval = 100; 12 
13 static void on_trackbar(int, void*) 14 { 15     Mat bw = threshval < 128 ? (img < threshval) : (img > threshval); 16  Mat labelImage(img.size(), CV_32S); 17     int nLabels = connectedComponents(bw, labelImage, 8); 18     std::vector<Vec3b> colors(nLabels); 19     colors[0] = Vec3b(0, 0, 0);//background
20     for(int label = 1; label < nLabels; ++label){ 21         colors[label] = Vec3b( (rand()&255), (rand()&255), (rand()&255) ); 22  } 23  Mat dst(img.size(), CV_8UC3); 24     for(int r = 0; r < dst.rows; ++r){ 25         for(int c = 0; c < dst.cols; ++c){ 26             int label = labelImage.at<int>(r, c); 27             Vec3b &pixel = dst.at<Vec3b>(r, c); 28             pixel = colors[label]; 29  } 30  } 31 
32     imshow( "Connected Components", dst ); 33 } 34 
35 static void help() 36 { 37     cout << "\n This program demonstrates connected components and use of the trackbar\n"
38              "Usage: \n"
39              " ./connected_components <image(../data/stuff.jpg as default)>\n"
40              "The image is converted to grayscale and displayed, another image has a trackbar\n"
41              "that controls thresholding and thereby the extracted contours which are drawn in color\n"; 42 } 43 
44 const char* keys =
45 { 46     "{help h||}{@image|../data/stuff.jpg|image for converting to a grayscale}"
47 }; 48 
49 int main( int argc, const char** argv ) 50 { 51  CommandLineParser parser(argc, argv, keys); 52     if (parser.has("help")) 53  { 54  help(); 55         return 0; 56  } 57     string inputImage = parser.get<string>(0); 58     img = imread(inputImage.c_str(), 0); 59 
60     if(img.empty()) 61  { 62         cout << "Could not read input image file: " << inputImage << endl; 63         return -1; 64  } 65 
66     namedWindow( "Image", 1 ); 67     imshow( "Image", img ); 68 
69     namedWindow( "Connected Components", 1 ); 70     createTrackbar( "Threshold", "Connected Components", &threshval, 255, on_trackbar ); 71     on_trackbar(threshval, 0); 72 
73     waitKey(0); 74     return 0; 75 }

 

       這是3 版本的代碼,因為按照淺墨大神的優化代碼移植到這里有點問題,所以先放官方代碼

  

    

    <2>獲取當前軌跡條的位置——getTrackbarPos函數

     這個函數用於獲取當前軌跡條的位置並返回

1 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循環解決問題: 

 1 for (int y = 0; y < g_srcImage.rows; y++)  2  {  3         for (int x = 0; x < g_srcImage.cols; x++)  4  {  5             for (int c = 0; c < 3; c++)  6  {  7                 g_dstImage.at<Vec3b>(y, x)[c] = saturate_cast<uchar>((g_nContrasaValue*0.01) * (g_srcImage.at<Vec3b>(y,x)[c]) + g_nBrightValue);  8  }  9  } 10     }

   

       讓我們分3個方面進行講解:

     -----為了訪問圖像的每一個像素,我們使用這樣的語法:image.at<Vec3b>(y,x)[c].其中,y是像素所在的行, x是像素所在的列, c是R、G、B(對應0、1、2)其中之一。

    -----因為我們的運算結果可能超出像素取值范圍(溢出),還可能是非整數(如果是浮點數的話),所以我們要用staurate_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。

    

   

  四、圖像對比度、亮度值調整示例程序

     

 1 /*---------------------------------------------------  2  創建Trackbar && 圖像對比度,亮度值調整  3 -----------------------------------------------------*/
 4 
 5 #include <opencv2/core/core.hpp>
 6 #include <opencv2/highgui/highgui.hpp>
 7 #include "opencv2/imgproc/imgproc.hpp"  //圖像處理模塊
 8 #include <iostream>
 9 
10 using namespace cv; 11 using namespace std; 12 
13 static void ContrastAndBright(int, void *);    //全局函數,回調函數,對比 &&亮度 14 
15 //全局變量
16 int g_nContrastValue;    //對比度值
17 int g_nBrightValue;   //亮度
18 Mat g_srcImage, g_dstImage; 19 
20 
21 /*---------------------------------------------------------- 22  描述:改變圖像對比度和亮度值的回調函數 23 -----------------------------------------------------------*/
24 static void ContrastAndBright(int, void*) 25 { 26     //創建窗口
27     namedWindow("【原始窗口】",1); 28 
29     //3個for循環,執行運算 g_Image(i,j) = a*g_srcImage(i,j) + b
30     for (int y = 0; y < g_srcImage.rows; y++) 31  { 32         for (int x = 0; x < g_srcImage.cols; x++) 33  { 34             for (int c = 0; c < 3; c++) 35  { 36                 g_dstImage.at<Vec3b>(y, x)[c] = saturate_cast<uchar>((g_nContrasaValue*0.01) * (g_srcImage.at<Vec3b>(y,x)[c]) + g_nBrightValue); 37  } 38  } 39  } 40 
41     //顯示圖像
42     imshow("【原始圖像 窗口】",g_srcImage); 43     imshow("【效果圖像 窗口】",g_dstImage); 44 
45 
46 } 47 
48 
49 int main() 50 { 51     //改變控制台前景色和背景色
52     system("color 5F"); 53 
54     //讀入用戶提供的圖像
55     g_srcImage = imread("pic1.jpg"); 56     if (!g_srcImage.data) 57  { 58         printf("Oh,no,讀取g_srcImage圖片錯誤~! \n"); 59         return false; 60  } 61     //這個函數還不是太清楚,zeros是什么鬼???輸出圖像
62     g_dstImage = Mat::zeros(g_srcImage.size(), g_srcImage.type()); 63 
64     //設定對比度和亮度的初值
65     g_nContrastValue = 80; 66     g_nBrightValue = 80; 67 
68     //創建窗口
69     namedWindow("【效果圖窗口】", 1); 70 
71     //創建軌跡條
72     createTrackbar("對比度:", "【效果圖窗口】", &g_nContrastValue, 300, ContrastAndBright); 73     createTrackbar("亮 度:", "【效果圖窗口】", &g_nBrightValue, 200, ContrastAndBright); 74 
75     //調用回調函數
76     ContrastAndBright(g_nContrastValue, 0); 77     ContrastAndBright(g_nBrightValue, 0); 78 
79     //輸出一些幫助信息
80     cout << endl << "\t嗯。好了,請調整滾動條觀察圖像效果~\n\n"
81         << "\t按下“q”鍵時,程序退出~!\n"
82         << "\n\n\t\t\t\t byhehheh"; 83 
84     //按下 q 時,程序退出
85     while (char (waitKey(1)) != 'q'); 86     return 0; 87}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM