11、【opencv入門】ROI區域 mask掩碼 圖像疊加&初級圖像混合


一、設定感興趣的區域---ROI(region of interest)

  在圖像處理領域,我們常常需要設置感興趣區域(ROI,region of interest),來專注或者簡化我們的工作過程 。也就是從圖像中選擇的一個圖像區域,這個區域是我們圖像分析所關注的重點。我們圈定這個區域,以便進行進一步處理。而且,使用ROI指定我們想讀入的目標,可以減少處理時間,增加精度,給圖像處理來帶不小的便利。

ROI區域定義的兩種方法

  定義ROI區域有兩種方法,第一種是使用cv:Rect.顧名思義,cv::Rect表示一個矩形區域。指定矩形的左上角坐標(構造函數的前兩個參數)和矩形的長寬(構造函數的后兩個參數)就可以定義一個矩形區域。

1 //定義一個Mat類型並給其設定ROI區域 2 Mat imageROI; 3 //方法一 4 imageROI=image(Rect(500,250,logo.cols,logo.rows));

  另一種定義ROI的方式是指定感興趣行或列的范圍(Range)。Range是指從起始索引到終止索引(不包括終止索引)的一連段連續序列。

  cv::Range可以用來定義Range。如果使用cv::Range來定義ROI,那么前例中定義ROI的代碼可以重寫為:

1 //方法二 2 imageROI=srcImage3(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

二、mask掩碼

1     mask(掩碼或者掩膜):是一個8位單通道圖像(灰度圖像/二值圖像) 2  掩碼某個位置如果為0,則在此位置上的操作不起作用 3  掩碼某個位置如果不為0,則在此位置上的操作會起作用。 4 可以用來提取不規則ROI

  在下面的示例中,我們通過一個圖像掩膜(mask),直接將插入處的像素設置為logo圖像的像素值,這樣效果會很贊很逼真:

 1 // 描述:利用感興趣區域ROI實現圖像疊加  2 #include<iostream>  3 #include<opencv2/core/core.hpp>  4 #include<opencv2/highgui/highgui.hpp>  5  6 using namespace std;  7 using namespace cv;//OpenCV中的C++類和函數都是定義在命名空間cv之內的  8  9 int main() 10 { 11 //【1】讀入圖像 12 Mat srcImage1= imread("poster_dota.jpg"); 13 if(!srcImage1.data ) 14  { 15 cout << "讀取錯誤!" << endl; 16 return false; 17  } 18 19 Mat logoImage= imread("poster_dota_logo.jpg"); 20 if(!logoImage.data ) 21  { 22 cout << "讀取錯誤!" << endl; 23 return false; 24  } 25 26 //【2】定義一個Mat類型並給其設定ROI區域Rect()函數的前兩個參數表示左上角的起始坐標,后兩個參數表示長方向的長、寬 27 Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows)); 28 29 //【3】加載掩模(必須是灰度圖) 30 Mat mask= imread("dota_logo.jpg",0); 31 32 //【4】將掩膜拷貝到ROI 33  logoImage.copyTo(imageROI,mask); 34 35 //【5】顯示結果 36 namedWindow("<1>利用ROI實現圖像疊加示例窗口"); 37 imshow("<1>利用ROI實現圖像疊加示例窗口",srcImage1); 38 39 waitKey(0);//等待按鍵觸發 40 return true; 41 }

  首先是載入了兩張jpg圖片到srcImage1和logoImage中,然后定義了一個Mat類型的imageROI,並使用cv::Rect設置其感興趣區域為srcImage1中的一塊區域,將imageROI和srcImage1關聯起來。

  接着定義了一個Mat類型的的mask並讀入dota_logo.jpg,順勢使用Mat:: copyTo把mask中的內容拷貝到imageROI中,於是就得到了最終的效果圖,namedWindow和imshow配合使用,顯示出最終的結果。

這里白色的dota2 logo,就是通過操作之后加上去的圖像。

