影像可以用不同的方式組合,就像是矩陣運算,各個相對像素做加減乘除,這邊介紹如何使用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;
}
有時我們想合併大小不同的影像,類似把一個小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;
}
转自:http://monkeycoding.com/?p=529