OpenCV——调整图片的对比度、亮度和饱和度

一、图片的对比度和亮度调整
1、原理:
  • f(row, col):原始图像的像素。
  • g(row, col):调整后图像的像素。
  • a(a>0:称为增益(gain),常常被用来控制图像的对比度,其取值范围一般为0.0-3.0
  • b:称为偏置(bias),常常被用来控制图像的亮度。
  • g(row, col) = a*f(row, col) + b:随原始图像进行对比度亮度调节的公式。
  • new_img.at<Vec3b> (row, col)[c]:opencv访问图片每个像素的语法。
  • saturate_cast<uchar>():防止溢出。当运算完之后,结果为负,则转为0,结果超出255,则为255。
2、C++ OpenCV核心代码:

遍历原始图片的每一个像素,对R,G,B分别使用公式进行变换。

void contrast_bright (int, void*)
{
	contrastValue_f = 0.1 * contrastValue; // 为了使滑动条调节的幅度变大,把 contrastValue值进行缩小。
	for (int row = 0; row < img.rows; row++)
	{
		for (int col = 0; col < img.cols; col++)
		{
			for (int c = 0; c < 3; c++) {
				new_img.at<Vec3b> (row, col)[c] = saturate_cast<uchar>(contrastValue_f * (img.at<Vec3b> (row, col)[c]) + brightValue);  // g(x,y) = af(x,y) + b; a 是对比度调节,b是亮度调节
			}
		}
	}
	imshow ("Effect Image", new_img);
}
二、图片的饱和度调整

网上关于图片饱和度调整的算法很多,不知道选择哪一个。所以就都试一遍看看哪个效果好。这里,参考了:https://blog.csdn.net/u012198575/article/details/82985482 这篇文章提及的算法,算法思路写的比较清楚。

1、Photoshop饱和度调整思想(我也不知道是不是PS的~~):
  1. 计算每个像素点关于RGB的最大值,最小值。
  2. 设 delta 为两值的差 / 255,value为两值的和 / 255。
  3. 两值之差 delta 为0不做操作,即跳过该像素点。否则,进行下面操作:
  4. 把RGB图像转换成HSL图像(Hue:色彩,Saturability:饱和度,Light:亮度)
  5. light = value / 2,如果 light < 0.5, sat = delta / value;否则: sat = delta / (2-value);
  6. 最后根据增量判断做怎么样的处理,将转换后的新的RGB值存到新图片内。
2、C++核心代码:
void saturability (int, void*)
{
	float increment = (saturation - 80) * 1.0 / max_increment;
	for (int col = 0; col < img.cols; col++)
	{
		for (int row = 0; row < img.rows; row++)
		{
			// R,G,B 分别对应数组中下标的 2,1,0
			uchar r = img.at<Vec3b> (row, col)[2];		
			uchar g = img.at<Vec3b> (row, col)[1];
			uchar b = img.at<Vec3b> (row, col)[0];

			float maxn = max (r, max (g, b));
			float minn = min (r, min (g, b));

			float delta, value;
			delta = (maxn - minn) / 255;
			value = (maxn + minn) / 255;

			float new_r, new_g, new_b;

			if (delta == 0)		 // 差为 0 不做操作,保存原像素点
			{
				new_img.at<Vec3b> (row, col)[0] = new_b;
				new_img.at<Vec3b> (row, col)[1] = new_g;
				new_img.at<Vec3b> (row, col)[2] = new_r;
				continue;
			}

			float light, sat, alpha;
			light = value / 2;

			if (light < 0.5)
				sat = delta / value;
			else
				sat = delta / (2 - value);

			if (increment >= 0)
			{
				if ((increment + sat) >= 1)
					alpha = sat;
				else
				{
					alpha = 1 - increment;
				}
				alpha = 1 / alpha - 1;
				new_r = r + (r - light * 255) * alpha;
				new_g = g + (g - light * 255) * alpha;
				new_b = b + (b - light * 255) * alpha;
			}
			else
			{
				alpha = increment;
				new_r = light * 255 + (r - light * 255) * (1 + alpha);
				new_g = light * 255 + (g - light * 255) * (1 + alpha);
				new_b = light * 255 + (b - light * 255) * (1 + alpha);
			}
			new_img.at<Vec3b> (row, col)[0] = new_b;
			new_img.at<Vec3b> (row, col)[1] = new_g;
			new_img.at<Vec3b> (row, col)[2] = new_r;
		}
	}
	imshow ("Effect Image", new_img);
}
三、OpenCV实现的图片的对比度、亮度、饱和度完整代码
#include<iostream>
#include<algorithm>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <opencv2\imgproc\types_c.h>

using namespace std;
using namespace cv;

int contrastValue;	// 对比度值
float contrastValue_f; // 实际使用的对比度值,对contrastValue进行的缩小处理
int brightValue;   // 亮度值
int saturation;	// 饱和度
const int max_increment = 200;
Mat img, new_img;	   //img:原始图像; new_img:最终要展示图像;

void contrast_bright (int, void*);
void saturability (int, void*);

// 调整对比度和亮度
void contrast_bright (int, void*)
{
	contrastValue_f = 0.1 * contrastValue;
	for (int row = 0; row < img.rows; row++)
	{
		for (int col = 0; col < img.cols; col++)
		{
			for (int c = 0; c < 3; c++) {
				new_img.at<Vec3b> (row, col)[c] = saturate_cast<uchar>(contrastValue_f * (img.at<Vec3b> (row, col)[c]) + brightValue);  // g(x,y) = af(x,y) + b; a 是对比度调节,b是亮度调节
			}
		}
	}
	imshow ("Effect Image", new_img);
}

//调整饱和度
void saturability (int, void*)
{
	float increment = (saturation - 80) * 1.0 / max_increment;
	for (int col = 0; col < img.cols; col++)
	{
		for (int row = 0; row < img.rows; row++)
		{
			// R,G,B 分别对应数组中下标的 2,1,0
			uchar r = img.at<Vec3b> (row, col)[2];		
			uchar g = img.at<Vec3b> (row, col)[1];
			uchar b = img.at<Vec3b> (row, col)[0];

			float maxn = max (r, max (g, b));
			float minn = min (r, min (g, b));

			float delta, value;
			delta = (maxn - minn) / 255;
			value = (maxn + minn) / 255;

			float new_r, new_g, new_b;

			if (delta == 0)		 // 差为 0 不做操作,保存原像素点
			{
				new_img.at<Vec3b> (row, col)[0] = new_b;
				new_img.at<Vec3b> (row, col)[1] = new_g;
				new_img.at<Vec3b> (row, col)[2] = new_r;
				continue;
			}

			float light, sat, alpha;
			light = value / 2;

			if (light < 0.5)
				sat = delta / value;
			else
				sat = delta / (2 - value);

			if (increment >= 0)
			{
				if ((increment + sat) >= 1)
					alpha = sat;
				else
				{
					alpha = 1 - increment;
				}
				alpha = 1 / alpha - 1;
				new_r = r + (r - light * 255) * alpha;
				new_g = g + (g - light * 255) * alpha;
				new_b = b + (b - light * 255) * alpha;
			}
			else
			{
				alpha = increment;
				new_r = light * 255 + (r - light * 255) * (1 + alpha);
				new_g = light * 255 + (g - light * 255) * (1 + alpha);
				new_b = light * 255 + (b - light * 255) * (1 + alpha);
			}
			new_img.at<Vec3b> (row, col)[0] = new_b;
			new_img.at<Vec3b> (row, col)[1] = new_g;
			new_img.at<Vec3b> (row, col)[2] = new_r;
		}
	}
	imshow ("Effect Image", new_img);
}

int main ()
{
	img = imread ("test.jpg");		// 加载图片,保存在 Mat 对象 img 中
	new_img = Mat::zeros (img.size (), img.type ());    // 最终要展示结果的对象

	contrastValue = 1;	//对比度初始值
	brightValue = 1;	//亮度初始值
	saturation = 10;	//饱和度初始值

	namedWindow ("Effect Image", WINDOW_NORMAL);		// 创建效果图窗口

	createTrackbar ("Contrast:", "Effect Image", &contrastValue, 100, contrast_bright);	// 创建对比度滑动条
	createTrackbar ("Brightness:", "Effect Image", &brightValue, 200, contrast_bright);	// 创建亮度滑动条
	createTrackbar ("Saturability:", "Effect Image", &saturation, 200, saturability); // 创建饱和度滑动条

	// 函数回调,因为是全局变量,所以 userdata 为0
	contrast_bright (contrastValue, 0);
	contrast_bright (brightValue, 0);
	saturability (saturation, 0);
	
	cv::waitKey (0);
	return 0;
}

发布了176 篇原创文章 · 获赞 46 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_43207025/article/details/102635455