8、OpenCV调整图像对比度和亮度

2023-10-26

一、学习目标

  • 理解图像对比度和亮度调整的原理
  • 对比三种不同亮度和对比度调整方法

二、原理理解

1、对比度
对比度指的是一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,差异范围越大代表对比越大,差异范围越小代表对比越小,好的对比率120:1就可容易地显示生动、丰富的色彩,当对比率高达300:1时,便可支持各阶的颜色。但对比率遭受和亮度相同的困境,现今尚无一套有效又公正的标准来衡量对比率,所以最好的辨识方式还是依靠使用者眼睛。

对比度对视觉效果的影响非常关键,一般来说对比度越大,图像越清晰醒目,色彩也越鲜明艳丽;而对比度小,则会让整个画面都灰蒙蒙的。高对比度对于图像的清晰度、细节表现、灰度层次表现都有很大帮助。在一些黑白反差较大的文本显示、CAD显示和黑白照片显示等方面,高对比度产品在黑白反差、清晰度、完整性等方面都具有优势。相对而言,在色彩层次方面,高对比度对图像的影响并不明显。对比度对于动态视频显示效果影响要更大一些,由于动态图像中明暗转换比较快,对比度越高,人的眼睛越容易分辨出这样的转换过程。

2、亮度
图象亮度是指画面的明亮程度,单位是堪德拉每平米(cd/m2)或称nits。图象亮度是从白色表面到黑色表面的感觉连续体,由反射系数决定,亮度侧重物体,重在“反射”。亮度是一副图像给人的一种直观感受,如果是灰度图像,则跟灰度值有关,灰度值越高则图像越亮。在RGB图像中,亮度体现为每个点的像素值的大小,像素值越大,亮度越高。

3、对比度和亮度调整公式
在这里插入图片描述
参数α>0β通常被称为增益参数和偏置参数;有时这些参数被称为分别控制对比度和亮度。
可以认为 f(x) 是源图像像素,g(x) 是输出图像像素。然后,我们可以更方便地将表达式写成:
在这里插入图片描述
其中i和j表示像素位于第i行和第j列。α 作为系数乘以源像素值,会扩大最大像素值和最小像素值之间的差异,从而提升对比度。β 作为加数,直接增大源像素值,能提升亮度。

三、对比度、亮度调整

1、直接套用公式实现

for( int y = 0; y < image.rows; y++ ) {
        for( int x = 0; x < image.cols; x++ ) {
            for( int c = 0; c < image.channels(); c++ ) {
                new_image.at<Vec3b>(y,x)[c] =
                  saturate_cast<uchar>( alpha*image.at<Vec3b>(y,x)[c] + beta );
            }
        }
}

执行操作 g(i,j) = α ⋅ f(i,j) + β ,访问图像中的每个像素。因为我们是在操作BGR图像,所以每个像素有三个值(B, G和R),所以我们需要分别访问它们。

2、使用 cv::Mat::convertTo() 函数
cv::Mat::convertTo 的函数原型为:

void cv::Mat::convertTo	(OutputArray 	m,
						 int 			rtype,
						 double 		alpha = 1,
						 double 		beta = 0)	const
  • 参数 m:输出矩阵;如果在操作之前没有正确的大小或类型,则重新分配。
  • 参数 rtype:所需的输出矩阵类型,或者更确切地说,深度,通道的数量与输入相同;如果rtype为负,则输出矩阵将与输入矩阵具有相同的类型。
  • 参数 alpha:可选的比例因子,用于调整对比度。
  • 参数 beta:可选的缩放因子,用于调整亮度。
    该函数是Mat对象的一个方法,用于将Mat的数组转换为另一种可选伸缩的数据类型。
    该方法将源像素值转换为目标数据类型。其转换公式为:

**m (x, y) = saturate_cast < rType >(α(∗)(x, y) +β)**
satate_cast <> 应用于最后以避免可能的数值溢出。计算公式基本与对比度和亮度调整公式一致。

调用代码如下:

image.convertTo(new_image, -1, alpha, beta);

3、现有公式的问题分析及改进

  • 公式理解

增加(/减少) β 值将增加(/减少)一个常量值到每个像素。超过 [0,255] 范围的像素将过于饱和(即大于(或小于)255(/ 0)的像素值将被调整为255(/ 0))。
在这里插入图片描述

浅灰色为原始图像的像素值分布直方图,Gimp中亮度= 80时为深灰色

直方图表示每种颜色级别的像素数量。一个黑暗的图像将有许多低颜色值的像素,因此直方图将在其左侧呈现一个峰值。当添加一个恒定的偏置 β 时,直方图会向右移动,因为我们已经向所有像素添加了恒定的偏置。

