C++ OpenCV实现白平衡之完美反射算法

目录
  • 实现原理
  • 功能函数代码
  • C++测试代码
  • 测试效果

实现原理

白平衡的意义在于,对在特定光源下拍摄时出现的偏色现象,通过加强对应的补色来进行补偿,使白色物体能还原为白色。

完美反射算法是白平衡各种算法中较常见的一种,比灰度世界算法更优。它假设图像世界中最亮的白点是一个镜面,能完美反射光照;基于白点,将三通道的数值进行适当地调整,以达到白平衡效果;除此之外,还需要统计最亮的一定区间的三通道均值,该均值与该通道最大值的差距决定了该通道调整的力度。

通俗的讲,若图像中绿色分量最大值是255,但是绿色最亮的前百分之10个点的平均值只有80,说明原图的绿色分量整体较低,需要对其加强;若最大值只有100,那么加强的系数就较低,白平衡的效果就不达预期。这就是完美反射算法比较依赖图像中存在白点的原因,白点的三通道灰度值接近【255,255,255】。最下方将用实际图像作进一步说明,以帮助读者理解。

完美反射算法的实现流程如下:

1.计算图像RGB三通道各自的灰度最大值Rmax、Gmax、Bmax。

2.利用三通道数值和,确定图像最亮区间的下限T。

3.计算图像三通道数值和大于T的点的三通道均值Rm、Gm、Bm。

4.计算三通道的补偿系数,即单通道最大值除以单通道亮区平均值。

功能函数代码

// 白平衡-完美反射
cv::Mat WhiteBalcane_PRA(cv::Mat src)
{
	cv::Mat result = src.clone();
	if (src.channels() != 3)
	{
		cout << "The number of image channels is not 3." << endl;
		return result;
	}

	// 通道分离
	vector<cv::Mat> Channel;
	cv::split(src, Channel);

	// 定义参数
	int row = src.rows;
	int col = src.cols;
	int RGBSum[766] = { 0 };
	uchar maxR, maxG, maxB;

	// 计算单通道最大值
	for (int i = 0; i < row; ++i)
	{
		uchar *b = Channel[0].ptr<uchar>(i);
		uchar *g = Channel[1].ptr<uchar>(i);
		uchar *r = Channel[2].ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			int sum = b[j] + g[j] + r[j];
			RGBSum[sum]++;
			maxB = max(maxB, b[j]);
			maxG = max(maxG, g[j]);
			maxR = max(maxR, r[j]);
		}
	}

	// 计算最亮区间下限T
	int T = 0;
	int num = 0;
	int K = static_cast<int>(row * col * 0.1);
	for (int i = 765; i >= 0; --i)
	{
		num += RGBSum[i];
		if (num > K)
		{
			T = i;
			break;
		}
	}

	// 计算单通道亮区平均值
	double Bm = 0.0, Gm = 0.0, Rm = 0.0;
	int count = 0;
	for (int i = 0; i < row; ++i)
	{
		uchar *b = Channel[0].ptr<uchar>(i);
		uchar *g = Channel[1].ptr<uchar>(i);
		uchar *r = Channel[2].ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			int sum = b[j] + g[j] + r[j];
			if (sum > T)
			{
				Bm += b[j];
				Gm += g[j];
				Rm += r[j];
				count++;
			}

		}
	}
	Bm /= count;
	Gm /= count;
	Rm /= count;

	// 通道调整
	Channel[0] *= maxB / Bm;
	Channel[1] *= maxG / Gm;
	Channel[2] *= maxR / Rm;

	// 合并通道
	cv::merge(Channel, result);

	return result;
}

C++测试代码

#include <iostream>
#include <opencv.hpp>

using namespace std;

