1. 程式人生 > >openCV之影象混合

openCV之影象混合

        有時候,我們需要將兩張圖片融合在一起。

比如我們要把下面這兩張合併為一張:


最後得到這兩種效果圖:


        這些操作也不是很難。

        在這之前我們需要了解一個函式

CV_EXPORTS_W void addWeighted(InputArray src1, double alpha, InputArray src2,double beta, double gamma, OutputArray dst, int dtype = -1);

第一個引數(InputArray src1): 就是輸入要融合的Mat類圖1

      第二個引數(alpha):就是輸入src1的透明度0-1,1代表原圖輸入,0代表全透明

      第三個引數(InputArray src2): 就是輸入要融合的Mat類圖2

      第四個引數(beta):就是輸入src2的透明度0-1,1代表原圖輸入,0代表全透明

      第五個引數(gama):需要結合第六個引數來理解

      第六個引數(dst):dst=src1*alpha+src2*beta+gama,就是加權處理

      第七個引數(dtype):輸出陣列的可選深度,有預設值-1。;當兩個輸入陣列具有相同的深度時,這個引數設定為-1(預設值),即等同於src1.depth()。

首先我們需要確定我們感興趣的區域(ROI),有不懂的怎麼定義的可以去看前面我在基礎內容裡面寫到的

ROI定義

下面我們給出程式碼:

bool add() {

	Mat image = imread("帽子.png");
	Mat image1 = imread("路飛.jpg");
	//定義ROI區域,注意對ROI操作也會改變image1相應區域的影象
	Mat ROI_image = image1(Range(0, 0+image.rows), Range(0, 0+image.cols));
	//alpha為0.5,beta為0.5
	addWeighted(ROI_image, 0.5, image, 0.5, 0, ROI_image);

	imshow("效果", image1);
	return true;

}
效果就是這樣啦

      可是我們發現雖然是融合了,但是那塊白濛濛的看著就討厭,怎麼去掉呢?

      其實也不難。我們只需要將骷顱頭黑色區域摳出來打到路飛圖上就行了。

      openCV彩色影象是建立在BGR通道上建立起來的。我們需要處理下畫素級別的點就可以了。

      訪問畫素點我們可通過以下指令來操作:

	//Vec3b表示有3通道為uchar型的元素點
	int x = 100, y = 50;//座標點,把一張圖看作一個座標圖,左上為原點,向右為y正向,向下為x正向
	image.at<Vec3b>(x, y)[0];//訪問image在(x,y)位置出的藍色通道
	image.at<Vec3b>(x, y)[1];//訪問image在(x,y)位置出的綠色通道
	image.at<Vec3b>(x, y)[2];//訪問image在(x,y)位置出的紅色通道


知道怎麼訪問畫素點後,還需要影象的成色原理,即顏色都是有三原色(對應著畫素的三通道),通過改變這三種顏色的值(0-255)來得到我們需要的顏色。我們可以看到在骷顱頭的影象中,主要是由白色和黑色組成,白色三通道一般為【255,255,255】,黑色為【0,0,0】

但是在一張圖片中圖片即便是看起來全部都是白色的區域,如果深入到畫素點探究會發現很多畫素點並不是完美的【255,255,255】更多的是像【255,249,245】,【250,254,249】等這種接近完美白色的畫素點。

我們可以執行一下程式碼驗證下:

	for(int i=0;i<image.rows;++i)
		for (int j=0; j < image.cols; ++j) 
			if ((image.at<Vec3b>(i, j)[0] != 255) || (image.at<Vec3b>(i, j)[1] != 255) || (image.at<Vec3b>(i, j)[2] != 255)) {
				image1.at<Vec3b>(i, j)[0] = image.at<Vec3b>(i, j)[0];
				image1.at<Vec3b>(i, j)[1] = image.at<Vec3b>(i, j)[1];
				image1.at<Vec3b>(i, j)[2] = image.at<Vec3b>(i, j)[2];
			}

得到的圖

可以看到圖中還是有些白色的點加了進去,這些白色的點可能就是類似與【254,254,253】這種接近完美白色的畫素點,為了改變一下我們可以用兩種方法來改正。

第一種就是處理骷顱頭的所有接近完美白色的點都成為完美白色畫素【255,255,255】,其餘都變為完美黑色畫素【0,0,0】

給出程式碼:

	for (int i = 0; i < image.rows; ++i)
		for (int j = 0; j < image.cols; ++j) {
			if ((image.at<Vec3b>(i, j)[0] < 220) && (image.at<Vec3b>(i, j)[1] < 220) && (image.at<Vec3b>(i, j)[2] < 220)) {
				//完美黑色
				image.at<Vec3b>(i, j)[0] = 0;
				image.at<Vec3b>(i, j)[1] = 0;
				image.at<Vec3b>(i, j)[2] = 0;
			}
			else {//完美白色
				image.at<Vec3b>(i, j)[0] = 255;
				image.at<Vec3b>(i, j)[1] = 255;
				image.at<Vec3b>(i, j)[2] = 255;
			}
		}


結合上面的程式,可以得到以下效果圖:



第二種方法很簡單,只要是接近黑色的我全給他摳出來給貼上去:

由於為了保證圖的真實性,只要三通道的值都小於200就認為其為黑色

		for (int j=0; j < image.cols; ++j) 
			if ((image.at<Vec3b>(i, j)[0] < 200) && (image.at<Vec3b>(i, j)[1] < 200) && (image.at<Vec3b>(i, j)[2] < 200)) {
				image1.at<Vec3b>(i, j)[0] = image.at<Vec3b>(i, j)[0];
				image1.at<Vec3b>(i, j)[1] = image.at<Vec3b>(i, j)[1];
				image1.at<Vec3b>(i, j)[2] = image.at<Vec3b>(i, j)[2];
			}
效果