α 参数将改变直方图的水平扩展。如果α<1,颜色级别将被压缩,结果将是一个对比度较低的图像。
在这里插入图片描述

浅灰色为原始图像的直方图,Gimp中对比度< 0时为深灰色

你会发现,调整β 偏置值将提高亮度,但同时图像会感觉蒙上了一层纱,因为对比度降低,α增益可以用来减小这种影响,但由于饱和,我们会丢失一些原始亮区的细节。

  • γ 校正

Gamma校正可以使用输入值和映射输出值之间的非线性转换来校正图像的亮度:
在这里插入图片描述
由于这种关系是非线性的,所有像素的效果将不相同,并将取决于它们的原始值。
在这里插入图片描述

绘制不同的伽玛值

γ<1 时,原始的暗区会变亮,直方图会向右移动,而γ>1 与之相反。

  • 使用查找表实现 γ校正
 Mat lookUpTable(1, 256, CV_8U);
 uchar* p = lookUpTable.ptr();
 for( int i = 0; i < 256; ++i)
     p[i] = saturate_cast<uchar>(pow(i / 255.0, gamma_) * 255.0);
 Mat res = img.clone();
 LUT(img, lookUpTable, res);
  • 效果对比
    在这里插入图片描述

上图是直接套用公式调整对比度和亮度的效果,其中α=1.3 ,β=40。整体的亮度得到了提高,但是你可以注意到,由于存在数值饱和度(saturate_cast),云层已经非常饱和了。
在这里插入图片描述
上图是γ校正的效果,其中γ=0.4。gamma校正应该倾向于增加较少的饱和效应,因为映射是非线性的,而且不可能像在前一种方法中的数值饱和。
在这里插入图片描述

左:alpha, beta修正后直方图;中心:原始图像的直方图;右:gamma校正后的直方图

上图比较了三幅图的直方图(其中y的取值范围不同)。您可以注意到,大多数像素值都位于原始图像直方图的下方。经过α,β校正后,由于饱和和右移,我们可以在255处观察到一个大的峰值。经过伽马校正后,直方图向右移动,但黑暗区域的像素比明亮区域的像素移动更大(见伽马曲线图)。

四、完整代码示例

#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
    // 读入图像,判断读入是否成功
	string fileName = samples::findFile("O:\\CSDN\\7.jpg");
	Mat src = imread(fileName, IMREAD_COLOR);
	if (src.empty())
	{
		fprintf(stderr, "failed to load image: %s\n", fileName);
		system("pause");
		return EXIT_FAILURE;
	}

	Mat dst1, dst2, dst3;
	dst1 = Mat::zeros(src.size(), src.type());
	double alpha = 1.0;
	double beta = 0.0;
	double gama = 1.0;

    // 提示并输入 α  β  γ  的值
	cout << " Basic Linear Transforms " << endl;
	cout << "-------------------------" << endl;
	cout << "* Enter the alpha value [1.0-3.0]: "; cin >> alpha;
	cout << "* Enter the beta value [0-100]: ";    cin >> beta;
	cout << "* Enter the gama value [-1,1]: ";    cin >> gama;
    
    // 直接使用循环遍历每一个像素,应用公式
	double t1 = (double)getTickCount();
	for (int row=0;row<src.rows;++row)
		for(int col=0;col<src.cols;++col)
			for (int channel = 0; channel < src.channels(); ++channel)
			{
				dst1.at<Vec3b>(row, col)[channel] = saturate_cast<uchar>(alpha * src.at<Vec3b>(row, col)[channel] + beta);
			}
	double time1 = ((double)getTickCount() - t1) / getTickFrequency();
	cout << "Method by pixel use time:" << time1 << "(ms)" << endl;

    // 调用 convertTo() 函数调整对比度和亮度
	double t2 = (double)getTickCount();
	src.convertTo(dst2, -1, alpha, beta);
	double time2 = ((double)getTickCount() - t2) / getTickFrequency();
	cout << "Method by pixel use time:" << time2 << "(ms)" << endl;

    // 构建查找表
	Mat lookUpTable(1, 256, CV_8U);
	uchar* p = lookUpTable.ptr();
	for (int i = 0; i < 256; ++i)
		p[i] = saturate_cast<uchar>(pow(i / 255.0, gama) * 255.0);

   // 使用查找表进行对比度亮度调整
	double t3 = (double)getTickCount();
	LUT(src, lookUpTable, dst3);
	double time3 = ((double)getTickCount() - t3) / getTickFrequency();
	cout << "Method by γ correct use time:" << time3 << "(ms)" << endl;

    // 调整窗体大小,显示调整效果
	namedWindow("original", WINDOW_NORMAL);
	resizeWindow("original", Size(src.cols / 2, src.rows / 2));
	imshow("original", src);
	namedWindow("pixel set", WINDOW_NORMAL);
	resizeWindow("pixel set", Size(src.cols / 2, src.rows / 2));
	imshow("pixel set", dst1);
	namedWindow("convertTo", WINDOW_NORMAL);
	resizeWindow("convertTo", Size(src.cols / 2, src.rows / 2));
	imshow("convertTo", dst2);
	namedWindow("γ correct", WINDOW_NORMAL);
	resizeWindow("γ correct", Size(src.cols / 2, src.rows / 2));
	imshow("γ correct", dst3);
	waitKey(0);
	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

