OpenCV4通道的分离split(),通道的合并merge(),通道的混合mixChannels()

opencv中默认imread函数加载图像文件,加载进来的是三通道彩色图像,色彩空间是RGB色彩空间,通道顺序是BGR(蓝色、绿色、红色),对于三通道的图像OpenCV中提供了三个API函数用以实现通道分离split(),合并merge(),混合mixChannels();

RGB图像,在opencv的Mat中,像素数据,存储结构以及通道分离,操作关系图如下:

在这里插入图片描述

1、通道的分离函数 split()

函数原型:

两种函数原型的用法相同,用于将多通道的图像分离成若干单通道的图像,两个函数原型的不同之处在于,分离后的Mat型单通道图像,用Mat型数组存储,Mat mvbegin[3];还是用vector容器存储, vector <Mat> mv

OpenCV 4 中split()函数有2种重载原型:

(1)函数原型一:用 Mat型数组 Mat mvbegin[3]存储分离后的图像;

void split( const Mat &src, Mat *mvbegin )

输入参数:
  • src:待分离的图像,Mat型多通道矩阵;
  • mvbegin:分离后的Mat型单通道图像,用Mat型数组存储,Mat mvbegin[3],定义数组大小时需要知道原图像的通道数,数组大小=原图像通道数;
  • 分离后的图像存储在,Mat型数组 Mat mvbegin[3] 中,数组内的3个元素,大小均为 image.rows X image.cols 的Mat型矩阵,依次存放着原图像B、G、R分量的数据,取数组内的元素只能通过 [] 取值,不能通过 at() 取值;

(2)函数原型二:用 vector容器 vector <Mat> 存储分离后的图像;

void split( InputArray m, OutputArrayOfArrays mv )

输入参数:
  • m:待分离的图像,Mat型多通道矩阵;
  • mv:分离后的Mat型单通道图像,用vector容器存储,vector <Mat> mv,不需要知道原图像的通道数;
  • 分离后的图像存储在,vector容器 vector <Mat> mv 中,mv容器内有3个元素,每个元素的大小均为 image.rows X image.cols 的Mat型矩阵,依次存放着原图像B、G、R分量的数据,每个元素可以通过 []取值,也可以通过 at() 取值;

(3)示例:

#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
    
    
	// 读取图像,BGR存储在Mat矩阵里
	Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
	if (src.empty()) {
    
    
		printf("could not load image..../n");
		return -1;
	}
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", src);

	// 用Mat型数组,存储分离后的图像,只能用 [] 访问
	// Mat mvbegin[3];
	// split(src, mvbegin);
	// imshow("B", mvbegin[0]);
	// imshow("G", mvbegin[1]);
	// imshow("R", mvbegin[2]); 

	// 用vector容器,存储分离后的图像,用 [] 访问
	// vector<Mat> mv;
	// split(src, mv);
	// imshow("B", mv[0]);
	// imshow("G", mv[1]);
	// imshow("R", mv[2]);

	// 用vector容器,存储分离后的图像,用 at() 访问
	vector<Mat> mv;
	split(src, mv);
	imshow("B", mv.at(0));
	imshow("G", mv.at(1));
	imshow("R", mv.at(2));

	waitKey();
	destroyAllWindows();
	return 0;
}
运行结果:

在这里插入图片描述

2、通道合并函数 merge()

  • 两种函数原型的用法相同,用于将多个图像(单通道或多通道图像)合并成一个多通道图像,两个函数原型的不同之处在于,输入是Mat型数组形式的图像数据 Mat mvbegin[3],还是一个vector容器形式的图像数据 vector <Mat>,这里和 split()函数原型相对应;
  • 合并函数输出的是一个多通道图像,其通道数是所有输入图像通道数的总和,用于合并的图像并非都是单通道的,也可以是多个通道的图像,输入图像的通道数目可以不相同,但是需要所有图像都具有相同的尺寸和数据类型;

函数原型:

(1)函数原型一:输入是,Mat型数组形式的图像数据 Mat mvbegin[3]

void merge( const Mat *mvbegin, size_tcount, OutputArray dst )

输入参数:
  • mvbegin:需要合并的单通道或多通道图像,输入的是一个,Mat型数组形式的图像数据 mvbegin[3]
  • size_tcount:输入图像数组的长度,其数值必须大于0;
  • dst:合并后的图像;

(2)函数原型二:输入是,vector容器形式的图像数据 vector <Mat>

void merge( InputArrayOfArrays mv, OutputArray dst )

输入参数:
  • mv:需要合并的单通道或多通道图像,输入的是一个,vector容器形式的图像数据 vector <Mat>,其中每个图像必须拥有相同的尺寸和数据类型;
  • dst:合并后的图像,与 mv[0]具有相同的尺寸和数据类型,通道数等于所有输入图像的通道数总和;

(3)示例一:先用split()将图像三通道分离,用 Mat型数组 Mat mvbegin[3]存储分离后的图像,然后再将三通道图像用merge()合并,对应函数原型一;

#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
    
    
	// 读取图像,BGR存储在Mat矩阵里
	Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
	if (src.empty()) {
    
    
		printf("could not load image..../n");
		return -1;
	}
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", src);


	// 通道分离,用Mat型数组存储分离后的图像
	Mat mvbegin[3];
	split(src, mvbegin);
	Mat BlueChannel = mvbegin[0];
	Mat GreenChannel = mvbegin[1];
	Mat RedChannel = mvbegin[2];

	// 将R通道全部置0
	Mat r = mvbegin[2].clone();
	r.setTo(0);

	// 需要合并的Mat型数组 
	Mat newChannel[3] = {
    
     BlueChannel , GreenChannel , r };

	// 合并通道
	Mat dst;
	merge(newChannel, 3, dst);
	// 显示
	imshow("Merged", dst);

	waitKey();
	destroyAllWindows();
	return 0;
}
运行结果:

在这里插入图片描述

(4)示例二:先用split()将图像三通道分离,用 vector容器 vector <Mat> 存储分离后的图像,然后再将三通道图像用merge()合并,对应函数原型二;

#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
    
    
	// 读取图像,BGR存储在Mat矩阵里
	Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
	if (src.empty()) {
    
    
		printf("could not load image..../n");
		return -1;
	}
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", src);


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

	// 将B通道全部置0
	Mat b = mv.at(0).clone();
	b.setTo(0);

	vector<Mat> newChannel;
	newChannel.push_back(b);
	newChannel.push_back(GreenChannel);
	newChannel.push_back(RedChannel);

	//通道合并
	Mat mergedImage;
	merge(newChannel, mergedImage);
	// 显示
	imshow("Merged", mergedImage);

	waitKey();
	destroyAllWindows();
	return 0;
}
运行结果:

在这里插入图片描述

3、通道的混合mixChannels()

函数原型:

(1)函数原型一:

void cv::mixChannels	(
	InputArrayOfArrays		src,
	InputOutputArrayOfArrays 	dst,
	const std::vector< int > 	&fromTo 
)
输入参数:
  • src:输入矩阵,所有矩阵的大小和深度必须相同;
  • dst:输出矩阵,大小和深度必须与 src[0]相同;
  • fromTo:索引对,表示输入矩阵的第几个通道,复制到,输出矩阵的第几个通道;举例说明:
    { 0, 2, 1, 1, 2, 0 } 表示:
    src颜色通道0 复制到 dst颜色通道2
    src颜色通道1 复制到 dst颜色通道1
    src颜色通道2 复制到 dst颜色通道0
    在这里插入图片描述

(2)函数原型二:

在这个函数原型中:

  • 如果输入矩阵和输出矩阵都是1,那么就跟第一种函数原型一致了;
  • 如果不为1,就可以实现多个矩阵的合并,或者一个矩阵拆分为多个矩阵,或者其他功能;
void cv::mixChannels
(
	const Mat 	*src,
	size_t 		nsrcs,
	Mat		*dst,
	size_t	        ndsts,
	const int       *fromTo,
	size_t 		npairs 
)
输入参数:
  • src:输入矩阵,所有矩阵的大小和深度必须相同;
  • ndsts:矩阵的数量;
  • dst:输出矩阵,大小和深度必须与 src[0]相同;
  • fromTo:索引对,表示输入矩阵的第几个通道,复制到,输出矩阵的第几个通道;
  • ndsts:矩阵的数量;
  • npairs:fromTo中索引对的数目;

(3)示例一:颜色通道交换 青色(255, 255, 0) 黄色(0, 255, 255)

原图的青色(255, 255, 0),通过指定通道复制到输出图像中变成了黄色(0, 255, 255);

通道对应关系:

