文章出處


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;

}

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()