文章目录
- 1、通道的分离函数 split()
- 函数原型:
- (1)函数原型一:用 Mat型数组 `Mat mvbegin[3]`存储分离后的图像;
- 输入参数:
- (2)函数原型二:用 vector容器 `vector <Mat>` 存储分离后的图像;
- 输入参数:
- (3)示例:
- 运行结果:
- 2、通道合并函数 merge()
- 函数原型:
- (1)函数原型一:输入是,Mat型数组形式的图像数据 `Mat mvbegin[3]`
- 输入参数:
- (2)函数原型二:输入是,vector容器形式的图像数据 `vector <Mat>`
- 输入参数:
- (3)示例一:先用split()将图像三通道分离,用 Mat型数组 `Mat mvbegin[3]`存储分离后的图像,然后再将三通道图像用merge()合并,对应函数原型一;
- 运行结果:
- (4)示例二:先用split()将图像三通道分离,用 vector容器 `vector <Mat>` 存储分离后的图像,然后再将三通道图像用merge()合并,对应函数原型二;
- 运行结果:
- 3、通道的混合mixChannels()
- (1)函数原型一:
- 输入参数:
- (2)函数原型二:
- 输入参数:
- (3)示例一:颜色通道交换 青色(255, 255, 0) 黄色(0, 255, 255)
- 示例代码:
- 运行结果:
- (4)示例二:图像分割
- 示例代码:
- 运行结果:
- (5)示例三:HSV通道获取
- 示例代码:
- 运行结果:
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;
}