在圖像處理中,目標區(qū)域定義為感興趣區(qū)域ROI(region of Interest),這是后期圖像處理的基礎,在獲取ROI后,進行一些列的處理。ROI區(qū)域在Opencv中就是Rect,先構建Rect,然后給予ROI一些特點,形成了圖像掩膜。 一、ROI創(chuàng)建//定義一個Mat類型并給其設定ROI區(qū)域 Mat imageROI; //方法一 imageROI=image(Rect(500,250,logo.cols,logo.rows)); //方法二 imageROI=Image(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols)); 代碼中定義了一個Mat類型,是一種類似指針的引用,然后指向Image(Mat)中制定區(qū)域,這樣就創(chuàng)建了一個ROI區(qū)域,這個區(qū)域在Image中。 二、圖像掩膜圖像掩膜,在ROI區(qū)域中導入一張圖像,然后在image中進行加載 Mat Image1= imread("dota_pa.jpg"); //定義一個Mat類型并給其設定ROI區(qū)域 ,指向Image中坐標點200,250,長寬為cols和rows Mat imageROI= Image1(Rect(200,250,logoImage.cols,logoImage.rows)); //加載掩模(必須是灰度圖) Mat mask= imread("dota_logo.jpg",0); //將掩膜拷貝到ROI logoImage.copyTo(imageROI,mask); 三、線性混合線性混合就是,對兩幅圖像(f0(x)和f1(x))或兩段視頻(同樣為(f0(x)和f1(x))產生時間上的畫面疊化(cross-dissolve)效果,就像幻燈片放映和電影制作中的那樣。函數表示為: 1、opencv函數-addWeighted函數void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1); //第一個參數,InputArray類型的src1,表示需要加權的第一個數組,常常填一個Mat。 //第二個參數,alpha,表示第一個數組的權重 //第三個參數,src2,表示第二個數組,它需要和第一個數組擁有相同的尺寸和通道數。 //第四個參數,beta,表示第二個數組的權重值。 //第五個參數,dst,輸出的數組,它和輸入的兩個數組擁有相同的尺寸和通道數。 //第六個參數,gamma,一個加到權重總和上的標量值。看下面的式子自然會理解。 //第七個參數,dtype,輸出陣列的可選深度,有默認值-1。;當兩個輸入數組具有相同的深度時,個參數設置為-1(默認值),即等同于src1.depth()。dst = src1 addWeighted函數計算如下兩個數組(src1和src2)的加權和,得到結果輸出給第四個參數。即addWeighted函數的作用可以被表示為為如下的矩陣表達式為: dst = src1[I]*alpha+ src2[I]*beta + gamma; 2、實例代碼//【1】讀取圖像 Mat srcImage4= imread("dota_pa.jpg",1); Mat logoImage= imread("dota_logo.jpg"); if(!srcImage4.data ) { printf("你妹,讀取srcImage4錯誤~! \n"); return false; } if(!logoImage.data ) { printf("你妹,讀取logoImage錯誤~! \n"); return false; } //【2】定義一個Mat類型并給其設定ROI區(qū)域 Mat imageROI; //方法一 imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows)); //【3】將logo加到原圖上 ,利用線性混合構建掩膜,其中l(wèi)ogo權重是0.3,原圖中的ROI區(qū)域圖像是0.5 addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI); //【4】顯示結果 namedWindow("<4>區(qū)域線性圖像混合示例窗口 by淺墨"); imshow("<4>區(qū)域線性圖像混合示例窗口 by淺墨",srcImage4); return true; 四、多通道顏色混合彩色圖像是三通道圖像,當然灰度圖像是單通道圖像,在圖像應用中需要對某一通道混合,或者幾個通道顏色混合,這就是多通道顏色混合。在多通道顏色混合應用中在opencv需要split函數和merge函數。 1、分離顏色通道C++: void split(const Mat& src, Mat*mvbegin); C++: void split(InputArray m,OutputArrayOfArrays mv); //第一個參數,InputArray類型的m或者const Mat&類型的src,填我們需要進行分離的多通道數組。 //第二個參數,OutputArrayOfArrays類型的mv,填函數的輸出數組或者輸出的vector容器 split函數分割多通道數組轉換成獨立的單通道數組,按公式來講: class CV_EXPORTS _OutputArray : public_InputArray { public: _OutputArray(); _OutputArray(Mat& m); template<typename _Tp> _OutputArray(vector<_Tp>& vec); template<typename _Tp> _OutputArray(vector<vector<_Tp>>& vec); _OutputArray(vector<Mat>& vec); template<typename _Tp> _OutputArray(vector<Mat_<_Tp>>& vec); template<typename _Tp> _OutputArray(Mat_<_Tp>& m); template<typename _Tp, int m, int n> _OutputArray(Matx<_Tp, m,n>& matx); template<typename _Tp> _OutputArray(_Tp* vec, int n); _OutputArray(gpu::GpuMat& d_mat); _OutputArray(ogl::Buffer& buf); _OutputArray(ogl::Texture2D& tex); _OutputArray(constMat& m); template<typename _Tp> _OutputArray(const vector<_Tp>&vec); template<typename _Tp> _OutputArray(constvector<vector<_Tp> >& vec); _OutputArray(const vector<Mat>& vec); template<typename _Tp> _OutputArray(const vector<Mat_<_Tp>>& vec); template<typename _Tp> _OutputArray(const Mat_<_Tp>& m); template<typename _Tp, int m, int n> _OutputArray(constMatx<_Tp, m, n>& matx); template<typename _Tp> _OutputArray(const _Tp* vec, int n); _OutputArray(const gpu::GpuMat& d_mat); _OutputArray(const ogl::Buffer& buf); _OutputArray(const ogl::Texture2D& tex); virtual bool fixedSize() const; virtual bool fixedType() const; virtual bool needed() const; virtual Mat& getMatRef(int i=-1) const; /*virtual*/ gpu::GpuMat& getGpuMatRef() const; /*virtual*/ ogl::Buffer& getOGlBufferRef() const; /*virtual*/ ogl::Texture2D& getOGlTexture2DRef() const; virtual void create(Size sz, int type, int i=-1, bool allowTransposed=false,int fixedDepthMask=0) const; virtual void create(int rows, int cols, int type, int i=-1, boolallowTransposed=false, int fixedDepthMask=0) const; virtual void create(int dims, const int* size, int type, int i=-1, boolallowTransposed=false, int fixedDepthMask=0) const; virtual void release() const; virtual void clear() const; #ifdefOPENCV_CAN_BREAK_BINARY_COMPATIBILITY virtual ~_OutputArray(); #endif }; 上面函數講解是OutputArray類原型,其中是模板類為主,注意類對象的創(chuàng)建。 split函數應用 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中的紅色分量。 2、圖像混合圖像混合中通過組合一些給定的單通道數組,將這些孤立的單通道數組合并成一個多通道的數組,從而創(chuàng)建出一個由多個單通道陣列組成的多通道陣列。 merge()函數的功能是split()函數的逆向操作,將多個數組組合合并成一個多通道的數組。 C++: void merge(const Mat* mv, size_tcount, OutputArray dst) C++: void merge(InputArrayOfArrays mv,OutputArray dst) //第一個參數,mv,填需要被合并的輸入矩陣或vector容器的陣列,這個mv參數中所有的矩陣必須有著一樣的尺寸和深度。 //第二個參數,count,當mv為一個空白的C數組時,代表輸入矩陣的個數,這個參數顯然必須大于1. //第三個參數,dst,即輸出矩陣,和mv[0]擁有一樣的尺寸和深度,并且通道的數量是矩陣陣列中的通道的總數。 五、圖像混合綜合代碼及解析//-----------------------------------【程序說明】---------------------------------------------- // 程序名稱::【OpenCV入門教程之四】分離顏色通道&多通道圖像混合 配套源碼 // VS2010版 OpenCV版本:2.4.8 // 2014年3月13 日 Create by 淺墨 // 圖片素材出處:dota2原畫 dota2logo // 配套博文鏈接:http://blog.csdn.net/poem_qianmo/article/details/20537737 // 淺墨的微博:@淺墨_毛星云 //------------------------------------------------------------------------------------------------ //-----------------------------------【頭文件包含部分】--------------------------------------- // 描述:包含程序所依賴的頭文件 //---------------------------------------------------------------------------------------------- #include <cv.hpp> #include <highgui.hpp> #include <iostream> //-----------------------------------【命名空間聲明部分】--------------------------------------- // 描述:包含程序所使用的命名空間 //----------------------------------------------------------------------------------------------- using namespace cv; using namespace std; //-----------------------------------【全局函數聲明部分】-------------------------------------- // 描述:全局函數聲明 //----------------------------------------------------------------------------------------------- bool MultiChannelBlending(); //-----------------------------------【main( )函數】-------------------------------------------- // 描述:控制臺應用程序的入口函數,我們的程序從這里開始 //----------------------------------------------------------------------------------------------- int main( ) { system("color 5E"); if(MultiChannelBlending( )) { cout<<endl<<"嗯。好了,得出了你需要的混合值圖像~"; } waitKey(0); return 0; } //-----------------------------【MultiChannelBlending( )函數】-------------------------------- // 描述:多通道混合的實現函數 //----------------------------------------------------------------------------------------------- bool MultiChannelBlending() { //【0】定義相關變量 Mat srcImage,greSrcImage,redSrcImage; Mat logoImage; vector<Mat> channels; Mat imageBlueChannel; //【0】定義相關變量 Mat imageGreenChannel; //【0】定義相關變量 Mat imageRedChannel,redTempImage,greTempImage,blueTempImage; //=================【藍色通道部分】================= // 描述:多通道混合-藍色分量部分 //============================================ // 【1】讀入圖片 logoImage= imread("dota_logo.jpg",0); srcImage= imread("dota_jugg.jpg"); if( !logoImage.data ) { printf("Oh,no,讀取logoImage錯誤~! \n"); return false; } if( !srcImage.data ) { printf("Oh,no,讀取srcImage錯誤~! \n"); return false; } srcImage.copyTo(greSrcImage); srcImage.copyTo(redSrcImage); //【2】把一個3通道圖像轉換成3個單通道圖像 split(srcImage,channels);//分離色彩通道 //【3】將原圖的藍色通道引用返回給imageBlueChannel,注意是引用,相當于兩者等價,修改其中一個另一個跟著變 imageBlueChannel= channels.at(0); //這是引用,指向channels,后面調用clear,這樣數據清空了 //imageGreenChannel = channels.at(1); ////展示單通道圖像 //imshow("單通道藍色圖像",imageBlueChannel); //imshow("單通道紅色圖像",imageRedChannel); //imshow("單通道綠色圖像",imageGreenChannel); //【4】將原圖的藍色通道的(500,250)坐標處右下方的一塊區(qū)域和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))); imshow("加載log后的藍色圖像",imageBlueChannel); //【5】將三個單通道重新合并成一個三通道 merge(channels,srcImage); //【6】顯示效果圖 imshow(" 游戲原畫+logo藍色通道",srcImage); //=================【綠色通道部分】================= // 描述:多通道混合-綠色分量部分 //============================================ // imshow("綠色圖像原圖像",greSrcImage); //因為同道中藍色通道已經加載logo進去,所以此時logo會有變化的,重新分離通道 channels.clear(); split(greSrcImage,channels); imageGreenChannel = channels.at(1); //【4】將原圖的綠色通道的(500,250)坐標處右下方的一塊區(qū)域和logo圖進行加權操作,將得到的混合結果存到imageGreenChannel中 addWeighted(imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0, logoImage,0.5,0.,imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows))); //【5】將三個獨立的單通道重新合并成一個三通道,如果繼續(xù)這樣,因為同道中藍色通道已經加載logo進去,所以此時logo會有變化的 merge(channels,greSrcImage); //【6】顯示效果圖 imshow("<2>游戲原畫+logo綠色通道",greSrcImage); //=================【紅色通道部分】================= // 描述:多通道混合-紅色分量部分 //============================================ channels.clear(); split(redSrcImage,channels); imageRedChannel = channels.at(2); //【4】將原圖的紅色通道的(500,250)坐標處右下方的一塊區(qū)域和logo圖進行加權操作,將得到的混合結果存到imageRedChannel中 addWeighted(imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0, logoImage,0.5,0.,imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows))); //【5】將三個獨立的單通道重新合并成一個三通道 merge(channels,redSrcImage); //【6】顯示效果圖 imshow("<3>游戲原畫+logo紅色通道",redSrcImage); return true; } 六、結果分析1、上述代碼中有ROI,就是創(chuàng)建感興趣區(qū)域,在代碼中直接用addweight函數直接完成了,實現mask的創(chuàng)建,是在SrcImage中ROI通過加權,將想要的圖像加載其中,實現mask的創(chuàng)建。 2、代碼中對split和merge進行演示、講解,split函數用于獲取單通道圖像,程序中對單通道圖像進行展示,發(fā)現單通道圖像都是灰度圖像,只是各個單通道圖像亮度不同,說明了在彩色圖像中red各占的比例大小。同時對于進行mask處理后的圖像進行展示,當然也是灰度圖像。 3、程序中分別是在srcImage中獲取到紅綠藍的logo進行處理,就是先將需要的通道獲取到,將logo按照一定比例添加其中(通道圖像權重要高一點,才能讓在roi中夜色占據主動),然后再合并。 4、程序一定注意到mat類型的應用,在程序大部分操作時引用,要記得保留未修改的數據。 |
|