欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2023-12-23 15:57:52
...

一、图像线性混合

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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学习笔记(三)——图像简单处理


二、亮度和对比度增强

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

        假设输入图像为OpenCV学习笔记(三)——图像简单处理,宽为OpenCV学习笔记(三)——图像简单处理、高为OpenCV学习笔记(三)——图像简单处理,输出图像记为OpenCV学习笔记(三)——图像简单处理,图像的线性变换可以利用以下公式定义:

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

因此,当OpenCV学习笔记(三)——图像简单处理时,OpenCV学习笔记(三)——图像简单处理OpenCV学习笔记(三)——图像简单处理的一个副本;如果OpenCV学习笔记(三)——图像简单处理,则输出图像OpenCV学习笔记(三)——图像简单处理的对比度比OpenCV学习笔记(三)——图像简单处理有所增大;如果OpenCV学习笔记(三)——图像简单处理,则输出图像OpenCV学习笔记(三)——图像简单处理的对比度比OpenCV学习笔记(三)——图像简单处理有所减小。而OpenCV学习笔记(三)——图像简单处理值的改变,影响的是输出图像的亮度,当OpenCV学习笔记(三)——图像简单处理时,亮度增加;OpenCV学习笔记(三)——图像简单处理时,亮度减小。

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

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

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


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<Vec3f>(row, col)[0];//蓝通道
					float g = m1.at<Vec3f>(row, col)[1]; // 绿通道
					float r = m1.at<Vec3f>(row, col)[2]; // 红通道			
					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);
				}
			}
		}
		namedWindow("调整前:", CV_WINDOW_AUTOSIZE);
		imshow("调整前:", src);
		namedWindow("调整后:", CV_WINDOW_AUTOSIZE);
		imshow("调整后:", dst);
		 waitKey(0);
		system("PAUSE");
		return 0;
}

运行程序,如下所示:

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


三、线性变换API

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

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

  其中参数的关系为OpenCV学习笔记(三)——图像简单处理,  OpenCV学习笔记(三)——图像简单处理的数据类型和输入矩阵OpenCV学习笔记(三)——图像简单处理的数据类型是相同的。

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

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


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学习笔记(三)——图像简单处理




上一篇:

下一篇: