影像相加(add、addWeighted)

影像可以用不同的方式組合,就像是矩陣運算,各個相對像素做加減乘除,這邊介紹如何使用addWeighted()和add()函式,將輸入影像進行混和,addWeighted()和add()只能處理相同大小的輸入圖,這邊另外介紹如何合併大小不同的影像,類似把一個小Logo加到原本影像上。

OpenCV影像相加:void add(InputArray src1, InputArray src2, OutputArray dst, InputArray mask=noArray(), int dtype=-1)

  • src1 :輸入圖或強度值。
  • src2 :輸入圖或強度值。
  • dst:輸出圖,輸出圖和輸入圖有相同的尺寸和通道數。
  • mask:可有可無的遮罩,8位元單通道圖,指定那些像素要計算。
  • dtype:可有可無的輸出圖深度。

OpenCV影像相加:void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1)

  • src1:輸入圖。
  • alpha:src1的權重。
  • src2:輸入圖,和src1的尺寸和通道數相同。
  • beta:src2的權重。
  • gamma:兩圖相加後再增加的值。
  • dst:輸出圖,輸出矩陣和輸入矩陣有相同的尺寸和通道數。
  • dtype:可有可無的輸出圖深度。

以下為函式概述,imgA、imgB、img皆為Mat,a[i]、b[i]、c[i]分別為此Mat的某個像素。

add(imgA, imgB, imgC);            //c[i] = a[i] + b[i]
add(imgA, imgB, imgC);            //c[i] = a[i] + b[i]
add(imgA, Scalar(20), imgC);      //c[i] = a[i] + 20
addWeighted(imgA, 0.8, imgB, 0.5, 10, imgC);   //c[i] = 0.8*a[i] + 0.5*b[i] + 10
scaleAdd(imgA, 1.2, imgB, imgC);  //c[i] = 1.2*a[i] + b[i]
add(imgA, imgB, imgC, mask);      //if(mask[i]) c[i] = a[i] + b[i]

這些運算內部都使用saturate_cast,來限制像素值在合理範圍內,以8位元影像來說,就是用saturate_cast限制範圍在0~255,而且參與運算的影像必須有相同的大小和深度,輸出圖像如果大小或格式不同,會重新分配空間。

有時我們只想處理部分區域,這時要使用遮罩(mask),這時我們可呼叫函式add(imgA, imgB, imgC, mask),這樣會在遮罩像素不為NULL的地方才相加,而遮罩必須是單通道的。

除了加法運算之外,OpenCV也提供像subtract、absdiff、multiply等多種矩陣運算,詳細用法可參考OpenCV文件。


以下範例為用兩個輸入圖,各佔0.5的比例混和產生新的圖:

#include <cstdio>
#include <opencv2/opencv.hpp>
using namespace cv;

int main(){
    Mat src1 = imread("input1.jpg",CV_LOAD_IMAGE_UNCHANGED);
    Mat src2 = imread("input2.jpg",CV_LOAD_IMAGE_UNCHANGED);
    Mat dst;
    addWeighted(src1,0.5,src2,0.5,0,dst);

    namedWindow("window1");
    namedWindow("window2");
    namedWindow("window3");
    imshow("window1", src1);
    imshow("window2", src2);
    imshow("window3", dst);
    waitKey(0); 

    return 0;
}

addWeighted

addWeighted

addWeighted


有時我們想合併大小不同的影像,類似把一個小Logo加到原本影像上,且能夠指定Logo的位置,由於add()函式要求輸入的影像格式、尺寸相同,所以不能直接使用add(),在使用之前要先定義感興趣區域(ROI),ROI大小和Logo圖相同,ROI位置決定Logo圖插入位置。我們使用addWeighted()調整背景和logo圖的強度比例,以下的imageROI和logo這兩個Mat,需要大小、尺寸相同,imageROI和img指向相同的數據結構,因此當我們改變imgROI時,原始圖img也隨之更改,達到插入Logo圖到原始圖的目的,以下為程式碼:

Mat img = imread("background.jpg");
Mat logo = imread("logo.jpg");
Mat imgROI = img(Rect(30,30,logo.cols,logo.rows));  //指定插入的大小和位置
addWeighted(imgROI,0.5,logo,0.5,0,imgROI);
  • 我們可以把imgROI想成是一張左上角在(30,30),寬logo.cols,高logo.rows的圖,重疊的像素值和img相同,而兩者指向相同的資料。

我們可用類似方法,來取得影像的某個部分來儲存或顯示,像下面的croppedImage為image這個影像,從(100,100)這個位置開始,寬度150、高度200的圖。

Mat croppedImage = image(Rect(100, 100, 150, 200));

以下示範如何將logo圖,混和添加在原始圖上產生一個新的圖:

#include <cstdio>
#include <opencv2/opencv.hpp>
using namespace cv;

int main(){
    Mat src = imread("background.jpg",CV_LOAD_IMAGE_UNCHANGED);
    Mat logo = imread("logo.jpg",CV_LOAD_IMAGE_UNCHANGED);
    Mat dst = imread("background.jpg",CV_LOAD_IMAGE_UNCHANGED);
    Mat imgROI = dst(Rect(30,30,logo.cols,logo.rows));  //指定插入的大小和位置
    addWeighted(imgROI,0.5,logo,0.5,0,imgROI);

    namedWindow("window1");
    namedWindow("window2");
    namedWindow("window3");
    imshow("window1", src);
    imshow("window2", logo);
    imshow("window3", dst);
    waitKey(0); 

    return 0;
}

addWeighted

addWeighted

addWeighted

繼續閱讀 影像相加(add、addWeighted)