学习@浅墨_毛星云的【OpenCV入门教程】之四


文章参考浅墨_毛星云的【OpenCV入门教程】http://blog.csdn.net/poem_qianmo/article/details/20911629


我们一起学习了在OpenCV中如何定义感兴趣区域ROI,如何使用addWeighted函数进行图像混合操作,以及将ROI和addWeighted函数结合起来使用,对指定区域进行图像混合操作。混合操作为两类:

一、设定感兴趣区域——ROI(region of interest)

----Test1()为函数,将1,jpg,logo.png两张图混合到朱朱.jpg并分别显示出来

//设定感兴趣区域——ROI混合
//函数Test1()将1,jpg,logo.png两张图混合到朱朱.jpg并分别显示出来
bool Test1()
{
        //读入彩色图片1.jpg
  Mat img1=    imread("img/1.jpg",1);
    //读入图片logo.png
  Mat img2=imread("img/logo.png",1);
  if(!img1.data){printf("读取图片有误!");return false;}
   if(!img2.data){printf("读取图片有误!");return false;}
    //创建两个窗口
    namedWindow("显示图片1");
    namedWindow("显示图片2");
    //显示上面两张图片
    imshow("显示图片1",img1);
    imshow("显示图片2",img2);

    //将这两张图片进行融合成图片"朱朱.jpg"
     //1、定义感兴趣的区域
    Mat imgROI;
          //--方法1:cv::Rect表示一个矩形区域。指定矩形的左上角坐标(构造函数的前两个参数)和矩形的长宽(构造函数的后两个参数)就可以定义一个矩形区域。
    //imgROI=img1(Rect(100,100,img2.cols,img2.rows));

     //--方法2:指定感兴趣行或列的范围(Range)Range是指从起始索引到终止索引(不包括终止索引)的一连段连续序列。cv::Range可以用来定义Range。
    imgROI=img1(Range(200,img2.rows+200),Range(100,img2.cols+100));
    //在imgROI区域,将img2合成到img1上去
    addWeighted(imgROI,0.2,img2,0.8,0.0,imgROI);

    //将融合好的图片写到指定的图片"朱朱.jpg"上
    imwrite("img/朱朱.jpg",img1);

    //将imgROI显示出来
    namedWindow("朱朱");
    imshow("朱朱",img1);
    return true;
}
效果图如下:

1.jpg

学习@浅墨_毛星云的【OpenCV入门教程】之四_第1张图片

logo.png

学习@浅墨_毛星云的【OpenCV入门教程】之四_第2张图片

朱朱.jpg

学习@浅墨_毛星云的【OpenCV入门教程】之四_第3张图片

----Test2()通过一个图像掩膜(mask),直接将插入处的像素设置为logo图像的像素值。

这个函数首先是载入了两张jpg图片到image和logo中,然后定义了一个Mat类型的imgROI,并使用cv::Rect设置其感兴趣区域为image中的一块区域,将imgROI和image关联起来。接着定义了一个Mat类型的的mask并读入logo.jpg,顺势使用Mat:: copyTo把mask中的内容拷贝到imgROI中,于是就得到了最终的效果图,namedWindow和imshow配合使用,显示出最终的结果。

//设定感兴趣区域——ROI跟掩模mask

bool Test2()
{
	//1`读两张图片
	Mat image=imread("img/2.jpg",1);
	Mat logo=imread("img/logo.png",1);
	 if(!image.data){printf("读取图片有误!");return false;}
	  if(!logo.data){printf("读取图片有误!");return false;}
	//2`定义一个Mat类型的ROI区域
	Mat imgROI=image(Rect(100,100,logo.cols,logo.rows));
	//3`加载掩模(必须是灰度图)
	Mat mask=imread("img/logo.png",0);
	//4`将掩模mask拷贝到ROI
	logo.copyTo(imgROI,mask);
	//5`显示结果
	namedWindow("利用ROI实现图像叠加");
	imshow("利用ROI实现图像叠加",image);
	return true;
}
上面的效果图:

学习@浅墨_毛星云的【OpenCV入门教程】之四_第4张图片

二、初级图像混合——线性混合操作

主要运用了OpenCV中addWeighted函数,

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

   第一个参数,InputArray类型的src1,表示需要加权的第一个数组,常常填一个Mat。
    第二个参数,alpha,表示第一个数组的权重
    第三个参数,src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数。
    第四个参数,beta,表示第二个数组的权重值。
   第五个参数,gamma,一个加到权重总和上的标量值。看下面的式子自然会理解。

  第六个参数,dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。 

  第七个参数,dtype,输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。

 
如果用数学公式来表达,addWeighted函数计算如下两个数组(src1和src2)的加权和,得到结果输出给第四个参数。即addWeighted函数的作用可以被表示为为如下的矩阵表达式为:
                                                      dst = src1[I]*alpha+ src2[I]*beta + gamma;

-----下面Test3(),img1和img2大小尺寸一样

//初级图像混合——线性混合操作
bool Test3()
{
	//声明
	Mat img2,img3,imgMax;
	double alpha=0.8;
	double beta=1-alpha;
	//读入
	img2=imread("img/2.jpg",1);
	img3=imread("img/3.jpg",1);
	if(!img2.data){printf("读取图片有误!");return false;}
	if(!img3.data){printf("读取图片有误!");return false;}
	addWeighted(img2,alpha,img3,beta,0,imgMax);
	
	namedWindow("线性混合图片显示");
	imshow("线性混合图片显示",imgMax);
	return true;
}
上面的效果图:


