opencv计算图像亮度调节_OpenCV教程创建Trackbar图像对比度、亮度值调整

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

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

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

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

bf38894b7eba16b624fea2214795ded2.png

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

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

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

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

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为回调函数的函数名(即指向函数地址的指针)

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

//-----------------------------------【头文件包含部分】---------------------------------------//描述:包含程序所依赖的头文件//---------------------------------------------------------------------------------------------- #include "opencv2/imgproc/imgproc.hpp"#include "opencv2/highgui/highgui.hpp"#include  //-----------------------------------【命名空间声明部分】---------------------------------------//描述:包含程序所使用的命名空间//-----------------------------------------------------------------------------------------------   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 > contours;vector hierarchy; //查找轮廓findContours( bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );//初始化dstMat 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图片文件错误~! "); 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;}

原图:

d2026f87c189919f1726cde53389e9c5.png

运行效果图:

56d279d2c6d0c764ad962b03775a73ba.png

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

acfa7409903f85014565a567f9eb1589.png

另外,在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,表示轨迹条的父窗口的名称。

这部分大概就是这些了。马不停蹄地向下一部分进发吧:)

二、亮度和对比度调整的理论依据

首先我们给出算子的概念。一般的图像处理算子都是一个函数,它接受一个或多个输入图像,并产生输出图像。下式给出了算子的一般形式

4fe98153dda7fe6cea1616ef2a6b7f6f.png

或者

177b81e083c80106315d09dcbe69bcdb.png

今天我们所讲解的图像亮度和对比度的调整操作,其实属于图像处理变换中比较简单的一种——点操作(pointoperators)。点操作有一个特点,仅仅根据输入像素值(有时可加上某些全局信息或参数),来计算相应的输出像素值。这类算子包括亮度(brightness)和对比度(contrast)调整,以及颜色校正(colorcorrection)和变换(transformations)。

最两种常用的点操作(或者说点算子),很显然,是乘上一个常数(对应对比度的调节)以及加上一个常数(对应亮度值的调节)。用公式表示出来就是这样:

1b8ba9076bef3cb3ab6727552f63a5d9.png

看到这个式子,我们关于图像亮度和对比度调整的策略就呼之欲出了。

其中:

参数f(x)表示源图像像素。

参数g(x) 表示输出图像像素。

参数a(需要满足a>0)被称为增益(gain),常常被用来控制图像的对比度。

参数b通常被称为偏置(bias),常常被用来控制图像的亮度。

而更近一步,我们这样改写这个式子:

b3caf94438d58b839e82859ed9acddc2.png

其中,i 和 j 表示像素位于第i行 和 第j列 。

那么,这个式子就可以用来作为我们在OpenCV中控制图像的亮度和对比度的理论公式了。

三、关于访问图片中的像素

访问图片中的像素有很多种方式,以后有机会浅墨会用个专题来讲解。目前我们可以先了解下面的这一种。

而为了执行

cae42ff67284949666eb9dc7b56fb217.png

