time:2015年 10月 03日 星期六 12:03:45 CST
# opencv筆記2:圖像ROI
ROI
ROI意思是Region Of Interests,感興趣區域,是一個圖中的一個子區域。
OpenCV中定義的ROI是矩形的。
ROI的用處包括而不限于:提取出ROI區域做進一步處理(比如人臉識別、車牌識別);將另一張圖片貼放到ROI區域。
這里以第二種用處為例,將一個logo圖像添加到一張大圖上指定的ROI區域。
圖像貼放
粗略想想,包括這四個步驟
- 定義大圖和小圖
- 在大圖上定義ROI區域
- 小圖貼放到ROI區域
- 顯示新的大圖
這里在fedora22下使用dnf(yum)安裝了opencv3.0,如下代碼可以運行良好
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
//【1】定義大圖和小圖
//【2】在大圖上定義ROI區域
//【3】小圖貼放到ROI區域
//【4】顯示新的大圖
//【1】定義大圖和小圖
Mat srcImage = imread("/home/chris/workspace/clion/dota_pa.jpg");
Mat logoImage = imread("/home/chris/workspace/clion/dota_ss.png");
if(!srcImage.data){
cerr << "讀取srcImage錯誤!" << endl;
exit;
}
if(!logoImage.data){
cerr << "讀取logoImage錯誤!" << endl;
exit;
}
//【2】在大圖上定義ROI區域
Mat imageROI = srcImage(Rect(20, 25, logoImage.cols, logoImage.rows));
//【3】小圖貼放到ROI區域
logoImage.copyTo(imageROI);
//【4】顯示新的大圖
imshow("利用ROI實現圖像疊加示例窗口", srcImage);
waitKey(0);
destroyAllWindows();
return 0;
}
這里copyTo()
函數中只用到一個參數,淺墨的教程上有第二個參數:圖像掩模(mask),我嘗試了下,發現不用mask也沒關系,mask的定義也不一定要是灰度圖(即imread第二個參數設定為0)。對此,我表示不理解,反正能用就好了。
圖像線性混合
直接把logo圖替換掉ROI區域的做法通常不是很好,如果能把兩者各按一定比例進行混合就顯得更好些,這需要用到圖像混合技術。
圖像線性混合,其實就是不同圖片(這里以兩張圖為例),各自按照一定比例系數進行相加,沒什么神奇的地方:
result = alpha*src1 + beta*src2 + gamma
使用函數addWeighted(src1, alpha, src2, beta, gamma, dstImage, dtype=-1)
這里dtype參數,是輸出陣列的可選深度,有默認值-1。;當兩個輸入數組具有相同的深度時,這個參數設置為-1(默認值),即等同于src1.depth()。
OK,粗略想下線性混合的步驟:
- 定義兩幅圖像
- 定義權重和偏置量等參數
- 按參數做圖像混合
- 顯示結果
上代碼:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
//【1】定義兩幅圖像
//【2】定義權重和偏置量等參數
//【3】按參數做圖像混合
//【4】顯示結果
//【1】定義兩幅圖像
Mat srcImage1 = imread("/home/chris/workspace/clion/mogu.jpg");
Mat srcImage2 = imread("/home/chris/workspace/clion/rain.jpg");
//【2】定義權重和偏置量等參數
double alpha = 0.5; //第一幅圖的權重
double beta = 1- alpha; //第二幅圖的權重
double gamma = 0.0; //偏置量
//【3】按參數做圖像混合
Mat dstImage; //目標圖像,存放結果
addWeighted(srcImage1, alpha, srcImage2, beta, gamma, dstImage);
//【4】顯示結果
imshow("線性混合結果", dstImage);
waitKey(0);
destroyAllWindows();
return 0;
}
好吧,其實這東西很簡單。應用到ROI區域,對應的代碼為:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
//【1】定義兩幅圖像
//【2】定義ROI區域
//【3】定義權重和偏置量等參數
//【4】按參數做圖像混合
//【5】顯示結果
//【1】定義兩幅圖像
Mat srcImage1 = imread("/home/chris/workspace/clion/dota_pa.jpg");
Mat srcImage2 = imread("/home/chris/workspace/clion/dota_ss.png");
//【2】定義ROI區域
Mat imageROI = srcImage1(Rect(20, 25, srcImage2.cols, srcImage2.rows));
//【3】定義權重和偏置量等參數
double alpha = 0.5; //第一幅圖的權重
double beta = 1- alpha; //第二幅圖的權重
double gamma = 0.0; //偏置量
//【4】按參數做圖像混合
addWeighted(imageROI, alpha, srcImage2, beta, gamma, imageROI);
//【5】顯示結果
imshow("線性混合結果", srcImage1);
waitKey(0);
destroyAllWindows();
return 0;
}
多通道的分離和混合
既然前面把圖像混合講到了,那么按照通道進行混合也就可以做了!比如要把看起來是白色的logo圖,和指定背景圖上ROI區域混合,并且希望logo圖顯示為紅色。這就需要ROI圖本身為紅色通道,logo圖讀取為灰度圖像(保證都是單通道),然后混合,這之后由于ROI區域就是原圖中的一個通道上的一個區域,原圖像的紅色通道變化了,現在把三個通道重新合并回去,就能夠得到想要的效果圖了。
粗略想下,步驟為:
- 定義義兩幅圖像
- 分離通道
- 在通道圖上定義ROI區域
- 定義權重和偏置量等參數
- 按參數做圖像混合
- 合并通道
- 顯示結果
對應的代碼為:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
//義兩幅圖像
//【2】分離通道
//【3】在通道圖上定義ROI區域
//【4】定義權重和偏置量等參數
//【5】按參數做圖像混合
//【6】合并通道
//【7】顯示結果
//【1】定義兩幅圖像
Mat srcImage = imread("/home/chris/workspace/clion/dota_pa.jpg");
Mat logoImage = imread("/home/chris/workspace/clion/dota_logo.jpg", 0);
//【2】分離通道
vector<Mat> channels;
split(srcImage, channels);
//【3】在通道圖上定義ROI區域
Mat redChannelImage = channels.at(2);
Mat imageROI = redChannelImage(Rect(50, 25, logoImage.cols, logoImage.rows));
//【4】定義權重和偏置量等參數
double alpha = 1.0;
double beta = 0.5;
double gamma = 0.0;
//【5】按參數做圖像混合
addWeighted(imageROI, alpha, logoImage, beta, gamma, imageROI);
//【6】合并通道
merge(channels, srcImage);
//【7】顯示結果
imshow("0通道", srcImage);
waitKey(0);
destroyAllWindows();
return 0;
}
文章列表