三、初級圖像混合 --- 線性混合

  線性混合操作是一種典型的二元(兩個輸入)的像素操作,它的理論公式是這樣的:

 

  我們通過在范圍0到1之間改變alpha值,來對兩幅圖像(f0(x)和f1(x))或兩段視頻(同樣為(f0(x)和f1(x))產生時間上的畫面疊化(cross-dissolve)效果,就像幻燈片放映和電影制作中的那樣。

實現方面,我們主要運用了OpenCV中addWeighted函數。

addWeighted函數

這個函數的作用是,計算兩個數組(圖像陣列)的加權和。原型如下:

1 void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);
1  第一個參數,InputArray類型的src1,表示需要加權的第一個數組,常常填一個Mat。 2  第二個參數,alpha,表示第一個數組的權重 3  第三個參數,src2,表示第二個數組,它需要和第一個數組擁有相同的尺寸和通道數。 4  第四個參數,beta,表示第二個數組的權重值。 5  第五個參數,gamma,一個加到權重總和上的標量值。看下面的式子自然會理解。 6  第六個參數,dst,輸出的數組,它和輸入的兩個數組擁有相同的尺寸和通道數。 7 第七個參數,dtype,輸出陣列的可選深度,有默認值-1。;當兩個輸入數組具有相同的深度時,這個參數設置為-1(默認值),即等同於src1.depth()。

  如果用數學公式來表達,addWeighted函數計算如下兩個數組(src1和src2)的加權和,得到結果輸出給第四個參數。即addWeighted函數的作用可以被表示為為如下的矩陣表達式為:

 dst = src1[I]*alpha+ src2[I]*beta + gamma;

  其中的I,是多維數組元素的索引值。而且,在遇到多通道數組的時候,每個通道都需要獨立地進行處理。另外需要注意的是,當輸出數組的深度為CV_32S時,這個函數就不適用了,這時候就會內存溢出或者算出的結果壓根不對。

【示例】

 1 //初級圖像混合 --- 線性混合  2 #include<iostream>  3 #include<opencv2/core/core.hpp>  4 #include<opencv2/highgui/highgui.hpp>  5  6 using namespace std;  7 using namespace cv;//OpenCV中的C++類和函數都是定義在命名空間cv之內的  8  9 int main() 10 { 11 double alphaValue = 0.5; 12 double betaValue; 13 14  Mat srcImage2, srcImage3, dstImage; 15 16 //讀取圖像 17 srcImage2 = imread("1.jpg"); 18 if(!srcImage2.data) 19  { 20 cout << "讀取錯誤!" << endl; 21 return false; 22  } 23 srcImage3 = imread("2.jpg"); 24 if(!srcImage3.data) 25  { 26 cout << "讀取錯誤!" << endl; 27 return false; 28  } 29 30 //圖像混合加權操作 31 betaValue = (1.0 - alphaValue); 32 addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage); 33 34 //創建窗口並顯示原圖 35 namedWindow("線性混合示例窗口【原圖】", 1); 36 imshow("線性混合示例窗口【原圖】",srcImage2); 37 38 //創建窗口並顯示混合后的圖像 39 namedWindow("線性混合示例窗口【效果圖】", 1); 40 imshow("線性混合示例窗口【效果圖】", dstImage); 41 42 waitKey(0);//等待按鍵輸入 43 return true; 44 }

