OpenCV学习笔记(三)——图像简单处理

一、图像线性混合

    在OpenCV中提供了一个API可以实现两张图片的线性融合,此函数的声明如下:


可以看出这个函数最小需要6个参数,其中参数解释如下:

    第一个参数,InputArray类型的src1,表示需要加权的第一个数组,常常填一个Mat。

    第二个参数,alpha,表示第一个数组的权重。

    第三个参数,src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数。

    第四个参数,beta,表示第二个数组的权重值。

    第五个参数,dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。

    第六个参数,gamma,一个加到权重总和上的标量值。看下面的式子自然会理解。

    第七个参数,dtype,输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。

    那么它的原理是什么呢?其实很简单:如果用数学公式来表达,addWeighted函数计算如下两个数组(src1和src2)的加权和,得到结果输出给第四个参数。即addWeighted函数的作用可以被表示为为如下的矩阵表达式为:

                                                        

    其中的,是多维数组元素的索引值。而且,在遇到多通道数组的时候,每个通道都需要独立地进行处理。另外需要注意的是,当输出数组的深度为CV_32S时,这个函数就不适用了,这时候就会内存溢出或者算出的结果压根不对。 

理论和函数的讲解就是上面这些,接着我们来看代码实例:

#include 
#include 


using namespace cv;
using namespace std;
int main()
{
	double alpha = 0.5;
	Mat img1, img2,dst;
	img1 = imread("test5.jpg");
	img2 = imread("test6.jpg");
	if (img1.empty())
	{
		printf("could not load the picture1...");
	}
	else if (img2.empty())
	{
		printf("could not load the picture2...");
	}

	if (img1.rows == img2.rows&&img1.cols == img2.cols&&img1.type() == img2.type())
	{
		addWeighted( img1,alpha,img2,(1.0-alpha),0.0,dst);
		namedWindow("图片1:", CV_WINDOW_AUTOSIZE);
		imshow("图片1:", img1);
		namedWindow("图片2:", CV_WINDOW_AUTOSIZE);
		imshow("图片2:", img2);
		namedWindow("混合后:", CV_WINDOW_AUTOSIZE);
		imshow("混合后:", dst);
	}
	else
	{
		printf( "could not  linear blend...");
	}	
	waitKey(0);
	system("PAUSE");
	return 0;
}

运行程序,结果如下:

OpenCV学习笔记(三)——图像简单处理_第1张图片


二、亮度和对比度增强

       图像对比度是通过灰度级范围来度量的,而灰度级范围可通过观察灰度直方图得到,灰度级范围越大代表对比度越高;反之,对比度越低,低对比度的图像在视觉上给人的感觉是看起来不够清晰的,所以通过算法调整图像的灰度值,从而调整图像的对比度是有必要的。最简单的一种对比度增强方法是通过灰度值的线性变换来实现的。

        假设输入图像为,宽为、高为,输出图像记为,图像的线性变换可以利用以下公式定义:


因此,当时,的一个副本;如果,则输出图像的对比度比有所增大;如果,则输出图像的对比度比有所减小。而值的改变,影响的是输出图像的亮度,当时,亮度增加;时,亮度减小。

    举例:假设图像的灰度级范围是[50,100],通过的线性变换,可以将输出图像的灰度级拉伸到[100,200],灰度级范围有所增加,从而提高了对比度;而如果令,则输出图像的灰度级会压缩到[25,50],灰度级范围有所减小,则降低了对比度。

      这就是为什么我们拿到彩色图像以后往往会转化为灰度图进行处理,这位这样相当于只要处理一个通道。如果是三通道,原理是一样的,只不过我们需要对每一个通道都做上述转换步骤。接下来我们对三通道的彩色图像进行线性变换:

#include 
#include 


using namespace cv;
using namespace std;
int main()
{
		Mat src, dst;
		src = imread("test3.png");
		if (src.empty())
		{
			printf("could not load image...\n");
			return -1;
		}

		// 亮度和对比度调整
		int height = src.rows;
		int width = src.cols;
		dst = Mat::zeros(src.size(), src.type());
		float alpha = 1.5;
		float beta = 30;
		Mat m1;
		if (src.depth() != CV_32F)
		{
			src.convertTo(m1, CV_32F);
		}
		for (int row = 0; row < height; row++)
		{
			for (int col = 0; col < width; col++)
			{
				if (src.channels() == 3) 
				{
					float b = m1.at(row, col)[0];//蓝通道
					float g = m1.at(row, col)[1]; // 绿通道
					float r = m1.at(row, col)[2]; // 红通道			
					dst.at(row, col)[0] = saturate_cast(b*alpha + beta);
					dst.at(row, col)[1] = saturate_cast(g*alpha + beta);
					dst.at(row, col)[2] = saturate_cast(r*alpha + beta);
				}
				else if (src.channels() == 1)
				{
					float v = src.at(row, col);
					dst.at(row, col) = saturate_cast(v*alpha + beta);
				}
			}
		}
		namedWindow("调整前:", CV_WINDOW_AUTOSIZE);
		imshow("调整前:", src);
		namedWindow("调整后:", CV_WINDOW_AUTOSIZE);
		imshow("调整后:", dst);
		 waitKey(0);
		system("PAUSE");
		return 0;
}

运行程序,如下所示:



三、线性变换API

    其实,在OpenCV中,就提供了API接口来实现上述的线性变换,其函数声明如下:


  其中参数的关系为,  的数据类型和输入矩阵的数据类型是相同的。

我们用上面介绍的API接口来实现同样的操作:

#include 
#include 


using namespace cv;
using namespace std;
int main()
{
		Mat src, dst;
		src = imread("test3.png");
		if (src.empty())
		{
			printf("could not load image...\n");
			return -1;
		}

		// 亮度和对比度调整
		int height = src.rows;
		int width = src.cols;
		dst = Mat::zeros(src.size(), src.type());
		float alpha = 1.5;
		float beta = 30;
		convertScaleAbs(src, dst, 1.5, 30);  //调用API接口
		namedWindow("调整前:", CV_WINDOW_AUTOSIZE);
		imshow("调整前:", src);
		namedWindow("调整后:", CV_WINDOW_AUTOSIZE);
		imshow("调整后:", dst);
		 waitKey(0);
		system("PAUSE");
		return 0;
}





你可能感兴趣的:(OpenCV)