一、 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的顺序存放。
错误之处,敬请雅正!