在前面分别介绍的设定感兴趣区域ROI和使用addWeighted函数进行图像线性混合的基础上,我们还将他们两者中和起来使用,也就是先指定ROI,并用addWeighted函数对我们指定的ROI区域的图像进行混合操作,下面是一个综合示例Test4(),

//设定感线性+区域ROI混合

bool Test4()
{
	Mat img1=imread("img/1.jpg",1);
	Mat logo=imread("img/logo.png",1);
	if(!img1.data){printf("读取图片有误!");return false;}
	if(!logo.data){printf("读取图片有误!");return false;}

	Mat imgROI=img1(Rect(200,200,logo.cols,logo.rows));
	addWeighted(imgROI,0.4,logo,0.6,0.0,imgROI);
	namedWindow("线性区域混合显示图片",1);
	imshow("线性区域混合显示图片",imgROI);
	return true;
}
上面的效果图:

学习@浅墨_毛星云的【OpenCV入门教程】之四_第5张图片

为了方便大家分块各个击破学习,每讲一个部分,示例代码都将封装在一个函数中,免得大家像学习各种不是特别地道的OpenCV教程时一样,看到代码全放在main函数中。
本篇文章的全部示例源代码:

#include
#include
#include

using namespace cv;
using namespace std;

//设定感兴趣区域——ROI混合
//函数Test1()将1,jpg,logo.png两张图融合到朱朱.jpg并分别显示出来
bool Test1()
{
		//读入彩色图片1.jpg
  Mat img1=	imread("img/1.jpg",1);
	//读入图片logo.png
  Mat img2=imread("img/logo.png",1);
  if(!img1.data){printf("读取图片有误!");return false;}
   if(!img2.data){printf("读取图片有误!");return false;}
	//创建两个窗口
	namedWindow("显示图片1");
	namedWindow("显示图片2");
	//显示上面两张图片
	imshow("显示图片1",img1);
	imshow("显示图片2",img2);

	//将这两张图片进行融合成图片"朱朱.jpg"
     //1、定义感兴趣的区域
	Mat imgROI;
	      //--方法1:cv::Rect表示一个矩形区域。指定矩形的左上角坐标(构造函数的前两个参数)
	//和矩形的长宽(构造函数的后两个参数)就可以定义一个矩形区域。
	//imgROI=img1(Rect(100,100,img2.cols,img2.rows));

	 //--方法2:指定感兴趣行或列的范围(Range)Range是指从起始索引到终止索引(不包括终止索引)
	//的一连段连续序列。cv::Range可以用来定义Range。
	imgROI=img1(Range(200,img2.rows+200),Range(100,img2.cols+100));
	//在imgROI区域,将img2合成到img1上去
	addWeighted(imgROI,0.2,img2,0.8,0.0,imgROI);

	//将融合好的图片写到指定的图片"朱朱.jpg"上
	imwrite("img/朱朱.jpg",img1);

	//将imgROI显示出来
	namedWindow("朱朱");
	imshow("朱朱",img1);
	return true;
}

//设定感兴趣区域——ROI混合

bool Test2()
{
	//1`读两张图片
	Mat image=imread("img/2.jpg",1);
	Mat logo=imread("img/logo.png",1);
	 if(!image.data){printf("读取图片有误!");return false;}
	  if(!logo.data){printf("读取图片有误!");return false;}
	//2`定义一个Mat类型的ROI区域
	Mat imgROI=image(Rect(100,100,logo.cols,logo.rows));
	//3`加载掩模(必须是灰度图)
	Mat mask=imread("img/logo.png",0);
	//4`将掩模mask拷贝到ROI
	logo.copyTo(imgROI,mask);
	//5`显示结果
	namedWindow("利用ROI实现图像叠加");
	imshow("利用ROI实现图像叠加",image);
	return true;
}

//初级图像混合——线性混合操作
bool Test3()
{
	//声明
	Mat img2,img3,imgMax;
	double alpha=0.8;
	double beta=1-alpha;
	//读入
	img2=imread("img/2.jpg",1);
	img3=imread("img/3.jpg",1);
	if(!img2.data){printf("读取图片有误!");return false;}
	if(!img3.data){printf("读取图片有误!");return false;}
	addWeighted(img2,alpha,img3,beta,0,imgMax);
	
	namedWindow("线性混合图片显示");
	imshow("线性混合图片显示",imgMax);
	return true;
}

//设定感线性+区域ROI混合

bool Test4()
{
	Mat img1=imread("img/1.jpg",1);
	Mat logo=imread("img/logo.png",1);
	if(!img1.data){printf("读取图片有误!");return false;}
	if(!logo.data){printf("读取图片有误!");return false;}

	Mat imgROI=img1(Rect(200,200,logo.cols,logo.rows));
	addWeighted(imgROI,0.4,logo,0.6,0.0,imgROI);
	namedWindow("线性区域混合显示图片",1);
	imshow("线性区域混合显示图片",imgROI);
	return true;
}
int main()
{
	system("color 5E");//5E取值范围0~F,前一位表背景色5:紫色,后一位表前景色
	if(Test1()&&Test2()&&Test3()&&Test4())
	{
		cout<

新人学习,向@浅墨_毛星云表示感谢~


你可能感兴趣的:(Opencv)