小言_互联网的博客

OpenCV开发笔记(十):OpenCV图像颜色通道分离和图像颜色多通道混合

283人阅读  评论(0)

若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/101420314

目录

前言

颜色通道

分离颜色通道

分离通道函数:splite()

测试代码

测试效果

多颜色通道混合

混合通道函数:merge()

测试代码1

测试效果1

测试代码2

测试效果2

Demo源码

工程模板:对应版本号v1.7.0


OpenCV开发专栏

OpenCV开发笔记(〇):使用mingw530_32编译openCV3.4.1源码,搭建Qt5.9.3的openCV开发环境

OpenCV开发笔记(一):OpenCV介绍、编译

OpenCV开发笔记(二):cvui交互界面

OpenCV开发笔记(三):OpenCV图像的概念和基本操作

OpenCV开发笔记(四):OpenCV图片和视频数据的读取与存储

OpenCV开发笔记(五):OpenCV读取与操作摄像头

OpenCV开发笔记(六):OpenCV基础数据结构、颜色转换函数和颜色空间

OpenCV开发笔记(七):OpenCV基础图形绘制

OpenCV开发笔记(八):OpenCV常用操作之计时、缩放、旋转、镜像

OpenCV开发笔记(九):OpenCV区域图像(ROI)和整体、局部图像混合

OpenCV开发笔记(十):OpenCV图像颜色通道分离和图像颜色多通道混合

持续补充中…

 

OpenCV开发笔记(十):OpenCV图像颜色通道分离和图像颜色多通道混合

 

前言

       前面说明了图像的混合,其实图像的混合本质是对应像素点的颜色通道的值混合,本篇对颜色通道讲解并操作。

 

颜色通道

       每个图像都有一个或多个颜色通道,图像中默认的颜色通道数取决于其颜色模式,即一个图像的颜色模式将决定其颜色通道的数量。例如,CMYK图像默认有4个通道,分别为青色、洋红、黄色、黑色。

       在默认情况下,位图模式、灰度、双色调和索引颜色图像只有一个通道。RGBLab图像有3个通道,CMYK图像有4个通道。

       每个颜色通道都存放着图像中颜色元素的信息。所有颜色通道中的颜色叠加混合产生图像中像素的颜色。

       一幅RGB图像的基本组成单位是以RGB为基础展开的,为此可以理解为一个图像由RGB这样的三个元素组成,R为一个红色通道,表示为1G为一个绿色通道,表示为2B 为一个蓝色通道,表示为3;有一处白色图像则为4,它是由123处的通道颜色混合而成,这相当于我们使用的调色板,几种颜色混合在一起将产生一种新的颜色。

 

分离颜色通道

       对一幅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
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场