索引对 from_to[] = { 0, 2, 1, 1, 2, 0, 3, 3 } 的含义:

  • bg的0通道,复制到,out[]的2通道,即bgr的0通道;
  • bgra的1通道,复制到,out[]的1通道,即bgr的1通道;
  • bgra的2通道,复制到,out[]的0通道,即bgr的2通道;
  • bgra的3通道,复制到,out[]的3通道,即bgr的alpha通道;
    在这里插入图片描述
示例代码:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
    
    
	// 读取图像,BGR存储在Mat矩阵里
	Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
	if (src.empty()) {
    
    
		printf("could not load image..../n");
		return -1;
	}
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", src);

	Mat bgra(200, 200, CV_8UC4, Scalar(255, 255, 0, 255));
	Mat bgr(bgra.rows, bgra.cols, CV_8UC3);
	Mat alpha(bgra.rows, bgra.cols, CV_8UC1);

	Mat out[] = {
    
     bgr, alpha };

	int from_to[] = {
    
     0, 2, 1, 1, 2, 0, 3, 3 };
	mixChannels(&bgra, 1, out, 2, from_to, 4);

	imshow("bgra", bgra);
	imshow("bgr", bgr);

	waitKey();
	destroyAllWindows();
	return 0;
}
运行结果:

在这里插入图片描述

(4)示例二:图像分割

将一个4通道矩阵(BGRA图像)分割成一个3通道矩阵(BGR图像)和一个单通道矩阵(alpha通道图像);

通道对应关系:索引对,int fromTo[] = { 0, 2, 1, 1, 2, 0, 3, 3 }

  • bgra的0通道,复制到,bgr的2通道;
  • bgra的1通道,复制到,bgr的1通道;
  • bgra的2通道,复制到,bgr的0通道;
  • bgra的3通道,复制到,alpha的0通道;
示例代码:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
    
    

	Mat bgra( 200, 200, CV_8UC4, Scalar(255, 0, 0, 255) );
	Mat bgr( bgra.rows, bgra.cols, CV_8UC3 );
	Mat alpha( bgra.rows, bgra.cols, CV_8UC1 );

	Mat out[] = {
    
     bgr,alpha };
	// 通道对应关系
	int fromTo[] = {
    
     0, 2, 1, 1, 2, 0, 3, 3 };

	mixChannels(&bgra, 1, out, 2, fromTo, 4);
	imshow("bgra", bgra);
	imshow("bgr", bgr);
	imshow("alpha", alpha);

	waitKey();
	destroyAllWindows();
	return 0;
}
运行结果:

在这里插入图片描述

(5)示例三:HSV通道获取

利用mixChannels()函数通过,复制指定通道,可以看到HSV颜色空间下的三个通道的具体情况;

HSV颜色空间:

  • Hue(色相):代表色彩,取 0 到 360 度的数值来衡量(红-黄-绿-青-蓝-洋红);
  • Saturation(饱和度、色度):指色彩的深浅,饱和度代表灰色与色调的比例,并以 0% (灰色) 到 100% (完全饱和) 来衡量,S=0时只有灰度;
  • Value(色调):色彩的明亮程度,V=1,它包含RGB模型中的R=1,G=1,B=1 三个面,所代表的颜色较亮;
示例代码:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>

using namespace cv;
using namespace std;

int main() {
    
    
	// 读取图像,BGR存储在Mat矩阵里
	Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
	if (src.empty()) {
    
    
		printf("could not load image..../n");
		return -1;
	}
	namedWindow("src", WINDOW_AUTOSIZE);
	imshow("src", src);

	Mat hsv, dst;
	cvtColor(src, hsv, COLOR_BGR2HSV);
	dst.create( hsv.size(), hsv.depth() );

	//分离Hue,色相通道
	int ch[] = {
    
     0, 0 };
	mixChannels(&hsv, 1, &dst, 1, ch, 1);
	imshow("H channel", dst);

	//分离Saturation,饱和度通道
	int ch1[] = {
    
     1, 0 };
	mixChannels(&hsv, 1, &dst, 1, ch1, 1);
	imshow("S channel", dst);

	//分离Value,色调通道
	int ch2[] = {
    
     2, 0 };
	mixChannels(&hsv, 1, &dst, 1, ch2, 1);
	imshow("V channel", dst);

	waitKey();
	destroyAllWindows();
	return 0;
}
运行结果:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_33867131/article/details/131602283