8、OpenCV调整图像对比度和亮度 的相关文章

  • display aspect ratio和遥控器上的调整

    刚刚通过实验新鲜总结出来的 科普一下 一张DVD电影碟片 其解码出来的视频画面大小总是固定的 比如NTSC的DVD 总是720x480 其实不一定 但可以姑且这么认为 显示比例为4 3 不过 值得注意的是 现代的DVD Player和电视机
  • C++模板

    模板定义 函数模板 template
  • websocket 心跳机制

    WebSocket 是一种在客户端和服务器之间创建持久连接的技术 为了保持连接的稳定性 就需要通过发送心跳消息来维持 WebSocket 连接 1 创建一个webscoket基本的使用 创建 WebSocket 对象 传入服务器地址 con
  • k8s--基础--23.7--认证-授权-准入控制--限制用户操作k8s资源的权限

    k8s 基础 23 7 认证 授权 准入控制 限制用户操作k8s资源的权限 1 生成一个证书 1 1 生成一个私钥 cd etc kubernetes pki umask 077 openssl genrsa out lucky key 2
  • 使用Mindstudio调用Modelarts进行模型训练

    使用MindStudio连接ModelArts进行模型训练 1 介绍 本文介绍如何使用MindStudio调用ModelArts资源进行模型训练 ModelArts是面向AI开发者的一站式开发平台 帮助用户快速创建和部署模型 管理全周期AI

