天天看點

(OpenCV — 8)分離顔色通道、多通道圖像混合

使用 addWeighted 函數進行圖像混合操作,以及如何将 ROI 和 addWeighted 函數結合起來 , 對指定區域進行圖像混合操作。

參考:​​(OpenCV — 7)ROI 區域圖像疊加&圖像混合​​ 而為了更好地觀察一些圖像材料的特征,有時需要對 RGB 三個顔色通道的分量進行分别顯示和調整。通過 OpenCV 的 split 和 merge 方法可以很友善地達到目的 。

通道分離: split()函數

split 函數用于将一個 多通道數組分離成幾個單通道數組。這裡的 array 按語境翻譯為數組或者陣列。

這個 split 函數的 C++版本有兩個原型 , 分别是 :

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

變量介紹如下 :

  • 第一個參數, InputArray 類型的 m 或者 const Mat&類型的 src , 填我們需要進行分離 的多通道數組。
  • 第二個參數, OutputArrayOfArrays 類型的 mv , 填函數的輸出數組或者輸出的 vector 容器。

split 函數分割多通道數組轉換成獨立的單通道數組 , 公式如下 :

(OpenCV — 8)分離顔色通道、多通道圖像混合

執行個體代碼:

//【0】定義相關變量
    Mat srcImage;
    Mat logoImage;
    vector<Mat> channels;
    Mat  imageBlueChannel;

    //=================【藍色通道部分】=================
    //  描述:多通道混合-藍色分量部分
    //============================================

    // 【1】讀入圖檔
    logoImage= imread("D:\\QT\\project\\opencv_qtcreaor\\dota_logo_5_3.jpg",0);
    srcImage= imread("D:\\QT\\project\\opencv_qtcreaor\\dota_jugg_5_3.jpg");

    if( !logoImage.data ) { printf("Oh,no,讀取logoImage錯誤~! \n"); return false; }
    if( !srcImage.data ) { printf("Oh,no,讀取srcImage錯誤~! \n"); return false; }

    //【2】把一個3通道圖像轉換成3個單通道圖像
    split(srcImage,channels);//分離色彩通道

    //【3】将原圖的藍色通道引用傳回給imageBlueChannel,注意是引用,相當于兩者等價,修改其中一個另一個跟着變
    imageBlueChannel= channels.at(0);
    //【4】将原圖的藍色通道的(500,250)坐标處右下方的一塊區域和logo圖進行權重操作,将得到的混合結果存到imageBlueChannel中
    addWeighted(imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
        logoImage,0.5,0,imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)));

    //【5】将三個單通道重新合并成一個三通道
    merge(channels,srcImage);

    //【6】顯示效果圖
    namedWindow(" <1>遊戲原畫+logo藍色通道");
    imshow(" <1>遊戲原畫+logo藍色通道",srcImage);      

通道合并: merge()函數

merge()函數是 split()函數 的逆 向操作一将多 個數組合并成一個 多通道的數組 。 它通過組合一些給定 的單通道數組 , 将這些孤立的單通道數組合并成一個多通道的數組,進而建立出 一個由多個單通道陣列組成的 多通道陣列 。 它有兩個基于 C++的 函數原型如下 。

void merge(const Mat* mv, size_t count, 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.a t(0)      

這裡的 Mat: :at()方法傳回一個引用到指定 的數組元素 。 注意是引用,相當于兩者等價,也就是修改其中一個 , 另 一個也會随之改變。

依然是一個示例 , 如下 。

vector<Mat> channels;
Mat imageBlueChannel;
Mat imageGreenChannel;
Mat imageRedChannel ;
srcimage4 = imread("dota.jpg" );
//把一個 3 通道 圖像轉換成 3 個單通道圖像
split(srcimage4, channels);//分離色彩通道
imageBlueChannel = channels.at(0);
imageGreenChannel = channels.at(1);
imageRedChannel = channels.at(2);      

上面的代碼先做了 相關的類型聲明 , 然後把載入 的 3 通道圖像轉換成 3 個單通道圖像,放到 vector<Mat>類型的 channels 中,接着進行引用指派 。

根據 OpenCV 的 BGR 色彩空間 (Bule 、 Green 、 Red 、藍綠紅),其中 channels.at(0)就表示引用取出 channels 中的藍色分量 , channels.at(1)就表示引用取出 channels中的綠色分量, channels.at(2)就表示引用取出 channels 中的紅色分量 。

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

上面隻是實作單一顔色混合,下面實作BGR三色混合

Mat srcImage;
    Mat logoImage;
    vector<Mat> channels;
    Mat  imageBlueChannel_B;
    Mat  imageBlueChannel_G;
    Mat  imageBlueChannel_R;

    logoImage= imread("D:\\QT\\project\\opencv_qtcreaor\\dota_logo_5_3.jpg",0);
    srcImage= imread("D:\\QT\\project\\opencv_qtcreaor\\dota_jugg_5_3.jpg");

    if( !logoImage.data ) { printf("Oh,no,讀取logoImage錯誤~! \n"); return false; }
    if( !srcImage.data ) { printf("Oh,no,讀取srcImage錯誤~! \n"); return false; }

    split(srcImage,channels);//分離色彩通道

    imageBlueChannel_B= channels.at(0);
    addWeighted(imageBlueChannel_B(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
        logoImage,0.5,0,imageBlueChannel_B(Rect(500,250,logoImage.cols,logoImage.rows)));

    imageBlueChannel_G= channels.at(1);
    addWeighted(imageBlueChannel_G(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
        logoImage,0.5,0.,imageBlueChannel_G(Rect(500,250,logoImage.cols,logoImage.rows)));

    imageBlueChannel_R= channels.at(2);
    addWeighted(imageBlueChannel_R(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
        logoImage,0.5,0.,imageBlueChannel_R(Rect(500,250,logoImage.cols,logoImage.rows)));

    merge(channels,srcImage);

    namedWindow("效果圖");
    imshow("效果圖",srcImage);      

運作結果:

(OpenCV — 8)分離顔色通道、多通道圖像混合

原理圖:

(OpenCV — 8)分離顔色通道、多通道圖像混合

繼續閱讀