zoukankan      html  css  js  c++  java
  • 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的顺序存放。

    错误之处,敬请雅正!

     

     

  • 相关阅读:
    【C#进阶系列】06 类型和成员基础
    纪中5日T1 1564. 旅游
    纪中17日T1 2321. 方程
    纪中17日T2 2322. capacitor
    纪中10日T1 2313. 动态仙人掌
    纪中14日听课小结 图论 最短路 二分图 差分约束
    一个抓猫的游戏 消遣GAME 持续更新中!
    洛谷P1464 Function  HDU P1579 Function Run Fun
    洛谷P1976 鸡蛋饼
    纪中12日T1 2307. 选择
  • 原文地址:https://www.cnblogs.com/HL-space/p/10546605.html
Copyright © 2011-2022 走看看