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];
			}
效果



发布了67 篇原创文章 · 获赞 77 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/weixin_37720172/article/details/72851497