【OpenCV学习笔记】之图像混合、叠加和对比度、亮度调整

一、图像混合、叠加

        图像线性混合的数学原理  :G(x)=(1-a)F(x)+aQ(x)

注意事项:

1,a的取值范围为0到1之间

2,F(x)和Q(x)为参与混合的两幅图像,G(x)表示输出图像

3,通过对两幅图像的每个像素值做线性加权得到最终的输出图像

4,两幅图像的大小和类型必须完全一致,如果把图像当成一个矩阵则两个矩阵相加的前提是维度必须一致,否则没有相加的意义。

在OpenCV里面我们使用的API是addWeighted()函数:

C++ void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);  

 

  • 第一个参数,InputArray类型的src1,表示需要加权的第一个数组,常常填一个Mat。
  • 第二个参数,alpha,表示第一个数组的权重
  • 第三个参数,src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数。
  • 第四个参数,beta,表示第二个数组的权重值。
  • 第五个参数,dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。
  • 第六个参数,gamma,一个加到权重总和上的标量值。看下面的式子自然会理解。
  • 第七个参数,dtype,输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。

        通过这个函数进行加权叠加就可以制造出一些奇特的画面叠加效果,下面这个这个实验我选的图不是很好,没有理想的效果,大家可以自行选取图片实验。程序里面另一个函数是选取ROI后再进行叠加的效果;

示例程序:

//图像的线性混合
#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>

using namespace std;
using namespace cv;

Mat src1, src2, mixed_image,Roi_mixed;

bool LinearBlending();
bool Roi_LinearBlending();

int main(int agrc, char**agrv)
{
	LinearBlending();
	Roi_LinearBlending();

	waitKey(0);
	return 0;
}

//线性混合
bool LinearBlending()
{
	src1 = imread("C:/Users/59235/Desktop/image/girl3.jpg");
	src2 = imread("C:/Users/59235/Desktop/image/national customs2.jpg");
	if (!src1.data)
	{
		cout << "could not load image1...%d\n" << endl;
		return -1;
	}
	if (!src2.data)
	{
		cout << "could not load image2...%d\n" << endl;
		return -1;
	}

	if (src1.rows == src2.rows &&src1.cols == src2.cols)
	{
		double alpha = 0.5;//图像的线性混合按照不同的权重进行混合src1权重0.5,src2权重0.5
		addWeighted(src1, alpha, src2, (1 - alpha), 0.0, mixed_image);

		namedWindow("mixed_image", CV_WINDOW_AUTOSIZE);
		imshow("mixed_image", mixed_image);
	}
	else
	{
		printf("image is not same size...\n");
		return -1;
	}
	
	return true;
}

//Roi区域线性混合
bool Roi_LinearBlending()
{
	src1 = imread("C:/Users/59235/Desktop/image/test.jpg");
	src2 = imread("C:/Users/59235/Desktop/image/heart.jpg");
	if (!src1.data)
	{
		cout << "could not load image1...%d\n" << endl;
		return -1;
	}
	if (!src2.data)
	{
		cout << "could not load image2...%d\n" << endl;
		return -1;
	}

	//定义一个ROI感兴趣区域
	Mat imageROI1 = src1(Rect(425, 215, 90, 65));
	Mat imageROI2 = src2(Rect(230, 500, 90, 65));


	addWeighted(imageROI1, 0.3, imageROI2, 0.7, 0.0, imageROI1);

	namedWindow("Roi_mixed_image", CV_WINDOW_AUTOSIZE);
	imshow("Roi_mixed_image", src1);
	
	return true;

}

效果图:

                                                                                      (原图)

 

                                                                                    (效果图)

                                                 

                                                                          (原图)                                                                                        (效果图)

 

二、分离、合并颜色通道

       我们知道一般的图像形式分为单通道(灰度)图像和多通道(彩色)图像。而且像我们最常见的图像RGB、HSV、HSI等都是三通道图像。当我们要对一个通道进行单独处理时,就需要进行分离,如HSV中V是亮度,我们将其置为0时可以有效抗击光照的影响。同时有时候,我们也需要将多个单通道图像合并成一个多通道图像。

       OpenCV里面提供的API分别为split();merge()函数:

c++: void split(const mat& src, mat* mvbegin); 
c++: void split(inputarray m, outputarrayofarrays mv);
第一个参数,inputarray类型的m或者const mat&类型的src,填我们需要进行分离的多通道数组。
第二个参数,outputarrayofarrays类型的mv,填函数的输出数组或者输出的vector容器
merge()函数是split()函数的逆向操作,将多个数组合并成一个多通道的数组。它通过组合一些给定的单通道数组,将这些孤立的单通道数组合并成一个多通道的数组,从而创建出一个由多个单通道阵列组成的多通道阵列。
C++; void merge(const Mat* mv, size_tcount, OutputArray dst) 
C++: void merge(InputArrayOfArrays mv, OutputArray dst)
第一个参数,mv。填需要被合并的输入矩阵或vector容器的阵列,这个mv参数中所有的矩阵必须有着一样的尺寸和深度。
第二个参数,count。当mv为一个空白的C数组时,代表输入矩阵的个数,这个参数显然必须大于1
第三个参数,dst。即输出矩阵,和mv[0]拥有一样的尺寸和深度,并且通洞数量是矩阵阵列中的通道的总数。

示例程序:

//分离颜色通道,多通道融合
#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
	Mat src = imread("C:\\Users\\59235\\Desktop\\image\\national customs3.jpg");
	if (src.empty())
	{
		cout << "could not load image...\n" << endl;
		return -1;
	}
	namedWindow("original image", CV_WINDOW_AUTOSIZE);
	imshow("original image", src);

	//把一个三通道图像,转换成3个单通道图像
	vector<Mat> channels;
	Mat BImg, GImg, RImg;

	split(src, channels);//分离色彩通道
	BImg = channels.at(0);
	GImg = channels.at(1);
	RImg = channels.at(2);

	imshow("蓝色分量", BImg);
	imshow("绿色分量", GImg);
	imshow("红色分量", RImg);

	//merge功能:将一些数组合并成一个多通道数组
	Mat dst;
	merge(channels, dst);

	waitKey(0);
	return 0;
}

三、对比度、亮度调整

         一般的图像处理算子都是一个函数,它接受一个或多个输入图像,并产生输出图像。算子的一般形式如下: 
                                                                        g(x)=h(f(x))或者g(x)=h(f0(x)……fn(x)) 
        图像亮度和对比度的调整操作,属于图像处理变换中一种——点操作。 点操作特点:仅仅根据输入像素值(有时加上某些全局信息或参数),来计算相应的输出像素值。这类算子包括亮度和对比度、颜色校正和变换。 两种最常用的点操作(或者说点算子)是乘上一个常数(对应对比度的调节)以及加上一个常数(对应亮度值的调节),公式如下: 

                                                                                  g(x)=a*f(x)+b

  • 参数f(x)表示源图像像素
  • 参数g(x)表示输出图像像素
  • 参数a(需要满足a>0)被称为增益(gain),常常被用来控制图像的对比度
  • 参数b通常被称为偏置,常常被用来控制图像的亮度 可以更进一步写成: g(i,j)=a*f(i,j)+b

 示例程序:

//图像的对比度和亮度调整
#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;

int main(int agrc, char**argv)
{
	Mat src;
	src = imread("C:\\Users\\59235\\Desktop\\image\\national customs3.jpg");
	if (!src.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	char input[] = "input image";
	namedWindow(input, CV_WINDOW_AUTOSIZE);
	imshow(input, src);

	
	int height = src.rows;
	int width = src.cols;
	int t = src.channels();
	Mat dst = Mat::zeros(src.size(), src.type());
	double alpha = 0.6;//对比度系数
	double beta = 30;//亮度系数
	for (int row = 0; row < height; row++)
	{
		for (int col = 0; col < width; col++)
		{
			if (t == 3)
			{
				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
				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
			{
				float gray = src.at<uchar>(row, col);
				dst.at<uchar>(row, col) = saturate_cast<uchar>(gray*alpha + beta);
			}

		}
	}
	char output[] = "output image";
	namedWindow(output, CV_WINDOW_AUTOSIZE);
	imshow(output, dst);

	waitKey(0);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值