// 白平衡-完美反射
cv::Mat WhiteBalcane_PRA(cv::Mat src)
{
	cv::Mat result = src.clone();
	if (src.channels() != 3)
	{
		cout << "The number of image channels is not 3." << endl;
		return result;
	}

	// 通道分离
	vector<cv::Mat> Channel;
	cv::split(src, Channel);

	// 定义参数
	int row = src.rows;
	int col = src.cols;
	int RGBSum[766] = { 0 };
	uchar maxR, maxG, maxB;

	// 计算单通道最大值
	for (int i = 0; i < row; ++i)
	{
		uchar *b = Channel[0].ptr<uchar>(i);
		uchar *g = Channel[1].ptr<uchar>(i);
		uchar *r = Channel[2].ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			int sum = b[j] + g[j] + r[j];
			RGBSum[sum]++;
			maxB = max(maxB, b[j]);
			maxG = max(maxG, g[j]);
			maxR = max(maxR, r[j]);
		}
	}

	// 计算最亮区间下限T
	int T = 0;
	int num = 0;
	int K = static_cast<int>(row * col * 0.1);
	for (int i = 765; i >= 0; --i)
	{
		num += RGBSum[i];
		if (num > K)
		{
			T = i;
			break;
		}
	}

	// 计算单通道亮区平均值
	double Bm = 0.0, Gm = 0.0, Rm = 0.0;
	int count = 0;
	for (int i = 0; i < row; ++i)
	{
		uchar *b = Channel[0].ptr<uchar>(i);
		uchar *g = Channel[1].ptr<uchar>(i);
		uchar *r = Channel[2].ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			int sum = b[j] + g[j] + r[j];
			if (sum > T)
			{
				Bm += b[j];
				Gm += g[j];
				Rm += r[j];
				count++;
			}

		}
	}
	Bm /= count;
	Gm /= count;
	Rm /= count;

	// 通道调整
	Channel[0] *= maxB / Bm;
	Channel[1] *= maxG / Gm;
	Channel[2] *= maxR / Rm;

	// 合并通道
	cv::merge(Channel, result);

	return result;
}

int main()
{
	// 载入原图
	cv::Mat src = cv::imread("test21.jpg");

	// 白平衡-完美反射
	cv::Mat result = WhiteBalcane_PRA(src);

	// 显示
	cv::imshow("src", src);
	cv::imshow("result", result);
	cv::waitKey(0);

	return 0;
}

测试效果

图1 原图

图2 白平衡后图像

如图1所示,是傍晚的一张图像,众所周知,傍晚的色温是较低的,此时采用高于傍晚色温的色温值拍照,就会得到一张暖色系的图片,偏黄;对其进行白平衡,使图片颜色回归真实的环境色温,就得到如图2的效果。

如果你用过灰度世界算法,你会发现完美反射算法的效果更亮些;这是因为蓝通道最大值和蓝通道亮区平均值的差距较大,因而补偿的强度很强;若原图中不存在白色区,那蓝通道的补偿就会较弱,达不到较好的预期,因此该算法所处理的图像中最好有较白的点。

图3 单色原图

图4 单色图白平衡效果

如图3所示,是一张色彩相对一致的图像,整体呈粉色系。灰度世界法将三通道数值进行平均再补偿,就会使三通道的数值趋近一致,进而呈现灰色;而完美反射算法,计算的是三通道各自数值最大值和其亮区平均值的差距,再进行补偿,因此三通道的数值都会适当加强,使光感更强,即图片更亮。

接下来做个有趣的测试,将原本粉色的墙纸设为较纯的绿色。

图5 调色后的图像

图6 白平衡效果图

如图5所示,因为图像中存在色调相冲的两个部分,完美反射算法的优势在这种场景下体现的很明显。因为绿色区域较大,灰度世界算法中单纯的计算均值再平衡,会无脑地将整图的绿色分量降低,红色分量提高,使得结果异常滑稽;而完美反射算法,因为图中有白值,三通道的最大值均在250左右,对绿色分量而言,其最亮区的均值接近于230,而红色分量和蓝色分量而言,其最亮区的均值也接近于200多,因此三通道的平衡结果就是整体提亮,而不是被无脑平均。

灰度世界算法效果图见:

C++ OpenCV实现白平衡之灰度世界算法

到此这篇关于C++ OpenCV实现白平衡之完美反射算法的文章就介绍到这了,更多相关C++ OpenCV完美反射算法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ OpenCV实现图像双三次插值算法详解

    目录 前言 一.图像双三次插值算法原理 二.C++ OpenCV代码 1.计算权重矩阵 2.遍历插值 3. 测试及结果 前言 近期在学习一些传统的图像处理算法,比如传统的图像插值算法等.传统的图像插值算法包括邻近插值法.双线性插值法和双三次插值法,其中邻近插值法和双线性插值法在网上都有很详细的介绍以及用c++编写的代码.但是,网上关于双三次插值法的原理介绍虽然很多,也有对应的代码,但是大多都不是很详细.因此基于自己对原理的理解,自己编写了图像双三次插值算法的c++ opencv代码,在这里记录一

  • C++ opencv利用grabCut算法实现抠图示例

    目录 前言 一.grabCut函数 二.compare函数 三.代码 前言 grabCut算法利用了图像中的纹理(颜色)信息和边界(反差)信息,只用少量的用户交互操作,即可得到比较好的分割结果,和分水岭顺丰比较相似,但是计算速度比较慢,得到的结果比较精确 用法:输入一幅图片并对一些像素做属于背景或属于前景的标记,算法会根据这个局部标记计算出整个图像中前景和背景的分割线. 一.grabCut函数 void grabCut(InputArray img, InputOutputArray mask,

  • C++结合OpenCV实现RRT算法(路径规划算法)

    目录 1.RRT算法简介 2.算法整体框架流程 2.1 rand点的建立 2.2 near和new点的建立 2.3 安全性检查 2.4 算法结束判断 3.RRT代码框架 3.1 主函数 3.2 地图数据的获取 3.3 RRT算法的实现 3.3.1 起点入树 3.3.2 rand点的获取 3.3.3 near点的获取 3.3.4 new点的获取 3.3.5 安全性检测 3.4 可视化显示 4. 代码运行过程 1.RRT算法简介 代码链接:RRT动图展示 RRT 2.算法整体框架流程 RRT算法整体

  • C++中实现OpenCV图像分割与分水岭算法

    分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水岭算法的一个重要特征. API介绍 void watershed( InputArray image, InputOutputArray markers ); 参数说明: image: 必须是一个8bit 3通道彩色图像矩阵序列 markers: 在执行分水岭函数watershed之前,必须对第二个参数markers

  • C++ OpenCV实现白平衡之完美反射算法

    目录 实现原理 功能函数代码 C++测试代码 测试效果 实现原理 白平衡的意义在于,对在特定光源下拍摄时出现的偏色现象,通过加强对应的补色来进行补偿,使白色物体能还原为白色. 完美反射算法是白平衡各种算法中较常见的一种,比灰度世界算法更优.它假设图像世界中最亮的白点是一个镜面,能完美反射光照:基于白点,将三通道的数值进行适当地调整,以达到白平衡效果:除此之外,还需要统计最亮的一定区间的三通道均值,该均值与该通道最大值的差距决定了该通道调整的力度. 通俗的讲,若图像中绿色分量最大值是255,但是绿

  • C++ OpenCV实现白平衡之灰度世界算法

    目录 实现原理 功能函数代码 C++测试代码 测试效果 实现原理 白平衡的意义在于,对在特定光源下拍摄时出现的偏色现象,通过加强对应的补色来进行补偿,使白色物体能还原为白色. 灰度世界算法是白平衡各种算法中最基本的一种.它假设图像世界具备丰富色彩,红蓝绿三通道的灰度值在平均后趋近一致,该值作为“灰色”:若各通道均值偏离“灰色”,则将其进行补偿,使其回归“灰色”,进而实现白平衡的效果. 通俗的讲,若图像中绿色较强,蓝色和红色较弱,则用了灰度世界算法后,绿色会适当减弱,蓝色和红色会适当加强,这样就使

  • Python OpenCV基于霍夫圈变换算法检测图像中的圆形

    目录 第一章:霍夫变换检测圆 ① 实例演示1 ② 实例演示2 ③ 霍夫变换函数解析 第二章:Python + opencv 完整检测代码 ① 源代码 ② 运行效果图 第一章:霍夫变换检测圆 ① 实例演示1 这个是设定半径范围 0-50 后的效果. ② 实例演示2 这个是设定半径范围 50-70 后的效果,因为原图稍微大一点,半径也大了一些. ③ 霍夫变换函数解析 cv.HoughCircles() 方法 参数分别为:image.method.dp.minDist.param1.param2.mi

  • Opencv分水岭算法学习

    分水岭算法可以将图像中的边缘转化成"山脉",将均匀区域转化为"山谷",这样有助于分割目标. 分水岭算法是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中的每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭.分水岭的概念和形成可以通过模拟浸入过程来说明:在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响区域慢慢向外扩展,

  • python opencv之分水岭算法示例

    本文介绍了python opencv之分水岭算法示例,分享给大家,具体如下: 目标 使用分水岭算法对基于标记的图像进行分割 使用函数cv2.watershed() 原理: 灰度图像可以被看成拓扑平面,灰度值高的区域可以看出山峰,灰度值低的区域可以看成是山谷.向每一个山谷当中灌不同颜色的水.水位升高,不同山谷的水会汇合,为防止不同山谷的水汇合,小在汇合处建立起堤坝.然后继续灌水,然后再建立堤坝,直到山峰都掩模.构建好的堤坝就是图像的分割. 此方法通常会得到过渡分割的结果,因为图像中的噪声以及其他因

  • OpenCV 边缘检测

    边缘在人类视觉和计算机视觉中均起着重要的作用. 人类能够仅凭一张背景剪影或一个草图就识别出物体类型和姿态. 其中OpenCV提供了许多边缘检测滤波函数,这些滤波函数都会将非边缘区域转为黑色,将边缘区域转为白色或其他饱和的颜色. 不过这些滤波函数都很容易将噪声错误地识别为边缘,所以需要进行模糊处理. 本次的模糊操作使用高斯模糊(低通滤波器),最常用的模糊滤波器(平滑滤波器)之一,是一个削弱高频信号强度的低通滤波器. 低通滤波器,在像素与周围像素的亮度差值小于一个特定值时,平滑该像素的亮度,主要用于

  • 用Python+OpenCV对比图像质量的几种方法

    前言 图片的本质就是大量像素在二维平面上的组合,每个像素点用数字化方式记录颜色.可以直观的想象,一张图片就是一个巨大的电子栅格,每个格子内有一盏灯泡,这个灯泡可以变换256的三次方种颜色,就像下面这张卡通像素图一样,越清晰的图片像素越密集. 这一次来看看OpenCV提供的两种图像质量对比方式(PSNR & SSIM)及其扩展, 这篇文章会涉及到一点数学公式,顺便介绍一个我用过的生成公式的最佳在线编辑工具,秒杀所有收费工具. 链接在这里, 请收好: https://www.mathcha.io/e

  • PyQt5+Caffe+Opencv搭建人脸识别登录界面

    最近开始学习Qt,结合之前学习过的caffe一起搭建了一个人脸识别登录系统的程序,新手可能有理解不到位的情况,还请大家多多指教. 我的想法是用opencv自带的人脸检测算法检测出面部,利用caffe训练好的卷积神经网络来提取特征,通过计算当前检测到的人脸与已近注册的所有用户的面部特征之间的相似度,如果最大的相似度大于一个阈值,就可以确定当前检测到的人脸对应为这个相似度最大的用户了. ###Caffe人脸识别 因为不断有新的用户加入,然而添加新用户后重新调整CNN的网络结构太费时间,所以不能用CN

  • python 下 CMake 安装配置 OPENCV 4.1.1的方法

    CMake 安装配置 OPENCV 4.1.1 解决各种问题 方法一 python 可以直接pip install opencv-contrib-python==3.4.x.x 安装,老版本的库包含SIFT等算法.但是,python不支持GPU的,对于JAVA等其他语言想调用opencv或者想使用更更高级的算法,那么还是必须得安装更高版本,下面介绍另外一种方法. 这个方法不提供SIFT和 SURF算法,因为这两个算法申请了专利,所有主要通过CMake设置OPENCV_ENABLE_NONFREE

  • Python OpenCV快速入门教程

    OpenCV OpenCV是计算机视觉中最受欢迎的库,最初由intel使用C和C ++进行开发的,现在也可以在python中使用.该库是一个跨平台的开源库,是免费使用的.OpenCV库是一个高度优化的库,主要关注实时应用程序. OpenCV库是2500多种优化算法的组合,可用于检测和识别不同的人脸,实时识别图像中的对象,使用视频和网络摄像头对不同的人类动作进行分类,跟踪摄像机的运动,跟踪运动对象(例如汽车,人等),实时计数对象,缝合图像来产生高分辨率图像,从图像数据库中查找相似的图像,从使用闪光

随机推荐