对图像像素进行操作并实现一些功能 –图片亮度,对比度调节,图片反相,融合(openCV学习记录–2)

0.前言

opencv对像素的操作有两种,一种是对单个单个的像素进行操作(点操作),一种是对一片区域的像素进行操作。

他们可以分别用于实现不同的效果

最近主要学了一部分的点操作和一些通过点操作能实现的效果

首先便是要能取出一个图片的所有的像素值

1.提取出图片的像素

图片在openCV中的操作都是通过Mat类型实现的,Mat本质上就是一个矩阵,图像的每一个像素值就是矩阵中的某一个值。

首先看一下得到单通道图(灰度图)的一个像素的实现

int num = img.at<uchar>(i,j);

表示将img这个灰度图的第i列,第j行的像素值

还有三通道图(最常见的RGB图)的获得一个点的像素的实现:

int b = img.at<Vec3b>(i,j)[0];
int g = img.at<Vec3b>(i,j)[1];
int r = img.at<Vec3b>(i,j)[2];

也可以获得他的像素的floalt值

Mat m1;
imgin.convertTo(m1, CV_32F);//首先对img进行类型转换

float b = m1.at<Vec3f>(i, j)[0];
float g = m1.at<Vec3f>(i, j)[1];
float r = m1.at<Vec3f>(i, j)[2];

也就是说,想要提取一个图片的像素值,首先Mat变量内部的通道数和对应的数据类型,搞错了就会报错,然后就是你需要提取的某一点所在的行数和列数

然后可以我们就可以对图片进行一些操作了

2.图片的亮度和对比度的调节

1.亮度和对比度和像素值之间的关系

参考链接:图像RGB值、灰度值、像素值的关系 (360doc.com)

我们可以先从灰度图开始说一说。

亮度我感觉就是说一个图像中相对的含有白色颜色部分的多少。其中灰度图中这种感觉尤为明显,当整个图像对于原图偏白时,我们就会觉得这个图片的亮度升高了,当整个图片对于原图偏黑(灰)时,就会觉得这个图片的亮度下降了。

而灰度图的像素值就是代表图中某一点的灰度值,像素值为255时,显白色,像素为0时,显黑色。

所以想要调节灰度图的亮度时,就可以去整体改变像素的大小(让所有的像素都去加或者减某一个值)。

对比度那又是啥呢?百科的解释:对比度指的是一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,差异范围越大代表对比越大,差异范围越小代表对比越小,好的对比率120:1就可容易地显示生动、丰富的色彩,当对比率高达300:1时,便可支持各阶的颜色。

个人感觉就是大概就是黑的地方更黑,白的地方更白。而乘除的效果可以让更高的像素值变得更高,相对较低的像素值的变化就没那么明显

虽然当时我觉得对像素进行掩码操作时对比度的增加的效果个人认为比直接将像素值乘以或者除以某一个值的效果更好。

所以对于图片的亮度和对比度的操作的公式:

g

(

x

)

=

α

f

(

x

)

+

β

g(x) = alpha * f(x) + beta

g(x)=αf(x)+β

α

:

β

alpha:对比度系数 , beta:亮度系数

α:β

三通道RGB图片,R,G,B每一个的有效取值范围也是在0~255,所以其实也是可以用上述这套公式的,本质是没有变的。

有一部分没有理解的就是,为什么直接加或者乘以某个特定的值,并且将范围框定在0~255内,图片仍能看出时原来的图,色调不变,但是有一些其他的操作就会变得很奇怪

2.代码实现

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <iostream>

using namespace cv;
using namespace std;

//亮度和对比度的函数操作
Mat Image_manipulation(Mat imgin,float alpha,float beta)//alpha 对比度系数,beta 亮度系数
{
	int height = imgin.rows;//行数
	int width = imgin.cols;//列数
	int dth = imgin.channels();//通道数
    //建立空图像
	Mat imgout;
	imgout = Mat::zeros(imgin.size(),imgin.type());
	//转换成可以用Vec3f的数据类型
	Mat m1;
	imgin.convertTo(m1, CV_32F);
	//进行点操作
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (dth == 3)
			{
				//进行操作的时候要注意数据类型
				float b = m1.at<Vec3f>(i, j)[0];
				float g = m1.at<Vec3f>(i, j)[1];
				float r = m1.at<Vec3f>(i, j)[2];
				
				imgout.at<Vec3b>(i, j)[0] = saturate_cast<uchar>(b * alpha + beta);//确保值的范围在0~255
				imgout.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(g * alpha + beta);
				imgout.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(r * alpha + beta);
			}
				
			else if (dth == 1)
			{
				float gray_num = imgin.at<uchar>(i, j);
				imgout.at<uchar>(i, j) = saturate_cast<uchar>(gray_num * alpha + beta);
			}
		}
	}
	return imgout;
}

int main(int argc, char** argv)
{
	string path = "XXXXXX/XXXXXXX.jpg";
	Mat img = imread(path);
	Mat img_gray;
	cvtColor(img, img_gray, CV_RGB2GRAY);
    //亮度和对比度的操作
	img = Image_manipulation(img, 2, 0);
	img_gray = Image_manipulation(img_gray, 1.2, -50);
	//imshow("img", img);
	imshow("img_gray", img_gray);
	waitKey(0);
	return 0;
}

一些需要注意的函数

imgin.convertTo(m1, CV_32F);//转换Mat类型
saturate_cast<uchar>(b * alpha + beta);//确保值的范围在0~255

3.其他的操作

1.图片反相

这个我觉得就很简单的理解,就是用255减去像素的每一个值

其中发现直接负号像素值也能达到类似的效果

代码(仅实现部分)

for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (dth == 3)
			{
				//进行操作的时候要注意数据类型
				int b = m1.at<Vec3b>(i, j)[0];
				int g = m1.at<Vec3b>(i, j)[1];
				int r = m1.at<Vec3b>(i, j)[2];
				
				imgout.at<Vec3b>(i, j)[0] = 255-b;//确保值的范围在0~255
				imgout.at<Vec3b>(i, j)[1] = 255-g;
				imgout.at<Vec3b>(i, j)[2] = 255-r;
			}
				
			else if (dth == 1)
			{
				int gray_num = imgin.at<uchar>(i, j);
				imgout.at<uchar>(i, j) = -gray_num;
			}
		}
	}

3.图片混合

就是将两个图片分别以不同的权重加了起来,实现了两个图片在一起的效果

y

=

α

f

(

x

)

+

1

α

g

(

x

)

+

β

y = alpha * f(x) + (1- alpha)*g(x)+beta

y=αf(x)+1αg(x)+β
这里直接也能实现,也比较简单,就是传两个图片进去套入公式得到的值直接赋值给另一个图片就行。

openCV也提供了一个api:

float alpha = 0.5;
float beta = 0;
addWeighted(img1, alpha, img2, alpha, beta, dst);
//将img1和img2用不同的权重计算得到不同的值然后赋给dst这个Mat图像

注意:img1和img2两的图片的大小要一样

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>