文章参考浅墨_毛星云的【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
logo.png
朱朱.jpg
----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中addWeighted函数,
void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);
第一个参数,InputArray类型的src1,表示需要加权的第一个数组,常常填一个Mat。
第六个参数,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教程时一样,看到代码全放在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<