zoukankan      html  css  js  c++  java
  • 【OpenCV入门教程之六】 创建Trackbar & 图像对比度、亮度值调整(转)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处。  

    文章链接: http://blog.csdn.net/poem_qianmo/article/details/21479533

    作者:毛星云(浅墨)    邮箱: happylifemxy@163.com 

    写作当前博文时配套使用的OpenCV版本: 2.4.8

    这篇文章中我们一起学习了如何在OpenCV中用createTrackbar函数创建和使用轨迹条,以及图像对比度、亮度值的动态调整。

    文章首先详细讲解了OpenCV2.0中的新版创建轨迹条的函数createTrackbar,并给上一个详细注释的示例。

    然后讲解图像的对比度、亮度值调整的细节,最后放出了一个利用createTrackbar函数创建轨迹条来辅助进行图像对比度、亮度值调整的程序源码。

    依然是先放一张运行截图:

     

    好了,下面正式开始我们的讲解。

    一、OpenCV中轨迹条(Trackbar)的创建和使用

     
     

    <1>创建轨迹条——createTrackbar函数详解

    createTrackbar这个函数我们以后会经常用到,它创建一个可以调整数值的轨迹条,并将轨迹条附加到指定的窗口上,使用起来很方便。首先大家要记住,它往往会和一个回调函数配合起来使用。先看下他的函数原型:

    1. C++: int createTrackbar(conststring& trackbarname, conststring& winname,  
    2.  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(第二个参数)所代表的窗口上。

    看完函数讲解,先给大家一个函数使用小示例:

         

    1.  //创建轨迹条  
    2.        createTrackbar("对比度:", "【效果图窗口】",&g_nContrastValue,  
    3. 300,ContrastAndBright );// g_nContrastValue为全局的整型变量,ContrastAndBright为回调函数的函数名(即指向函数地址的指针)  

    然给大家一个完整的使用示例。这是OpenCV官方的sample示例程序,一个演示了用轨迹条来控制轮廓检测,轮廓填充的程序。浅墨将其修改、代码简洁化和详细注释,放出来供大家消化研习。稍后更新的博文会有关于轮廓检测更详细的讲解。

    1. //-----------------------------------【头文件包含部分】---------------------------------------  
    2. //  描述:包含程序所依赖的头文件  
    3. //----------------------------------------------------------------------------------------------   
    4. #include "opencv2/imgproc/imgproc.hpp"  
    5. #include "opencv2/highgui/highgui.hpp"  
    6. #include <iostream>  
    7.   
    8. //-----------------------------------【命名空间声明部分】---------------------------------------  
    9. //  描述:包含程序所使用的命名空间  
    10. //-----------------------------------------------------------------------------------------------     
    11. using namespace cv;  
    12. using namespace std;  
    13.   
    14. //-----------------------------------【全局函数声明部分】--------------------------------------  
    15. //  描述:全局函数声明  
    16. //-----------------------------------------------------------------------------------------------  
    17. Mat img;  
    18. int threshval = 160;            //轨迹条滑块对应的值,给初值160  
    19.   
    20. //-----------------------------【on_trackbar( )函数】------------------------------------  
    21. //  描述:轨迹条的回调函数  
    22. //-----------------------------------------------------------------------------------------------  
    23. static void on_trackbar(int, void*)  
    24. {  
    25.     Mat bw = threshval < 128 ? (img < threshval) : (img > threshval);  
    26.   
    27.     //定义点和向量  
    28.     vector<vector<Point> > contours;  
    29.     vector<Vec4i> hierarchy;  
    30.   
    31.     //查找轮廓  
    32.     findContours( bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );  
    33.     //初始化dst  
    34.     Mat dst = Mat::zeros(img.size(), CV_8UC3);  
    35.     //开始处理  
    36.     if( !contours.empty() && !hierarchy.empty() )  
    37.     {  
    38.         //遍历所有顶层轮廓,随机生成颜色值绘制给各连接组成部分  
    39.         int idx = 0;  
    40.         for( ; idx >= 0; idx = hierarchy[idx][0] )  
    41.         {  
    42.             Scalar color( (rand()&255), (rand()&255), (rand()&255) );  
    43.             //绘制填充轮廓  
    44.             drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );  
    45.         }  
    46.     }  
    47.     //显示窗口  
    48.     imshow( "Connected Components", dst );  
    49. }  
    50.   
    51.   
    52. //-----------------------------------【main( )函数】--------------------------------------------  
    53. //  描述:控制台应用程序的入口函数,我们的程序从这里开始  
    54. //-----------------------------------------------------------------------------------------------  
    55. int main(  )  
    56. {  
    57.     system("color 5F");    
    58.     //载入图片  
    59.     img = imread("1.jpg", 0);  
    60.     if( !img.data ) { printf("Oh,no,读取img图片文件错误~!  "); return -1; }  
    61.   
    62.     //显示原图  
    63.     namedWindow( "Image", 1 );  
    64.     imshow( "Image", img );  
    65.   
    66.     //创建处理窗口  
    67.     namedWindow( "Connected Components", 1 );  
    68.     //创建轨迹条  
    69.     createTrackbar( "Threshold", "Connected Components", &threshval, 255, on_trackbar );  
    70.     on_trackbar(threshval, 0);//轨迹条回调函数  
    71.   
    72.     waitKey(0);  
    73.     return 0;  
    74. }  

    原图:

    运行效果图:

    拖动滚动条,改变threshval(阈值)的值,得到效果迥异的图片:

    想要下载这个程序源工程的童鞋请点击这里:

    createTrackbarDemo【 浅墨优化&详细注释版】下载

    另外,在OpenCV路径opencv_source_code/samples/cpp/connected_components.cpp下,可以找到原版的官方代码。

    接着顺便讲一个配合createTrackbar使用的函数,用于获取当前轨迹条的位置的getTrackbarPos函数吧。

    <2>获取当前轨迹条的位置——getTrackbarPos函数

    这个函数用于获取当前轨迹条的位置并返回。

    1. 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循环解决问题:

    1. //三个for循环,执行运算 new_image(i,j) =a*image(i,j) + b  
    2. for(int y = 0; y < image.rows; y++ )  
    3. {  
    4.        for(int x = 0; x < image.cols; x++ )  
    5.        {  
    6.               for(int c = 0; c < 3; c++ )  
    7.               {  
    8.                      new_image.at<Vec3b>(y,x)[c]= saturate_cast<uchar>( (g_nContrastValue*0.01)*(image.at<Vec3b>(y,x)[c] ) + g_nBrightValue );  
    9.               }  
    10.        }  
    11. }  



    让我们分三个方面进行讲解:

     

    • 为了访问图像的每一个像素,我们使用这样的语法: 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。

    四、图像对比度、亮度值调整示例程序

     
     
     

    依然是每篇文章都会配给大家的一个详细注释的博文配套示例程序,把这篇文章中介绍的知识点以代码为载体,展现给大家。

    这个示例程序用两个轨迹条分别控制对比度和亮度值,有一定的可玩性。废话不多说,上代码吧:

    1. //-----------------------------------【程序说明】----------------------------------------------  
    2. //  程序名称::【OpenCV入门教程之四】 创建Trackbar&图像对比度、亮度值调整 配套博文源码  
    3. // VS2010版  OpenCV版本:2.4.8  
    4. //  2014年3月18 日 Create by 浅墨  
    5. //------------------------------------------------------------------------------------------------  
    6.    
    7.    
    8. //-----------------------------------【头文件包含部分】---------------------------------------  
    9. //     描述:包含程序所依赖的头文件  
    10. //----------------------------------------------------------------------------------------------  
    11. #include <opencv2/core/core.hpp>  
    12. #include<opencv2/highgui/highgui.hpp>  
    13. #include"opencv2/imgproc/imgproc.hpp"  
    14. #include <iostream>  
    15.    
    16. //-----------------------------------【命名空间声明部分】---------------------------------------  
    17. //     描述:包含程序所使用的命名空间  
    18. //-----------------------------------------------------------------------------------------------    
    19. using namespace std;  
    20. using namespace cv;  
    21.    
    22.    
    23. //-----------------------------------【全局函数声明部分】--------------------------------------  
    24. //     描述:全局函数声明  
    25. //-----------------------------------------------------------------------------------------------  
    26. static void ContrastAndBright(int, void *);  
    27.    
    28. //-----------------------------------【全局变量声明部分】--------------------------------------  
    29. //     描述:全局变量声明  
    30. //-----------------------------------------------------------------------------------------------  
    31. int g_nContrastValue; //对比度值  
    32. int g_nBrightValue;  //亮度值  
    33. Mat g_srcImage,g_dstImage;  
    34. //-----------------------------------【main( )函数】--------------------------------------------  
    35. //     描述:控制台应用程序的入口函数,我们的程序从这里开始  
    36. //-----------------------------------------------------------------------------------------------  
    37. int main(  )  
    38. {  
    39.        //改变控制台前景色和背景色  
    40.        system("color5F");   
    41.    
    42.        //读入用户提供的图像  
    43.        g_srcImage= imread( "pic1.jpg");  
    44.               if(!g_srcImage.data ) { printf("Oh,no,读取g_srcImage图片错误~! "); return false; }  
    45.        g_dstImage= Mat::zeros( g_srcImage.size(), g_srcImage.type() );  
    46.    
    47.        //设定对比度和亮度的初值  
    48.        g_nContrastValue=80;  
    49.        g_nBrightValue=80;  
    50.    
    51.        //创建窗口  
    52.        namedWindow("【效果图窗口】", 1);  
    53.    
    54.        //创建轨迹条  
    55.        createTrackbar("对比度:", "【效果图窗口】",&g_nContrastValue,300,ContrastAndBright );  
    56.        createTrackbar("亮   度:","【效果图窗口】",&g_nBrightValue,200,ContrastAndBright );  
    57.         
    58.        //调用回调函数  
    59.        ContrastAndBright(g_nContrastValue,0);  
    60.        ContrastAndBright(g_nBrightValue,0);  
    61.         
    62.        //输出一些帮助信息  
    63.        cout<<endl<<" 嗯。好了,请调整滚动条观察图像效果~ "  
    64.                      <<" 按下“q”键时,程序退出~! "  
    65.                      <<" by浅墨";  
    66.    
    67.        //按下“q”键时,程序退出  
    68.    while(char(waitKey(1)) != 'q') {}  
    69.        return0;  
    70. }  
    71.    
    72.    
    73. //-----------------------------【ContrastAndBright( )函数】------------------------------------  
    74. //     描述:改变图像对比度和亮度值的回调函数  
    75. //-----------------------------------------------------------------------------------------------  
    76. static void ContrastAndBright(int, void *)  
    77. {  
    78.    
    79.        //创建窗口  
    80.        namedWindow("【原始图窗口】", 1);  
    81.    
    82.        //三个for循环,执行运算 g_dstImage(i,j) =a*g_srcImage(i,j) + b  
    83.        for(int y = 0; y < g_srcImage.rows; y++ )  
    84.        {  
    85.               for(int x = 0; x < g_srcImage.cols; x++ )  
    86.               {  
    87.                      for(int c = 0; c < 3; c++ )  
    88.                      {  
    89.                             g_dstImage.at<Vec3b>(y,x)[c]= saturate_cast<uchar>( (g_nContrastValue*0.01)*(g_srcImage.at<Vec3b>(y,x)[c] ) + g_nBrightValue );  
    90.                      }  
    91.               }  
    92.        }  
    93.    
    94.        //显示图像  
    95.        imshow("【原始图窗口】", g_srcImage);  
    96.        imshow("【效果图窗口】", g_dstImage);  
    97. }  



    最后看一下运行截图,运行这个程序会得到两个图片显示窗口。第一个为原图窗口,第二个为效果图窗口。在效果图窗口中可以调节两个轨迹条,来改变当前图片的对比度和亮度。

    原图:

    可调节的效果图:

    本篇文章到这里就基本结束了,最后放出本篇文章配套示例程序的下载地址。

    本篇文章的配套源代码请点击这里下载:

    【浅墨OpenCV入门教程之六】配套源代码下载

    OK,本节的内容大概就是这些,我们下篇文章见:)

  • 相关阅读:
    tuple 元组及字典dict
    day 49 css属性补充浮动 属性定位 抽屉作业
    day48 选择器(基本、层级 、属性) css属性
    day47 列表 表单 css初识
    day 46 http和html
    day 45索引
    day 44 练习题讲解 多表查询
    day 40 多表查询 子查询
    day39 表之间的关联关系、 补充 表操作总结 where 、group by、
    day38 数据类型 约束条件
  • 原文地址:https://www.cnblogs.com/wobuchouyan/p/5059137.html
Copyright © 2011-2022 走看看