學習 opencv---(4) 分離顏色通道 && 多通道混合


   上篇文章中我們講到了使用addWeighted函數進行圖像混合操作,以及將ROI和addWeighted函數結合起來使用,對指定區域進行圖像混合操作。

    而為了更好地觀察一些圖像材料的特征,有時需要對RGB三個顏色通道的分量進行 分割顯示和調整 。通過Opencv 的split和merge 方法很方便 達到的目的。

    

   

      一、分離顏色通道

     先講講這倆個互為冤家的函數。首先講進行通道分離的split 函數

 

     <1>split函數詳解

       將一個多通道數組分離成幾個單通道數組。  PS:這里的array按語境譯為 數組或陣列。

    這里的split 函數的C++版本有倆個原型,他們分別是:

1 void split(const Mat& src,Mat *mvbegin); 2 void split(InputArray m, OutputArrayOfArrays mv);

 

 

 

     變量介紹:

     ----第一個參數:InputArray類型的m或者const Mat&類型的src,填我們需要進行分離的多通道數組。

     ----第二個參數,OutputArrayOfArrays類型的mv,填函數的輸出數組或者輸出的vector容器。

 

 

      這里的OutputArrayOfArrays我們通過【轉到定義】大法,可以查到它是_OutputArray的引用,那么我們在源代碼中再次通過【轉到定義】看到_OutputArray類的原型,即是OutputArrayOfArrays的原型:

 1 class CV_EXPORTS _OutputArray : public_InputArray  2 {  3 public:  4  _OutputArray();  5    
 6    _OutputArray(Mat& m);  7    template<typename _Tp> _OutputArray(vector<_Tp>& vec);  8    template<typename _Tp> _OutputArray(vector<vector<_Tp>>& vec);  9    _OutputArray(vector<Mat>& vec); 10    template<typename _Tp> _OutputArray(vector<Mat_<_Tp>>& vec); 11    template<typename _Tp> _OutputArray(Mat_<_Tp>& m); 12    template<typename _Tp, int m, int n> _OutputArray(Matx<_Tp, m,n>& matx); 13    template<typename _Tp> _OutputArray(_Tp* vec, int n); 14    _OutputArray(gpu::GpuMat& d_mat); 15    _OutputArray(ogl::Buffer& buf); 16    _OutputArray(ogl::Texture2D& tex); 17    
18     _OutputArray(constMat& m); 19    template<typename _Tp> _OutputArray(const vector<_Tp>&vec); 20    template<typename _Tp> _OutputArray(constvector<vector<_Tp> >& vec); 21    _OutputArray(const vector<Mat>& vec); 22    template<typename _Tp> _OutputArray(const vector<Mat_<_Tp>>& vec); 23    template<typename _Tp> _OutputArray(const Mat_<_Tp>& m); 24    template<typename _Tp, int m, int n> _OutputArray(constMatx<_Tp, m, n>& matx); 25    template<typename _Tp> _OutputArray(const _Tp* vec, int n); 26    _OutputArray(const gpu::GpuMat& d_mat); 27    _OutputArray(const ogl::Buffer& buf); 28    _OutputArray(const ogl::Texture2D& tex); 29    
30    virtual bool fixedSize() const; 31    virtual bool fixedType() const; 32    virtual bool needed() const; 33    virtual Mat& getMatRef(int i=-1) const; 34    /*virtual*/ gpu::GpuMat& getGpuMatRef() const; 35    /*virtual*/ ogl::Buffer& getOGlBufferRef() const; 36    /*virtual*/ ogl::Texture2D& getOGlTexture2DRef() const; 37    virtual void create(Size sz, int type, int i=-1, bool allowTransposed=false,int fixedDepthMask=0) const; 38    virtual void create(int rows, int cols, int type, int i=-1, boolallowTransposed=false, int fixedDepthMask=0) const; 39    virtual void create(int dims, const int* size, int type, int i=-1, boolallowTransposed=false, int fixedDepthMask=0) const; 40    virtual void release() const; 41    virtual void clear() const; 42    
43 #ifdefOPENCV_CAN_BREAK_BINARY_COMPATIBILITY 44    virtual ~_OutputArray(); 45 #endif  
46 };  

   

     類體中還是有不少內容的,其實注意到里面是定義的各種模板,重載的各種構造函數就可以了。

 