随机推荐

  • 彩虹医疗器械彩超、内窥镜维修技能学习

    近几年随着医疗行业的快速发展 医疗器械的需求量不断增加 同时对医疗器械的维修和保养需求也在不断增长随着医疗技术的不断进步 新型 复杂的医疗器械不断涌现 这对维修技术提出了更高的要求 加强技术研发是必经之路 通过加强工程师培训 提高工程师工作
  • 安卓搜不到airpods_完美兼容 安卓手机连接AirPods必懂方法

    苹果的AirPods被很多人认为是最好的蓝牙耳机 除了iOS用户外 不少安卓用户也折服于其产品力 购买了它并搭配安卓机使用 不过AirPods和安卓机之间的配合 显然不如和iOS那样天衣无缝 虽然AirPods也能通过蓝牙连接安卓听歌 但不
  • 微信小程序隐私协议接入

    自2023年9月15日起 对于涉及处理用户个人信息的小程序开发者 微信要求 仅当开发者主动向平台同步用户已阅读并同意了小程序的隐私保护指引等信息处理规则后 方可调用微信提供的隐私接口 相关公告见 关于小程序隐私保护指引设置的公告 微信开放社
  • javaweb(四)——过滤器与监听器

    文章目录 过滤器Filter 基本概念 滤波器的分类 时域和频域表示 滤波器类型 1 低通滤波器 Low Pass Filter 2 高通滤波器 High Pass Filter 3 带通滤波器 Band Pass Filter 4 带阻滤
  • 如果您在搭载 Apple M1 芯片的 Mac 上重新安装 macOS 时收到个性化错误

    在重新安装时 您可能会收到一条信息 提示在准备更新期间出现了错误 如果您抹掉了搭载 Apple M1 芯片的 Mac 您可能无法通过 macOS 恢复功能重新安装 macOS 系统可能会显示信息 准备更新时出错 未能个性化软件更新 请再试一
  • mysql 安装 中途遇到的意外:it seems that the port 3306 is already in use 和 卡到最后一个页面

    由于软件工程大作业需要 需要复习数据库 重装数据库 中途遇到两个意外 it seems that the port 3306 is already in use 和 一直卡到最后一个页面 目录 首次安装 意外一 it seems that
  • RAID介绍及RAID10配置实例

    目录 一 RAID磁盘阵列介绍 二 RAID磁盘阵列详解 2 1RAID0 条带化存储 2 2RAID 1 镜像存储 2 3RAID5 2 4RAID6 2 5 RAID 1 0 先做镜像 再做条带 2 6RAID 0 1 先做条带 在做镜
  • logstash数据同步

    1 编写logstash的pipeline文件 abc conf input stdin jdbc jdbc connection string gt jdbc mysql ip 3306 db serverTimezone Asia Sh
  • 我在Gazebo中加入了IMU传感器,并用Python发布了话题和传感器数据,可是为什么数据都为0,哪里漏了或者错了

    Gazebo SDF 文件中传感器的添加如下 话题和数据发布的代码如下 使用如下指令查看话题数据 rtopic echo Imu 1 获得的IMU数据都为0 有人知道哪里不对吗 能帮助的话就太感谢了
  • CloudCompare 二次开发(8)——提取点云的重叠区域

    目录 一 概述 二 代码集成 三 结果展示 本文由CSDN点云侠原创 原文链接 爬虫网站自重 一 概述 使用CloudCompare与PCL联合编程实现两期点云数据重叠区域的获取 具体计算原理见 PCL 提取两片点云的重叠部分并保存 二 代
  • 华为OD机试真题- 荒岛逃生游戏-2023年OD统一考试(B卷)

    题目描述 一个荒岛上有若干人 岛上只有一条路通往岛屿两端的港口 大家需要逃往两端的港口才可逃生 假定每个人移动的速度一样 且只可选择向左或 向右逃生 若两个人相遇 则进行决斗 战斗力强的能够活下来 并损失掉与对方相同的战斗力 若战斗力相同
  • 【自学51单片机】5 --- 定时器介绍、数码管静态显示、逻辑运算符和逻辑电路符号

    文章目录 1 逻辑运算和逻辑电路 1 1 C语言逻辑运算符 1 2 逻辑电路符号 2 定时器学习 重点非难点 2 1 时钟周期和机器周期的介绍 2 2 定时器的介绍 2 2 1 定时器寄存器介绍 2 2 2 定时器模式工作电路逻辑图 2 3
  • github可以做文件服务器吗,局域网搭建git服务端并使用Github Desktop作为客户端

    在使用了github的客户端软件Github Desktop之后 感受到了git的便捷 研究了一下与svn的区别之后 结合目前的团队情况 决定下个项目开始使用git 整理一下 这里服务端为centos 6 5 客户端为mac 一 服务端安装
  • Mysql 架构图

    Mysql 架构图 第一层 对客户端的连接处理 安全认证 授权等 每个客户端连接都会在服务端拥有一个线程 每个连接发起的查询都会在对应的单独线程中执行 第二层 MySQL的核心服务功能层 包括查询解析 分析 查询缓存 内置函数 存储过程 触
  • 电脑怎样执行编程语言的?

    链接 https www zhihu com question 29227521 answer 154819061 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 这个问题真的是很大 让我们自顶向下的解释 在
  • 2023华为OD机试真题【最大利润/贪心算法】

    题目描述 商人经营一家店铺 有number 种商品 由于仓库限制每件商品的最大持有数量是 item index 每种商品的价格是 price item index day 通过对商品的买进和卖出获取利润 请给出商人在 days 天内能获取的
  • 在Windows10下使用GPU安装TensorFlow

    1 安装Python和pip 在Windows环境安装Python 3 x版本 通常安装包中集成了pip工具 安装会非常简单方便 具体见 https www python org downloads windows 按以上网站的信息 获取到
  • tomcat端口号被占用

    这里有两种方法 第一个是通过命令窗口终止 第二个是使用任务管理器 1 端口被占用 可以用cmd window R 第一步 输入netstat ano 找到被占用的端口号 netstat ano 也可以输入netstat aon findst
  • matlab和stata,Stata和Matlab联合处理金融数据

    Stata是统计学专业软件 可以很方便的对数据处理 但几乎只能按照整行整列进行 而且每次只能加载一个矩阵 dta文件 如果要用到多个矩阵数据进行操作或进行复杂的循环控制 就力不从心了 而Matlab工业界广泛使用的数据分析处理工具 对矩阵支
  • 8、OpenCV调整图像对比度和亮度

    OpenCV调整图像对比度和亮度 一 学习目标 二 原理理解 三 对比度 亮度调整 四 完整代码示例 一 学习目标 理解图像对比度和亮度调整的原理 对比三种不同亮度和对比度调整方法 二 原理理解 1 对比度 对比度指的是一幅图像中明暗区域最