四、綜合示例

  在前面分別介紹的設定感興趣區域ROI和使用addWeighted函數進行圖像線性混合的基礎上,我們還將他們兩者中和起來使用,也就是先指定ROI,並用addWeighted函數對我們指定的ROI區域的圖像進行混合操作。

 【示例】

  1 //綜合示例 ROI區域圖像疊加 圖像線性混合  2 #include<iostream>  3 #include<opencv2/core/core.hpp>  4 #include<opencv2/highgui/highgui.hpp>  5  6 using namespace cv;  7 using namespace std;  8  9 //函數聲明  10 bool ROI_AddImage();  11 bool LinearBlending();  12 bool ROI_LinearBlending();  13  14 int main()  15 {  16 system("color 5E");  17 if(ROI_AddImage() && LinearBlending() && ROI_LinearBlending())  18  {  19 cout<<endl<<"嗯。好了,得出了你需要的圖像~! : )";  20  }  21  22 waitKey(0);  23 return 0;  24 }  25  26 //ROI圖像疊加  27 bool ROI_AddImage()  28 {  29  30 //【1】讀入圖像  31 Mat srcImage1= imread("dota.jpg");  32 if(!srcImage1.data )  33  {  34 cout << "讀取錯誤!" << endl;  35 return false;  36  }  37  38 Mat logoImage= imread("dota_logo.jpg");  39 if(!logoImage.data )  40  {  41 cout << "讀取錯誤!" << endl;  42 return false;  43  }  44  45 //【2】方法一:定義一個Mat類型並給其設定ROI區域  46 Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));  47 //方法二:定義一個Mat類型並給其設定ROI區域  48 //Mat imageROI=srcImage1(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));  49  50 //【3】加載掩模(必須是灰度圖)  51 Mat mask= imread("dota_logo.jpg",0);  52  53 //【4】將掩膜拷貝到ROI  54  logoImage.copyTo(imageROI,mask);  55  56 //【5】顯示結果  57 namedWindow("<1>利用ROI實現圖像疊加示例窗口");  58 imshow("<1>利用ROI實現圖像疊加示例窗口",srcImage1);  59 //waitKey(0);//等待按鍵輸入  60 return true;  61 }  62 //圖像的線性混合  63 bool LinearBlending()  64 {  65    double alphaValue = 0.5;  66 double betaValue;  67  68  Mat srcImage2, srcImage3, dstImage;  69  70 //讀取圖像  71 srcImage2 = imread("1.jpg"); 72 if(!srcImage2.data) 73 { 74 cout << "讀取錯誤!" << endl; 75 return false; 76 } 77 srcImage3 = imread("2.jpg"); 78 if(!srcImage3.data) 79 { 80 cout << "讀取錯誤!" << endl; 81 return false; 82 } 83 84 //圖像混合加權操作 85 betaValue = (1.0 - alphaValue); 86 addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 1.0, dstImage); 87 88 //創建窗口並顯示原圖 89 namedWindow("線性混合示例窗口【原圖】", 1); 90 imshow("線性混合示例窗口【原圖】",srcImage2); 91 92 //創建窗口並顯示混合后的圖像 93 namedWindow("線性混合示例窗口【效果圖】", 1); 94 imshow("線性混合示例窗口【效果圖】", dstImage); 95 96 //waitKey(0);//等待按鍵輸入 97 return true; 98 } 99 100 //指定區域的線性混合 101 bool ROI_LinearBlending() 102 { 103 //【1】讀取圖像 104 Mat srcImage4= imread("dota.jpg",1); 105 Mat logoImage= imread("dota_logo.jpg"); 106 107 if(!srcImage4.data ) 108 { 109 cout << "讀取錯誤!" << endl; 110 return false; 111 } 112 if(!logoImage.data ) 113 { 114 cout << "讀取錯誤!" << endl; 115 return false; 116 } 117 118 //【2】定義一個Mat類型並給其設定ROI區域 119 Mat imageROI; 120 //方法一 121 imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows)); 122 //方法二 123 //imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols)); 124 125 //【3】將logo加到原圖上 126 addWeighted(imageROI,0.5,logoImage,0.3,0.0,imageROI); 127 128 //【4】顯示結果 129 namedWindow("<4>ROI區域線性圖像混合示例窗口 by淺墨"); 130 imshow("<4>ROI區域線性圖像混合示例窗口 by淺墨",srcImage4); 131 //waitKey(0);//等待按鍵輸入 132 return true; 133 }

 


免責聲明!

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



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