好了,穿越完OutputArrayOfArrays的介紹,我們繼續講解split。

 

split函數分割多通道數組轉換成獨立的單通道數組,按公式來看就是這樣:

 

                             

 

   

     <2>merge函數詳解

    merge()函數的功能是split()函數的逆向操作,將多個數組組合合並成一個多通道的數組

     它通過組合一些給定的單通道數組,將這些孤立的單通道數組合並成一個多通道的數組,從而創建出一個由多個單通道陣列組成的多通道陣列。它有兩個基於C++的函數原型:

void merge(const Mat* mv, size_tcount,OutputArray dst); void merge(InputArrayOfArrays mv, OutputArray dst);

    

  • 第一個參數,mv,填需要被合並的輸入矩陣或vector容器的陣列,這個mv參數中所有的矩陣必須有着一樣的尺寸和深度。
  • 第二個參數,count,當mv為一個空白的C數組時,代表輸入矩陣的個數,這個參數顯然必須大於1.
  • 第三個參數,dst,即輸出矩陣,和mv[0]擁有一樣的尺寸和深度,並且通道的數量是矩陣陣列中的通道的總數。

   

函數解析:

merge函數的功能是將一些數組合並成一個多通道的數組。關於組合的細節,輸出矩陣中的每個元素都將是輸出數組的串接,其中,第i個輸入數組的元素被視為mv[i]。 c一般用其中的Mat::at()方法對某個通道進行存取,也就是這樣用channels.at(0)。

PS: Mat::at()方法,返回一個引用到指定的數組元素。注意是引用,相當於兩者等價,修改其中一個另一個跟着變。

    

    

一對做相反操作的plit()函數和merge()函數和用法就是這些了。另外提一點,如果我們需要從多通道數組中提取出特定的單通道數組,或者說實現一些復雜的通道組合,可以使用mixChannels()函數。

 

      

    二、多通道圖像混合示例程序

    我們把多通道圖像混合的實現代碼封裝在了名為MultiChannelBlending()的函數中

    

 1 #include <iostream>
 2 #include <vector>
 3 #include <opencv2/core/core.hpp>
 4 #include <opencv2/highgui/highgui.hpp>
 5 
 6 
 7 using namespace cv;  8 using namespace std;  9 
 10 bool MultiChannelBlending();  11 
 12 
 13 
 14 /*-------------------------------------------------------------  15  多通道混合的實現函數  16 ---------------------------------------------------------------*/
 17 bool MultiChannelBlending()  18 {  19  Mat srcImage;  20  Mat logoImage;  21     vector<Mat> channels;  22     
 23     /*-----------------藍色通道部分----------------------------  24  描述:多通道混合--藍色部分  25  -----------------------------------------------------------*/
 26     //【0】定義相關變量
 27  Mat imageBlueChannel;  28 
 29     //【1】讀入圖片
 30     logoImage = imread("dota_logo.jpg",0);  31     srcImage = imread("dota_jugg.jpg");  32     if (!logoImage.data)  33  {  34         printf("Oh,no,讀取logoImage錯誤~! \n");  35         return false;  36  }  37     if (!srcImage.data)  38  {  39         printf("Oh,no,讀取srcImage錯誤~! \n");  40         return false;  41  }  42 
 43     //【2】把一個3通道圖像轉換成3個單通道圖像
 44  split(srcImage,channels);  45 
 46     //【3】將原圖的藍色通道引用返回給 imageBlueChannel,注意是引用,相當於兩者等價,修改一個另一個也跟着變
 47     imageBlueChannel = channels.at(0);  48 
 49     //【4】將原圖的藍色通道的(500,250)坐標處右下方的一塊區域和logo 圖進行加權操作,將得到的混合結果存到imageBlueChannel中
 50     addWeighted(imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,logoImage,0.5,0,  51                 imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)));  52 
 53     //【5】將3個單通道重新合並成1個3通道
 54  merge(channels,srcImage);  55 
 56     //【6】顯示效果圖
 57     namedWindow("1 游戲原畫+(logo+原畫藍色通道) byhehheh");  58     imshow("1 游戲原畫+(logo+原畫藍色通道) byhehheh",srcImage);  59 
 60 
 61     
 62     /*-----------------綠色通道部分----------------------------  63  描述:多通道混合--綠色部分  64  -----------------------------------------------------------*/
 65     //【0】定義相關變量  66     //Mat imageGreenChannel;
 67     /*
 68  //【1】讀入圖片  69  logoImage = imread("dota_logo.jpg", 0);  70  srcImage = imread("dota_jugg.jpg");  71  if (!logoImage.data)  72  {  73  printf("Oh,no,讀取logoImage錯誤~! \n");  74  return false;  75  }  76  if (!srcImage.data)  77  {  78  printf("Oh,no,讀取srcImage錯誤~! \n");  79  return false;  80  }  81     */
 82     /*    
 83  //【2】把一個3通道圖像轉換成3個單通道圖像  84  split(srcImage, channels);  85 
 86  //【3】將原圖的綠色通道引用返回給 imageBlueChannel,注意是引用,相當於兩者等價,修改一個另一個也跟着變  87  imageGreenChannel = channels.at(0);  88 
 89  //【4】將原圖的綠色通道的(500,250)坐標處右下方的一塊區域和logo 圖進行加權操作,將得到的混合結果存到imageBlueChannel中  90  addWeighted(imageGreenChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0, logoImage, 0.5, 0,  91  imageGreenChannel(Rect(500, 250, logoImage.cols, logoImage.rows)));  92 
 93  //【5】將3個單通道重新合並成1個3通道  94  merge(channels, srcImage);  95 
 96  //【6】顯示效果圖  97  namedWindow("2 游戲原畫+(logo+原畫綠色通道) byhehheh");  98  imshow("2 游戲原畫+(logo+原畫綠色通道) byhehheh", srcImage);  99     */
