OpenCV(C++)图像处理基础05:图像的亮度与对比度

Posted 源代码杀手

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV(C++)图像处理基础05:图像的亮度与对比度相关的知识,希望对你有一定的参考价值。

0、知识点


案例: 像素值越接近255越白。两参数则是调整像素和对比度。

Api接口:

复习Vec3f :
Vec3f表示的是3通道float类型的 Vect,就相当于3通道float类型的图像(这是其中一个具体化),解释可以从源代码中看出来。

下面给出一个具体的例子:
Vec3f point = Vec3f(10,10,3.2);//Float, 3 components
Mat mat(3,3,CV_32FC3,);//3 channel matrix
Vec3f v3f = mat.at(y, x);//read color values for pixel (y,x)
这里注释一下:Vec3f是一种数据类型,其是3通道的float,后面的mat.at(y, x)是访问图像的一种方式。(可以从定义形式上看出来 int a=…)
对于mat的理解,可以认为mat.at是mat的一种访问形式,其有点类似vector。

复习Vec3b:
Vec3b可以看作是vector<uchar, 3>。
简单而言就是一个uchar类型的,长度为3的vector向量。
由于在OpenCV中,使用imread读取到的Mat图像数据,都是用uchar类型的数据存储,对于RGB三通道的图像,每个点的数据都是一个Vec3b类型的数据。使用at定位方法如下:

img.at(row, col)[0] = 255;  // 这是指修改B通道数据
img.at(row, col)[1] = 255;  // 这是指修改G通道数据
img.at(row, col)[2] = 255;  // 这是指修改R通道数据

1、测试代码

创建一张跟原图像大小和类型一致的空白图像,像素值初始化为0;
saturate_cast(value)确保值在0-255之间;
Mat.at(y,x)[index] = value每个像素点每个通道赋值

测试图像:

测试代码:

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

using namespace cv;

#if 1
int main(int argc, char** argv) {
	Mat src, dst;
	//图片路径
	src = imread("D:/CV2021/opencv_test0/Project1/test_img/40c.png");

	if (!src.data) {
		printf("could not load image...\\n");
		return -1;
	}

	char input_win[] = "input image";
	//cvtColor(src, src, CV_BGR2GRAY); //灰度
	namedWindow(input_win, CV_WINDOW_AUTOSIZE);
	imshow(input_win, src);

	// contrast and brigthtness changes 
	int height = src.rows;
	int width = src.cols;
	dst = Mat::zeros(src.size(), src.type());//图像初始化 BGR
	float alpha = 1.2;
	float beta = 30;

	//Mat m1;
	//src.convertTo(m1, CV_32F);  
	for (int row = 0; row < height; row++) {
		for (int col = 0; col < width; col++) {
			if (src.channels() == 3) {
				//RGB三通道
				float b = src.at<Vec3b>(row, col)[0];// blue
				float g = src.at<Vec3b>(row, col)[1]; // green
				float r = src.at<Vec3b>(row, col)[2]; // red

				// output:亮度和对比度处理
				dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b * alpha + beta);
				dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g * alpha + beta);
				dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r * alpha + beta);
			}
			else if (src.channels() == 1) {
				//灰度值
				float v = src.at<uchar>(row, col);
				dst.at<uchar>(row, col) = saturate_cast<uchar>(v * alpha + beta);
			}
		}
	}

	char output_title[] = "contrast and brightness change demo";
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow(output_title, dst);

	waitKey(0);
	return 0;
}
#endif

测试结果:

2、补充:convertTo的用法

函数原型:
void Mat::convertTo( Mat& m, int rtype, double alpha=1, double beta=0 )

参数解释:
m 目标矩阵。如果m的大小与原矩阵不一样,或者数据类型与参数不匹配,那么在函数convertTo内部会先给m重新分配空间。
rtype 指定从原矩阵进行转换后的数据类型,即目标矩阵m的数据类型。当然,矩阵m的通道数应该与原矩阵一样的。如果rtype是负数,那么m矩阵的数据类型应该与原矩阵一样。
alpha 缩放因子。默认值是1。即把原矩阵中的每一个元素都乘以alpha。
beta 增量。默认值是0。即把原矩阵中的每一个元素都乘以alpha,再加上beta。

功能
把一个矩阵从一种数据类型转换到另一种数据类型,同时可以带上缩放因子和增量,公式如下:
m(x,y)=saturate_cast(alpha*(*this)(x,y)+beta);
由于有数据类型的转换,所以需要用saturate_cast来处理数据的溢出。

三通道测试,测试代码:


	Mat m1;
	src.convertTo(m1, CV_32F);  
	for (int row = 0; row < height; row++) {
		for (int col = 0; col < width; col++) {
			if (src.channels() == 3) {
				//RGB三通道
				float b = m1.at<Vec3f>(row, col)[0];// blue
				float g = m1.at<Vec3f>(row, col)[1]; // green
				float r = m1.at<Vec3f>(row, col)[2]; // red

				// output:亮度和对比度处理
				dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b * alpha + beta);
				dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g * alpha + beta);
				dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r * alpha + beta);

测试结果:

在灰度基础上,测试代码:

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

using namespace cv;

#if 1
int main(int argc, char** argv) {
	Mat src, dst;
	//图片路径
	src = imread("D:/CV2021/opencv_test0/Project1/test_img/40c.png");

	if (!src.data) {
		printf("could not load image...\\n");
		return -1;
	}

	char input_win[] = "input image";
	cvtColor(src, src, CV_BGR2GRAY);
	namedWindow(input_win, CV_WINDOW_AUTOSIZE);
	imshow(input_win, src);

	// contrast and brigthtness changes 
	int height = src.rows;
	int width = src.cols;
	dst = Mat::zeros(src.size(), src.type());//图像初始化 BGR
	float alpha = 1.2;
	float beta = 30;

	Mat m1;
	src.convertTo(m1, CV_32F);
	for (int row = 0; row < height; row++) {
		for (int col = 0; col < width; col++) {
			if (src.channels() == 3) {
				//RGB三通道
				float b = m1.at<Vec3f>(row, col)[0];// blue
				float g = m1.at<Vec3f>(row, col)[1]; // green
				float r = m1.at<Vec3f>(row, col)[2]; // red

				// output:亮度和对比度处理
				dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b * alpha + beta);
				dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g * alpha + beta);
				dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r * alpha + beta);
			}
			else if (src.channels() == 1) {
				//灰度值
				float v = src.at<uchar>(row, col);
				dst.at<uchar>(row, col) = saturate_cast<uchar>(v * alpha + beta);
			}
		}
	}

	char output_title[] = "contrast and brightness change demo";
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow(output_title, dst);

	waitKey(0);
	return 0;
}
#endif

测试结果:

去掉灰度,进行降低对比度的操作: float alpha = 0.2;测试结果:

参考文献

https://www.cnblogs.com/suubai/p/12485417.html
http://www.360doc.com/content/16/1202/09/35269117_611224795.shtml
https://blog.csdn.net/xiongwen_li/article/details/78523670
https://www.bbsmax.com/A/GBJrKeQK50/

以上是关于OpenCV(C++)图像处理基础05:图像的亮度与对比度的主要内容,如果未能解决你的问题,请参考以下文章

C++ OpenCV直方图均衡化

如何使用opencv均衡图像的对比度和亮度?

opencv入门之四Trackbar图像对比度亮度值调整

更改图像的亮度和对比度

估计图像 Opencv 的亮度

如何在opencv中找到图像的最大和最小亮度值?