若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/101420314
目录
OpenCV开发专栏
《OpenCV开发笔记(〇):使用mingw530_32编译openCV3.4.1源码,搭建Qt5.9.3的openCV开发环境》
《OpenCV开发笔记(三):OpenCV图像的概念和基本操作》
《OpenCV开发笔记(四):OpenCV图片和视频数据的读取与存储》
《OpenCV开发笔记(五):OpenCV读取与操作摄像头》
《OpenCV开发笔记(六):OpenCV基础数据结构、颜色转换函数和颜色空间》
《OpenCV开发笔记(八):OpenCV常用操作之计时、缩放、旋转、镜像》
《OpenCV开发笔记(九):OpenCV区域图像(ROI)和整体、局部图像混合》
《OpenCV开发笔记(十):OpenCV图像颜色通道分离和图像颜色多通道混合》
持续补充中…
OpenCV开发笔记(十):OpenCV图像颜色通道分离和图像颜色多通道混合
前言
前面说明了图像的混合,其实图像的混合本质是对应像素点的颜色通道的值混合,本篇对颜色通道讲解并操作。
颜色通道
每个图像都有一个或多个颜色通道,图像中默认的颜色通道数取决于其颜色模式,即一个图像的颜色模式将决定其颜色通道的数量。例如,CMYK图像默认有4个通道,分别为青色、洋红、黄色、黑色。
在默认情况下,位图模式、灰度、双色调和索引颜色图像只有一个通道。RGB和Lab图像有3个通道,CMYK图像有4个通道。
每个颜色通道都存放着图像中颜色元素的信息。所有颜色通道中的颜色叠加混合产生图像中像素的颜色。
一幅RGB图像的基本组成单位是以RGB为基础展开的,为此可以理解为一个图像由RGB这样的三个元素组成,R为一个红色通道,表示为1;G为一个绿色通道,表示为2;B 为一个蓝色通道,表示为3;有一处白色图像则为4,它是由1、2、3处的通道颜色混合而成,这相当于我们使用的调色板,几种颜色混合在一起将产生一种新的颜色。
分离颜色通道
对一幅RGB图像,是可以分理处RGB三个通道的,对于RGBA图像是可以分理处RGBA四个通道的(A是透明度通道)。
在OpenCV中,直接提供了2个函数方便我们对颜色通道进行调整。
分离通道函数:splite()
该函数用于将一个多通道数据分离成几个单通道数组(cv::Mat),该函数原型如下:
CV_EXPORTS void split(const Mat& src, Mat* mvbegin);
- 参数一:输入图像(要被分离的图像);
- 参数二:输出分离后的列表,std::vector<cv::mat>类型;
测试代码
// 测试通道分离
cv::Mat mat1;
QString fileName1 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
mat1 = cv::imread(fileName1.toStdString());
if(!mat1.data)
{
qDebug() << __FILE__ << __LINE__
<< "Failed to load image:" << fileName1;
return;
}
std::vector<cv::Mat> listChannel;
cv::split(mat1,listChannel);
cv::imshow("origin", mat1);
for(int index = 0; index < listChannel.size(); index++)
{
cv::imshow("channel" + std::to_string(index), listChannel.at(index));
}
cv::waitKey(0);
测试效果
因为分成的RGB编程单个通道,显示出来就是灰度图像了。
多颜色通道混合
该操作是分离颜色通道的逆向操作,将多个mat合并成一个多通道的mat。此处纠正一下对通道的认知,mat多通道的矩阵,分离和混合的时候并不管其具体指示的颜色意义,操作时只认为是纯数字多通道的分离和混合。
混合通道函数:merge()
通道混合函数原型如下:
CV_EXPORTS_W void merge(InputArrayOfArrays mv, OutputArray dst);
- 参数一:输入通道列表,std::vector<cv::mat>类型;
- 参数二:输出图像,cv::Mat类型;
测试代码1
// 测试通道分离
cv::Mat matR(300, 300, CV_8UC1);
cv::Mat matG(300, 300, CV_8UC1);
cv::Mat matB(300, 300, CV_8UC1);
// 上部分1/3为红色, 2/3为绿色,3/3为蓝色
for(int row = 0; row < matR.rows; row++)
{
if(row < matR.rows / 3)
{
for(int col = 0; col < matR.cols; col++)
{
matR.at<uchar>(row, col) = 255;
matG.at<uchar>(row, col) = 0;
matB.at<uchar>(row, col) = 0;
}
}else if(row < matR.rows / 3 * 2 )
{
for(int col = 0; col < matR.cols; col++)
{
matR.at<uchar>(row, col) = 0;
matG.at<uchar>(row, col) = 255;
matB.at<uchar>(row, col) = 0;
}
}else{
for(int col = 0; col < matR.cols; col++)
{
matR.at<uchar>(row, col) = 0;
matG.at<uchar>(row, col) = 0;
matB.at<uchar>(row, col) = 255;
}
}
}
cv::Mat matOut;
std::vector<cv::Mat> listChanel;
// 特别注意,OpenCV通道顺序为BGR
listChanel.push_back(matB);
listChanel.push_back(matG);
listChanel.push_back(matR);
cv::merge(listChanel, matOut);
cv::imshow("merge", matOut);
cv::waitKey(0);
测试效果1
然后我们将分离颜色通道的进行一次优化,让其分离为RGB三个通道:
测试代码2
// 测试通道分离
cv::Mat mat1;
QString fileName1 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
mat1 = cv::imread(fileName1.toStdString());
if(!mat1.data)
{
qDebug() << __FILE__ << __LINE__
<< "Failed to load image:" << fileName1;
return;
}
std::vector<cv::Mat> listChannel;
cv::split(mat1,listChannel);
cv::imshow("origin", mat1);
// 生成一个空矩阵
cv::Mat chanel(mat1.rows, mat1.cols, CV_8UC1);
for(int row = 0; row < chanel.rows; row++)
{
for(int col = 0; col < chanel.cols; col++)
{
mat1.at<uchar>(row, col) = 0;
}
}
for(int index = 0; index < listChannel.size(); index++)
{
// 通道BGR
if(index == 0)
{
std::vector<cv::Mat> listOutChannel;
listOutChannel.push_back(listChannel.at(0));
listOutChannel.push_back(chanel);
listOutChannel.push_back(chanel);
cv::Mat matOut;
cv::merge(listOutChannel, matOut);
cv::imshow("channel" + std::to_string(index), matOut);
}else if(index == 1)
{
std::vector<cv::Mat> listOutChannel;
listOutChannel.push_back(chanel);
listOutChannel.push_back(listChannel.at(1));
listOutChannel.push_back(chanel);
cv::Mat matOut;
cv::merge(listOutChannel, matOut);
cv::imshow("channel" + std::to_string(index), matOut);
}else if(index == 2)
{
std::vector<cv::Mat> listOutChannel;
listOutChannel.push_back(chanel);
listOutChannel.push_back(chanel);
listOutChannel.push_back(listChannel.at(2));
cv::Mat matOut;
cv::merge(listOutChannel, matOut);
cv::imshow("channel" + std::to_string(index), matOut);
}
}
cv::waitKey(0);
测试效果2
Demo源码
void OpenCVManager::testSplitAndMerge()
{
#define TEST_SPLIT (0)
#define TEST_MERGE (0)
#define TEST_SPLIT_MERGE (1)
#if TEST_SPLIT
// 测试通道分离
cv::Mat mat1;
QString fileName1 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
mat1 = cv::imread(fileName1.toStdString());
if(!mat1.data)
{
qDebug() << __FILE__ << __LINE__
<< "Failed to load image:" << fileName1;
return;
}
std::vector<cv::Mat> listChannel;
cv::split(mat1,listChannel);
cv::imshow("origin", mat1);
for(int index = 0; index < listChannel.size(); index++)
{
cv::imshow("channel" + std::to_string(index), listChannel.at(index));
}
cv::waitKey(0);
#endif
#if TEST_MERGE
// 测试通道分离
cv::Mat matR(300, 300, CV_8UC1);
cv::Mat matG(300, 300, CV_8UC1);
cv::Mat matB(300, 300, CV_8UC1);
// 上部分1/3为红色, 2/3为绿色,3/3为蓝色
for(int row = 0; row < matR.rows; row++)
{
if(row < matR.rows / 3)
{
for(int col = 0; col < matR.cols; col++)
{
matR.at<uchar>(row, col) = 255;
matG.at<uchar>(row, col) = 0;
matB.at<uchar>(row, col) = 0;
}
}else if(row < matR.rows / 3 * 2 )
{
for(int col = 0; col < matR.cols; col++)
{
matR.at<uchar>(row, col) = 0;
matG.at<uchar>(row, col) = 255;
matB.at<uchar>(row, col) = 0;
}
}else{
for(int col = 0; col < matR.cols; col++)
{
matR.at<uchar>(row, col) = 0;
matG.at<uchar>(row, col) = 0;
matB.at<uchar>(row, col) = 255;
}
}
}
cv::Mat matOut;
std::vector<cv::Mat> listChanel;
// 特别注意,OpenCV通道顺序为BGR
listChanel.push_back(matB);
listChanel.push_back(matG);
listChanel.push_back(matR);
cv::merge(listChanel, matOut);
cv::imshow("merge", matOut);
cv::waitKey(0);
#endif
#if TEST_SPLIT_MERGE
// 测试通道分离
cv::Mat mat1;
QString fileName1 = "D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
mat1 = cv::imread(fileName1.toStdString());
if(!mat1.data)
{
qDebug() << __FILE__ << __LINE__
<< "Failed to load image:" << fileName1;
return;
}
std::vector<cv::Mat> listChannel;
cv::split(mat1,listChannel);
cv::imshow("origin", mat1);
// 生成一个空矩阵
cv::Mat chanel(mat1.rows, mat1.cols, CV_8UC1);
for(int row = 0; row < chanel.rows; row++)
{
for(int col = 0; col < chanel.cols; col++)
{
mat1.at<uchar>(row, col) = 0;
}
}
for(int index = 0; index < listChannel.size(); index++)
{
// 通道BGR
if(index == 0)
{
std::vector<cv::Mat> listOutChannel;
listOutChannel.push_back(listChannel.at(0));
listOutChannel.push_back(chanel);
listOutChannel.push_back(chanel);
cv::Mat matOut;
cv::merge(listOutChannel, matOut);
cv::imshow("channel" + std::to_string(index), matOut);
}else if(index == 1)
{
std::vector<cv::Mat> listOutChannel;
listOutChannel.push_back(chanel);
listOutChannel.push_back(listChannel.at(1));
listOutChannel.push_back(chanel);
cv::Mat matOut;
cv::merge(listOutChannel, matOut);
cv::imshow("channel" + std::to_string(index), matOut);
}else if(index == 2)
{
std::vector<cv::Mat> listOutChannel;
listOutChannel.push_back(chanel);
listOutChannel.push_back(chanel);
listOutChannel.push_back(listChannel.at(2));
cv::Mat matOut;
cv::merge(listOutChannel, matOut);
cv::imshow("channel" + std::to_string(index), matOut);
}
}
cv::waitKey(0);
#endif
}
工程模板:对应版本号v1.7.0
对应版本号v1.7.0
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/101420314
转载:https://blog.csdn.net/qq21497936/article/details/101420314