这个运算 ,我们需要访问图像的每一个像素。因为是对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(y,x)[c]= saturate_cast( (g_nContrastValue*0.01)*(image.at(y,x)[c] ) + g_nBrightValue );                     }              }       }

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

  • 为了访问图像的每一个像素,我们使用这样的语法: image.at(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( (g_nContrastValue*0.01)*(image.at(y,x)[c] ) + g_nBrightValue )中的g_nContrastValue*0.01。

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

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

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

//-----------------------------------【程序说明】----------------------------------------------//  程序名称::【OpenCV入门教程之四】 创建Trackbar&图像对比度、亮度值调整 配套博文源码// VS2010版  OpenCV版本:2.4.8//  2014年3月18 日 Create by 浅墨//------------------------------------------------------------------------------------------------  //-----------------------------------【头文件包含部分】---------------------------------------//     描述:包含程序所依赖的头文件//----------------------------------------------------------------------------------------------#include #include#include"opencv2/imgproc/imgproc.hpp"#include  //-----------------------------------【命名空间声明部分】---------------------------------------//     描述:包含程序所使用的命名空间//-----------------------------------------------------------------------------------------------  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图片错误~!"); 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<(y,x)[c]= saturate_cast( (g_nContrastValue*0.01)*(g_srcImage.at(y,x)[c] ) + g_nBrightValue );                     }              }       }        //显示图像       imshow("【原始图窗口】", g_srcImage);       imshow("【效果图窗口】", g_dstImage);}

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

原图:

a46d704880719fdd86387727071a4410.png

可调节的效果图:

02803cdc94ee47020084ef51223300e3.png
2211ef82c16085bee9cdc26d1be7a155.png

本文转载于https://blog.csdn.net/zhmxy555/category_9262318.html

作者:浅墨_毛星云

对OpenCV感兴趣的可以去看原作者的其他文章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443648.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

find linux 目录深度_浪里淘沙,详解Linux系统中Find命令的实用技巧

知了小巷&#xff1a;浪里淘沙&#xff0c;详解Linux系统中Find命令的实用技巧。啊哈&#xff0c;找到了&#xff01;当我们需要在Linux系统上定位某个文件或目录时&#xff0c;find命令通常是必备之选。它使用起来非常简单&#xff0c;但有许多不同的可选项&#xff0c;允许我…

剑指offer之从上到下打印二叉树

从上到下打印出二叉树的每个节点&#xff0c;同一层的节点按照从左到右的顺序打印。 例如: 给定二叉树: [3,9,20,null,null,15,7], 返回&#xff1a; [3,9,20,15,7] 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode-cn.com/problem…

小米真蓝牙耳机说明书_小米真无线蓝牙耳机Air2 SE评测:仅需169元,享受随心畅听体验...

继小米真无线蓝牙耳机Air 2、小米真无线蓝牙耳机Air 2S之后&#xff0c;小米公司又于2020年5月19日再次推出了一款售价更为亲民的真无线蓝牙耳机新品——小米真无线蓝牙耳机Air2 SE&#xff0c;该机不仅延续了小米真无线蓝牙耳机Air 2系列的外观设计&#xff0c;支持开盒弹窗、…

三点外接圆_故地重游伪切圆——伪外接圆的基本性质

在思考一个有关于伪外接圆的等角线问题时&#xff0c;我回想起伪外接圆的一道小题目&#xff0c;这是2012年罗马尼亚大师杯的第六题&#xff0c;这道题目直接以结论的形式呈现出了伪外接圆的基本性质&#xff0c;是一道入门伪外接圆必做的精巧小题。当然有些读者可能从未见过&q…

一点等于多少厘米_马桶知识介绍,你了解马桶多少

我们可能并不了解我们经常运用的马桶&#xff0c;认为马桶便是简简单单的规划&#xff0c;没什么技术含量。其实不然&#xff0c;马桶的规划也包含了不少物理学原理。假如你家里的马桶出现毛病&#xff0c;首先要排查毛病的原因&#xff0c;但是假如不了解马桶结构图那就很难把…

1151压力变送器型号_日本进口横河EJA530E压力变送器型号解读!

横河EJA变送器对大家来说也许不陌生&#xff0c;但是对于EJA变送器的型号很多人还不是很懂&#xff0c;因为一个全型号代表这很多参数&#xff0c;每一个字母和每一个数字背后都是一个准确的参数&#xff0c;我们在选型的时候要提供必要的参数&#xff0c;更具参数选出合适的型…

怎样在数组末尾添加数据_如何利用C++实现可变长的数组?

应该执行什么功能&#xff1f;假设我们要实现一个将自动扩展的数组类&#xff0c;是否需要实现函数&#xff1f;让我们从下面主要功能使用的功能开始&#xff0c;看看我们需要实现哪些功能。输出结果&#xff1a;0 1 2 3 40 1 2 100 4您需要做什么才能实现上述功能&#xff1f;…

覆盖索引与联合索引_浅析MySQL的索引覆盖和索引下推

写在前面在MySQL数据库中&#xff0c;索引对查询的速度有着至关重要的影响&#xff0c;理解索引也是进行数据库性能调优的起点&#xff0c;索引就是为了提高数据查询的效率。今天我们来聊聊在MySQL索引优化中两种常见的方式&#xff0c;索引覆盖和索引下推索引覆盖要了解索引覆…

循环斐波那契数列_第五课:斐波那契数列(第一课时)

简介&#xff1a;又称黄金分割数列、因数学家列昂纳多斐波那契以兔子繁殖为例子而引入&#xff0c;故又称为“兔子数列”&#xff0c;指的是这样一个数列&#xff1a;1、1、2、3、5、8、13、21、34……在数学上&#xff0c;斐波那契数列以如下被以递推的方法定义&#xff1a;F(…

命令行 蓝牙_Ubuntu使用BlueZ驱动蓝牙dongle

蓝牙dongle即蓝牙适配器&#xff0c;一般为USB接口&#xff0c;通过USB连接到PC等设备。连接dongle后&#xff0c;PC即可使用驱动程序控制dongle连接其它蓝牙设备。本文主要介绍在Ubuntu系统中安装BlueZ的方法及蓝牙的使用。01获取BlueZBlueZ是Linux系统的官方蓝牙协议栈&#…

Java在Windows下导出xml文件到Linux服务器上

最近由于公司项目需要&#xff0c;学习了在Windows平台导出xml文件到Linux服务器上的指定目录下的方法&#xff0c;&#xff08;注&#xff1a;这里的我的Linux是在本机上装的虚拟机&#xff09;现在写下来记录一下&#xff01; 1.首先是项目截图&#xff1a; 2.主要是类&…

java peek函数_Java 8 Stream Api 中的 peek 操作

1. 前言我在 Java 8 Stream API中的 map 和flatMap 中讲述了Java8 Stream API中 map 操作和 flatMap 操作的区别。然后有小伙伴告诉我 peek 操作 也能实现元素的处理。但是你知道 map 和 peek 的区别吗&#xff1f; map 我们在开头文章已经讲过了&#xff0c;你可以去详细了解一…

iphone如何查看dns延迟_iPhone手机网速慢?1分钟教你设置DNS,网速立马翻一番

很多小伙伴在购机时选择苹果手机都是因为iOS系统的流畅度和精简性&#xff0c;但iPhone在可玩性和信号方面是不如安卓手机的。大家在使用过程中一定遇到过这样的情况&#xff0c;连接同一个无线网&#xff0c;但是苹果的网速总是要比安卓慢&#xff0c;这该怎么办呢&#xff1f…

copying mysql status_mysql慢查询copying to tmp table

windows server&#xff0c;无论修改my.ini的tmp_table_size&#xff0c;max_heap_table_size到多少&#xff0c;情况都一样。同样的表和查询语句&#xff0c;在本地运行&#xff0c;没出现慢查询。SELECTg.goods_id,g.goods_name,g.shop_price,g.goods_thumb,SUM(og.goods_num…

JDK 7,jdk1.7 安装及配置

1.打开网页&#xff1a;http://www.oracle.com 下载对应平台的合适JDK。 2. 双击下载的exe,如jdk-7u7-windows-i586.exe。 3.进入安装向导&#xff1a; 4.下一步&#xff0c;更改安装路径&#xff0c;选择安装所有组件。 更改为D:\jdk1.7.0_07\ 点击确定 5.下一步&#xff0c;…

c mysql 编译_MySQL编译安装之cmake

mysql版本5.5以上编译安装时需要用到软件cmake&#xff0c;cmake特性是独立于源码编译&#xff0c;编译工作可以在另外一个目录中而非源码目录中进行&#xff0c;mysql版本5.5以上编译安装时需要用到软件cmake&#xff0c;cmake特性是独立于源码编译&#xff0c;编译工作可以在…

vb连接mysql未发现_vb连接MySQL遇到的问题解决方法

1.安装mysql,2.安装MyODBC-standard-3.51.07-win.msi3:vb连接语句是:Public strcnn As StringPublic sql As StringPublic conn A1.安装mysql,2.安装MyODBC-standard-3.51.07-win.msi3:vb连接语句是:Public strcnn As StringPublic sql As StringPublic conn As New ADODB.Conn…

mysql里面有没有map类型_MySQL学习(二) 数据类型

MySQL支持多种列类型&#xff1a;数值类型、日期/时间类型和字符串(字符)类型。数值类型数值类型又分为整数型与小数型整数型下面的表显示了需要的每个整数类型的存储和范围创建一张表mysql> CREATE TABLE t_int (int_1 TINYINT,int_2 SMALLINT,int_3 MEDIUMINT,int_4 INT,i…

shell执行perl_【编程技巧(一)】在Perl、Shell和Python中传参与输出帮助文档

社会你明哥&#xff0c;人狠话又多&#xff01;【小明的碎碎念】与你不见不散&#xff01;作为一名搞数据的生物狗&#xff0c;咱们是生物狗中代码写得最六的&#xff0c;程序员中生物学得最好的——大家没意见吧&#xff0c;有意见请憋着跟随小明的步伐&#xff0c;让我们开开…

python之路2.0_Python之路【第二十一篇】:JS基础

1.2 ECMAScript尽管 ECMAScript 是一个重要的标准&#xff0c;但它并不是 JavaScript 唯一的部分&#xff0c;当然&#xff0c;也不是唯一被标准化的部分。实际上&#xff0c;一个完整的 JavaScript 实现是由以下 3 个不同部分组成的&#xff1a;● 核心(ECMAScript)● 文档对象…