C++ Opencv split()通道分离函数 merge()通道合并函数 使用操作详解

一、 split()通道分离函数

split()函数的C++版本有两个原型,他们分别是:


C++: void split(const Mat& src, Mat*mvbegin);//&为引用操作符
C++: void split(InputArray m,OutputArrayOfArrays mv);

两种定义用法相同,第一个参数填待分离的Mat型多通道矩阵(二维),第二个参数填分离后的Mat型单通道数组(三维)或一个vector<Mat>对象。应用实例如下:

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat image = imread("colorful.jpg");
	if (image.data == 0)
	{
		cout << "读取错误" << endl;
	}
	imshow("原图", image);

	//使用Mat容器,用【】访问
	//vector<Mat> channels;
	//split(image, channels);
	//imshow("B", channels[0]);
	//imshow("G", channels[1]);
	//imshow("R", channels[2]);

	//使用Mat容器,用at访问
	vector<Mat> channels;
	split(image, channels);
	imshow("B", channels.at(0));
	imshow("G", channels.at(1));
	imshow("R", channels.at(2));

	//使用Mat数组,只能用【】访问
	//Mat aChannel[3];
	//split(image, aChannel);
	//imshow("B", aChannel[0]);
	//imshow("G", aChannel[1]);
	//imshow("R", aChannel[2]);

	waitKey();
	return 0;
}

如果将分离后的信息填入vector<Mat> channels中,最后channels对象内会有3个元素,每个元素都是大小为image.rows X image.cols的二维Mat型矩阵,依次存放着原图像对应像素位置的B、G、R分量数据。每个元素(二维矩阵)可以通过【】索引或.at()访问。

如果将分离后的信息填入Mat aChannel[3]中,最后aChannel数组内会的3个元素也都是大小为image.rows X image.cols的二维Mat型矩阵,依次存放着原图像对应像素位置的B、G、R分量数据。每个元素(二维矩阵)只能通过【】索引,不能通过.at()访问。

同时需要注意,vector<Mat> channels和Mat aChannel[3]中的元素均为二维矩阵,因此channels对象和aChannel数组都是三维的矩阵。而输出操作符“<<”仅能输出二维矩阵,所以可以用"cout<<"输出channels对象或aChannel数组中的单个元素,而channels对象和aChannel数组本身不能被输出。

因为分离出来的3个元素都是大小为image.rows X image.cols的二维Mat型矩阵,所以用imshow()显示每个元素时,最后显示出来的都是单通道的灰度图。

上述程序运行结果如下:

 

二、merge()通道合并函数

merge()函数的C++版本有两个原型,他们分别是:

C++: void merge(const Mat* mv, size_tcount, OutputArray dst)
C++: void merge(InputArrayOfArrays mv,OutputArray dst)

若待合并通道放在Mat aChannel[ ]这样的数组里面,则使用第一种定义方法下的merge()函数。第一个参数填要传入数组的地址,可直接填入数组名aChannel;第二个参数填要合并矩阵的个数,通常情况下图像大都是单通道的灰度图或三通道的真彩图,因此要想合并后的输出dst能直接用imshow()显示的话,最好填1或3,填2也能进行数据的合并,但输出时会报错;最后一个参数填通道合并后的矩阵。

以下示例中,先用split()将图像三通道分离,将R红色分量全部置0后再将三通道用merge()融合。通道分离后,单通道矩阵存放于数组中,代码如下:

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat image = imread("colorful.jpg");
	if (image.data == 0)
	{
		cout << "读取错误" << endl;
	}
	imshow("原图", image);

	//通道分离
	Mat aChannel[3];
	split(image, aChannel);
	Mat BlueChannel = aChannel[0];
	Mat GreenChannel = aChannel[1];
	Mat RedChannel = aChannel[2];

	//将R通道全部置0
	Mat newAddChannel = aChannel[2].clone();
	newAddChannel.setTo(0);
	Mat newChannels[3] = { BlueChannel , GreenChannel , newAddChannel };

	//通道合并
	Mat mergedImage;
	merge(newChannels, 3, mergedImage);

	imshow("Merged", mergedImage);
	waitKey();
	return 0;
}

若待合并通道放在vector<Mat> channels这样的Mat型容器对象中,则使用第二种定义方法下的merge()函数。第一个参数填对象名channels,第二个参数填通道合并后的矩阵。相较第一种定义方法来说,本定义方法无需说明需合并矩阵的个数,默认合并容器对象内所有元素。因此可以通过更改容器对象内元素的个数来改变合并矩阵的个数。

以下示例中,先用split()将图像三通道分离,将B绿色分量全部置0后再将三通道用merge()融合。通道分离后,单通道矩阵存放于容器对象中,代码如下:

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat image = imread("colorful.jpg");
	if (image.data == 0)
	{
		cout << "读取错误" << endl;
	}
	imshow("原图", image);

	//通道分离
	vector<Mat> channels;
	split(image, channels);
	Mat BlueChannel = channels.at(0);
	Mat GreenChannel = channels.at(1);
	Mat RedChannel = channels.at(2);

	//将B通道全部置0
	Mat newAddChannel = channels.at(0).clone();
	newAddChannel.setTo(0);
	vector<Mat> newChannels;
	newChannels.push_back(newAddChannel);
	newChannels.push_back(GreenChannel);
	newChannels.push_back(RedChannel);

	//通道合并
	Mat mergedImage;
	merge(newChannels, mergedImage);

	imshow("Merged", mergedImage);
	waitKey();
	return 0;
}

注:无论将单通道矩阵放在数组中还是容器对象中,都要按照B、G、R的顺序存放。

错误之处,敬请雅正!

 

posted @ 2018-07-18 19:38  秋沐霖  阅读(8425)  评论(1编辑  收藏  举报
Live2D