100 
101     /*-----------------紅色通道部分---------------------------- 102  描述:多通道混合--紅色部分 103  -----------------------------------------------------------*/
104     //【0】定義相關變量 105     //Mat imageRedChannel;
106     /*
107  //【1】讀入圖片 108  logoImage = imread("dota_logo.jpg", 0); 109  srcImage = imread("dota_jugg.jpg"); 110  if (!logoImage.data) 111  { 112  printf("Oh,no,讀取logoImage錯誤~! \n"); 113  return false; 114  } 115  if (!srcImage.data) 116  { 117  printf("Oh,no,讀取srcImage錯誤~! \n"); 118  return false; 119  } 120     */
121     /*
122  //【2】把一個3通道圖像轉換成3個單通道圖像 123  split(srcImage, channels); 124 
125  //【3】將原圖的紅色通道引用返回給 imageBlueChannel,注意是引用,相當於兩者等價,修改一個另一個也跟着變 126  imageRedChannel = channels.at(0); 127 
128  //【4】將原圖的紅色通道的(500,250)坐標處右下方的一塊區域和logo 圖進行加權操作,將得到的混合結果存到imageBlueChannel中 129  addWeighted(imageRedChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0, logoImage, 0.5, 0, 130  imageRedChannel(Rect(500, 250, logoImage.cols, logoImage.rows))); 131 
132  //【5】將3個單通道重新合並成1個3通道 133  merge(channels, srcImage); 134 
135  //【6】顯示效果圖 136  namedWindow("3 游戲原畫+(logo+原畫紅色通道) byhehheh"); 137  imshow("3 游戲原畫+(logo+原畫紅色通道) byhehheh", srcImage); 138     */
139     return true; 140 } 141 
142 
143 /*分離顏色通道&多通道圖像混合*/
144 int main() 145 { 146     system("color 6E"); 147 
148     if (MultiChannelBlending()) 149  { 150         cout << "得出了需要的圖像" << endl; 151  } 152 
153     waitKey(0); 154     return 0; 155 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM