• 学习OpenCV2——Mat之通道的理解


    本文详细介绍了opencv中涉及通道的知识,包括图像类型转换,通道合成分解,图像的显示。 

     来源:http://blog.csdn.net/GDFSG/article/details/50927257

    1. 知识点

    tips1:  一个图像的通道数是N,就表明每个像素点处有N个数,一个a×b的N通道图像,其图像矩阵实际上是b行N×a列的数字矩阵。

    OpenCV中图像的通道可以是1、2、3和4。其中常见的是1通道和3通道,2通道和4通道不常见。

          1通道的是灰度图。

          3通道的是彩色图像,比如RGB图像。

          4通道的图像是RGBA,是RGB加上一个A通道,也叫alpha通道,表示透明度。PNG图像是一种典型的4通道图像。alpha通道可以赋值0到1,或者0到255,表示透明到不透明。

          2通道的图像是RGB555和RGB565。2通道图在程序处理中会用到,如傅里叶变换,可能会用到,一个通道为实数,一个通道为虚数,主要是编程方便。RGB555是16位的,2个字节,5+6+5,第一字节的前5位是R,后三位+第二字节是G,第二字节后5位是B,可见对原图像进行压缩了。

         

    tips2: OpenCV中用imshow( )来显示图像,只要Mat的数据矩阵符合图像的要求,就可以用imshow来显示。二通道好像不可以。。。超过了4通道,就不是图像了,imshow( )也显示不了。

     

    tips3: imshow( )显示单通道图像时一定是灰度图,如果我们想显示红色的R分量,还是应该按三通道图像显示,只不过G和B通道要赋值成0或255.

     

    tips4: 通道分解用split( ),通道合成用merg( ),这俩函数都是mixchannel( )的特例。

     

    下面,结合程序说明以上知识点。

     

    2 图像类型的转换与显示 

    1. Mat image=imread("E:/图片/color.jpg");    
    2. Mat imageGRAY,imageRGBA,imageRGB555;  
    3. cvtColor(image,imageGRAY,CV_RGB2GRAY);            //RGB转GRAY  
    4. cvtColor(image,imageRGBA,CV_RGB2BGRA);            //RGB转RGBA  
    5. cvtColor(image,imageRGB555,CV_RGB2BGR555);        //RGB转RGB555  
    6.   
    7. //来看看通道数  
    8. int n = image.channels();                        //n=3  
    9. int nRGBA = imageRGBA.channels();                //nRGBA = 4  
    10. int nRGB555 = imageRGB555.channels();            //nRGB555 = 2  
    11.   
    12. //显示GRAY、RGB和RGBA图像  
    13. imshow("image",image);  
    14. imshow("imageGRAY",imageGRAY);  
    15. imshow("imageRGBA",imageRGBA);  
    16. //imshow("imageRGB555",imageRGB555);             //无法显示  


    RGB转GRAY是根据一个心理学公式来的:Gray = R*0.299 + G*0.587 + B*0.114

    RGB转GRBA,默认A通道的数值是255,也就是不透明的。

     

    3 通道的合成与分解

    3.1 简单的例子

    我们先来看下最常用的合成与分解函数。

    split()

    C++: void split(const Mat& mtx, Mat* mv)
    C++: void split(const Mat& mtx, vector<Mat>& mv)
    C:   void cvSplit(const CvArr* src, CvArr* dst0, CvArr* dst1, CvArr* dst2, CvArr* dst3)

    参数:mtx   输入矩阵

               mv    输出矩阵或矩阵数组

               src   输入矩阵

              dst0、dst1、dst2、dst3   最多4个单通道的输出矩阵

        当我们要固定提取某个通道的矩阵时,C形式的用法还是蛮实用的,不必向C++用法那样,先定义vector,再channels.at(k)

    1. Mat rgb( 3, 4, CV_8UC3, Scalar(1,2,3,4) );  
    2. vector<Mat> channels;  
    3. split(rgb,channels);  
    4. Mat B = channels.at(0);          //从vector中读数据用vector::at()  
    5. Mat G = channels.at(1);  
    6. Mat R = channels.at(2);  
    7. cout<<"RGB="<<endl<<rgb<<endl;  
    8. cout<<"B="<<endl<<B<<endl;  
    9. cout<<"G="<<endl<<G<<endl;  
    10. cout<<"R="<<endl<<R<<endl;  

       注意rgb图像的通道排列是BGR

    merge( )

    C++: void merge(const Mat* mv, size_t count, OutputArray dst)
    C++: void merge(const vector<Mat>& mv, OutputArray dst)
    C:   void cvMerge(const CvArr* src0, const CvArr* src1, const CvArr* src2, const CvArr* src3, CvArr* dst)

    参数:mv    输入矩阵

               count   当mv是C形式的array时,count表示输入矩阵个数

              dst   输出矩阵

              src0、src1、src2、src3   最多4个单通道的输入矩阵

    1. Mat R(3,4,CV_8UC1, Scalar(3));  
    2. Mat G(3,4,CV_8UC1, Scalar(2));  
    3. Mat B(3,4,CV_8UC1, Scalar(1));  
    4. Mat RGB( 3, 4, CV_8UC3);  
    5. vector<Mat> src;  
    6. src.push_back(B);               //往vector里存数据要用vector::push_back()  
    7. src.push_back(G);  
    8. src.push_back(R);     
    9. merge(src,RGB);   
    10. cout<<"B="<<endl<<B<<endl;  
    11. cout<<"G="<<endl<<G<<endl;  
    12. cout<<"R="<<endl<<R<<endl;  
    13. cout<<"RGB="<<endl<<RGB<<endl;  



    split( )和merge( )都是mixChannels( )的特例,接下来看看mixChannels()的用法

     

    mixChannels( )

    C++: void mixChannels(const Mat* src, int nsrc, Mat* dst, int ndst, const int* fromTo, size_t npairs)
    C++: void mixChannels(const vector<Mat>& src, vector<Mat>& dst, const int* fromTo, int npairs)

    参数:src  输入的矩阵,可以是一个矩阵也可以是多个矩阵构成的vector

               nsrc   输入矩阵的个数

               dst   输出矩阵,可以是一个矩阵也可以是多个矩阵构成的vector

               ndst   输出矩阵的个数

               fromTo   src到dst通道对应数组

               npairs    fromTo中有几组对应关系

    mixChannels( )本质是改变了几个通道的顺序,输入一共有几个通道,输出肯定也有几个通道,所以定义fromTo时,要知道有多少个通道,而且通道的编号一定是0,1,2,...

    1. Mat RGB(3,4, CV_8UC3,Scalar(1,2,3,4));  
    2. Mat A(3,4,CV_8UC1,Scalar(6));  
    3. cout<<"RGB="<<endl<<RGB<<endl;  
    4. cout<<"A="<<endl<<A<<endl;  
    5.   
    6. //RGB+A合成为RGBA  
    7. cout<<"RGB+A合成为RGBA"<<endl;  
    8. Mat RGBA(3,4,CV_8UC4);  
    9. Mat in[]={RGB,A};  
    10. int fromTo1[] = {0,0, 1,1, 2,2, 3,3};  
    11. mixChannels(in,2,&RGBA,1,fromTo1,4);      
    12. cout<<"RGBA="<<endl<<RGBA<<endl;  
    13.   
    14. //RGB分解为R+GB  
    15. cout<<"RGB分解为R+GB"<<endl;  
    16. Mat R(3,4,CV_8UC1);  
    17. Mat GB(3,4, CV_8UC2);  
    18. Mat out[]={R,GB};  
    19. int fromTo2[] = {0,2, 1,1, 2,0};  
    20. mixChannels(&RGB,1,out,2,fromTo2,3);      
    21. cout<<"R="<<endl<<R<<endl;  
    22. cout<<"GB="<<endl<<GB<<endl;  



    3.2 以图像为例

    我们先来看一个例子

    1. Mat image=imread("E:/图片/color.jpg");  
    2. vector<Mat> channels;  
    3. split(image,channels);  
    4. Mat B = channels.at(0);  
    5. Mat G = channels.at(1);  
    6. Mat R = channels.at(2);  
    7. imshow("image",image);  
    8. imshow("R",R);  
    9. imshow("G",G);  
    10. imshow("B",B);  

    三个分量R、G、B因为是单通道图像,所以只能显示为灰度图。如果要想显示出颜色来,应该用三通道图像来显示,比如显示R,我们就让G和B通道的数值为0或255。看下面例子

    1. Mat image=imread("E:/图片/color.jpg");  
    2. vector<Mat> sbgr;   
    3. split(image,sbgr);   //split to sbgr[0],sbgr[1] ,sbgr[2]  
    4. vector<Mat> mbgr(3);  
    5. Mat bk1(image.size(),CV_8UC1,Scalar(0));  
    6. //Mat bk2(image.size(),CV_8UC1,Scalar(255));  
    7.   
    8. //显示彩色的B分量  
    9. Mat imageB(image.size(),CV_8UC3);  
    10. mbgr[0]= sbgr[0];  
    11. mbgr[1]= bk1;  
    12. mbgr[2]= bk1;  
    13. merge(mbgr,imageB);  
    14. imshow("imageB",imageB);  
    15.   
    16. //显示彩色的G分量  
    17. Mat imageG(image.size(),CV_8UC3);  
    18. mbgr[0]= bk1;  
    19. mbgr[1]= sbgr[1];  
    20. mbgr[2]= bk1;  
    21. merge(mbgr,imageG);  
    22. imshow("imageG",imageG);  
    23.   
    24. //显示彩色的R分量  
    25. Mat imageR(image.size(),CV_8UC3);  
    26. mbgr[0]= bk1;  
    27. mbgr[1]= bk1;  
    28. mbgr[2]= sbgr[2];  
    29. merge(mbgr,imageR);  
    30. imshow("imageR",imageR);  
    31.   
    32. imwrite("imageR.jpg",imageR);  
    33. imwrite("imageG.jpg",imageG);  
    34. imwrite("imageB.jpg",imageB);  
    35.   
    36. waitKey(0);  


    如果将bk1赋值成255,将会得到下面的图像

    4  制作一个透明的图片

          PNG是RGBA的图片格式,对于一般的RGB图像,我们只需要加上一个A通道,并且A通道的值不全为1(或255),就可以得到一个透明的图片。

    1. Mat image=imread("E:/图片/color.jpg");      
    2. //定义4种A通道  
    3. Mat imageA0 = Mat(image.size(),image.depth(),Scalar(0));         //image.depth()返回0,表示cv_8u  
    4. Mat imageA85 = Mat(image.size(),image.depth(),Scalar(85));  
    5. Mat imageA170 = Mat(image.size(),image.depth(),Scalar(170));  
    6. Mat imageA255 = Mat(image.size(),image.depth(),Scalar(255));      
    7.   
    8. //定义合成后的RGBA图像,透明度分别为0%,33%,67%,100%,透明---->不透明  
    9. Mat imageRGBA0 = Mat(image.size(),CV_8UC4);  
    10. Mat imageRGBA85 = Mat(image.size(),CV_8UC4);  
    11. Mat imageRGBA170 = Mat(image.size(),CV_8UC4);  
    12. Mat imageRGBA255 = Mat(image.size(),CV_8UC4);  
    13.   
    14. Mat in1[] = {image,imageA0};  
    15. Mat in2[] = {image,imageA85};  
    16. Mat in3[] = {image,imageA170};  
    17. Mat in4[] = {image,imageA255};  
    18. int from_to[] = {0,0, 1,1, 2,2, 3,3};  
    19. mixChannels(in1,2,&imageRGBA0,1,from_to,4);  
    20. mixChannels(in2,2,&imageRGBA85,1,from_to,4);  
    21. mixChannels(in3,2,&imageRGBA170,1,from_to,4);  
    22. mixChannels(in4,2,&imageRGBA255,1,from_to,4);  
    23.   
    24. imwrite("imageRGBA0.png",imageRGBA0);  
    25. imwrite("imageRGBA85.png",imageRGBA85);  
    26. imwrite("imageRGBA170.png",imageRGBA170);  
    27. imwrite("imageRGBA255.png",imageRGBA255);  

        

        直接用imshow( )是看不出差别来的,可以这么看。把一张PPT的空白背景替换成彩色背景,然后把这些 图片放上去,效果如下图所示。


        上图显示的结果实质是背景网格图片和我们的PNG图片叠加显示的效果。所以我们有个更简洁的方法实现上面的显示效果,是显示效果!

            imageResult = α·image + (1-α)·imageRGID

         我们只需要调整α的值就能控制image和imageGRID显示的比例了。

  • 相关阅读:
    Bootstrap3.0学习第八轮
    内存管理相关的信息
    SVN merge
    Asp.Net MVC 3
    formValidator
    jquery 分页控件2
    从零开始学C++之STL(四):算法简介、7种算法分类
    (Java实现) 过河卒
    (Java实现) N皇后问题
    (Java实现) N皇后问题
  • 原文地址:https://www.cnblogs.com/SuMeng/p/8371026.html
Copyright © 2020-2023  润新知