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

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

在图像处理领域,我们常常要设置感兴趣区域(ROI,region of interest),来专注或者简化我们的工作过程,也就是从图像中选择的一个图像区域,这个区域是我们图像分析关注的重点。我们圈定这个区域,以便进行进一步处理。而且,使用ROI指定我们想读入的目标,可以减少处理时间,增加精度,给图像处理带来不小的便利。

ROI区域定义的两种方法

定义ROI区域有俩种方法,第一种是使用 cv::Rect ,顾名思义,cv::Rect 表示一个矩形区域。指定矩形的左上角坐标(构造函数的前俩个参数) 和矩形的长宽(构函数的后俩个参数)就可以定义一个矩形区域

 //定义一个Mat类型并给其设定ROI区域
Mat imageROI; //方法一
imageROI=image(Rect(,,logo.cols,logo.rows));

另一种定义ROI的方式是指定感兴趣行或列的范围Range.Range 是指从起始索引到终止索引(不包括终止索引)的一连段连续序列

cv::Range 可以用来定义Range .如果使用cv::Range 定义ROI ,那么前列定义ROI 的代码可以重写为:

 //方法二
imageROI = srcImage3((Range(,+logoImage.rows),Range(,+logoImage.cols));

好了,下面我们来看一个实例,显示如何利用ROI将一幅图加到另一幅图的指定位置。大家如果需要拷贝如下的函数中的代码直接运行的话,自己建一个基于console的程序,然后把函数体中的内容拷贝到main函数中,然后找两幅大小合适的图片,加入到工程目录下,并和代码中读取的文件名一致即可。

在下面的代码中,我们通过一个图像掩膜(mask),直接将插入处的像素设置为logo图像的像素值,这样效果会很赞很逼真

 /*------------------------------------------------------
函数名:ROI_AddImage()
描述: 利用感兴趣区域ROI实现图像叠加(把图像叠加到ROI区域中,而不是俩张图的直接叠加)
-------------------------------------------------------*/ #include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp> using namespace cv; bool ROI_AddImage()
{ //【1】读入图像
Mat srcImage1 = imread("dota_pa.jpg");
Mat logoImage = imread("dota_logo.jpg"); if (!srcImage1.data)
{
printf("fuck, read the picture is wrong!!! \n");
return false;
} if (!logoImage.data)
{
printf("fuck, read the picture is wrong!!! \n");
return false;
} //【2】定义一个Mat类型并给其设定ROI区域
Mat imageROI = srcImage1(Rect(,,logoImage.cols ,logoImage.rows)); //【3】加载掩膜
Mat mask = imread("dota_logo.jpg",); //【4】将掩膜拷贝到ROI
logoImage.copyTo(imageROI,mask); //【5】显示结果
namedWindow("1 利用ROI实现图像叠加示例窗口");
imshow("1 利用ROI实现图像叠加示例窗口",srcImage1); return true;
}

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

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

线性混合操作是一种典型的二元(两个输入)的像素操作,他的理论公式是这样的:

如果看过我之前写的游戏编程Alpha混合那篇文章的朋友们应该有些熟悉,其实他们是差不多的:

【Visual C++】游戏开发五十五浅墨 DirectX教程二十二水乳交融的美学:alpha混合技术

我们通过在范围0到1之间改变alpha值(α)值,来对两幅图像(f0(x)和f1(x))或两段视频(同样为(f0(x)和f1(x))产生时间上的画面叠化(cross-dissolve)效果,就像幻灯片放映和电影制作中的那样。即在幻灯片翻页时设置的前后页缓慢过渡叠加效果,以及电影情节过渡时经常出现的画面叠加效果。

实现方面,我们主要用了Opencv中AddWeighted函数,我们来全面的了解一下它:

addWeighted函数

这个函数的作用是,计算俩个数组(图像阵列)的加权和,原型如下:

 void addweighted (InputArray src1 ,double alpha, InputArray src2 ,double beta, double gamma, OutputArray dst ,int dtype = -);
  • 第一个参数,InputArray类型的src1,表示需要加权的第一个数组,常常填一个Mat。
  • 第二个参数,alpha,表示第一个数组的权重
  • 第三个参数,src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数。
  • 第四个参数,beta,表示第二个数组的权重值。
  • 第五个参数,dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。
  • 第六个参数,gamma,一个加到权重总和上的标量值。看下面的式子自然会理解。
  • 第七个参数,dtype,输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。

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

dst = src1[I]*alpha+ src2[I]*beta + gamma;

其中的I,是多维数组元素的索引值。而且,在遇到多通道数组的时候,每个通道都需要独立地进行处理。另外需要注意的是,当输出数组的深度为CV_32S时,这个函数就不适用了,这时候就会内存溢出或者算出的结果压根不对。

理论和函数的讲解就是上面这些,接着我们来看代码实例,以融会贯通。

 bool LinerBlending()
{
//【0】定义一些局部变量
double alphaValue = 0.5; //这些值感觉不懂
double betaValue;
Mat srcImage2, srcImage3, dstImage; //【1】读取图像(两幅图需为同样的类型和尺寸)
srcImage2 = imread("mogu.jpg");
srcImage3 = imread("rain.jpg"); if (!srcImage2.data)
{
printf("你妹,读取srcImage2错误!!! \n");
return false;
}
if (!srcImage3.data)
{
printf("你妹,读取srcImage3错误!!! \n");
return false;
} //【2】做图像混合加权操作
betaValue = (1.0 - alphaValue );
addWeighted(srcImage2,alphaValue ,srcImage3 ,betaValue, 0.0,dstImage ); //【3】创建并显示原图窗口
namedWindow("2 线性混合示例窗口【原图】 by hehhe",);
imshow("2 线性混合示例窗口【原图】 by hehhe", srcImage2); //【4】创建并显示效果图窗口
namedWindow("3 线性混合示例窗口【效果图】 by hehhe", );
imshow("3 线性混合示例窗口【效果图】 by hehhe",dstImage); return true; }

三、综合示例

在前面分别介绍的设定感兴趣区域ROI和使用addWeighted 函数进行线性混合的基础上,我们还将他们俩者中和起来使用,也就是先指定ROI,并用addWeighted 函数对我们指定的ROI区域进行混合操作,我们将其封装在了一个名为ROI_LinerBlending 的函数中。。。。。

 #include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream> using namespace cv;
using namespace std; bool ROI_AddImage();
bool LinerBlending();
bool ROI_LinerBlending(); /*--------------------------------------------------------------------------------------------------
【1】 函数名:ROI_AddImage()
描述: 利用感兴趣区域ROI实现图像叠加(把图像叠加到ROI区域中,而不是俩张图的直接叠加)
----------------------------------------------------------------------------------------------------*/ bool ROI_AddImage()
{ //【1】读入图像
Mat srcImage1 = imread("dota_pa.jpg");
Mat logoImage = imread("dota_logo.jpg"); if (!srcImage1.data)
{
printf("fuck, read the picture is wrong!!! \n");
return false;
} if (!logoImage.data)
{
printf("fuck, read the picture is wrong!!! \n");
return false;
} //【2】定义一个Mat类型并给其设定ROI区域
Mat imageROI = srcImage1(Rect(,,logoImage.cols ,logoImage.rows)); //【3】加载掩膜
Mat mask = imread("dota_logo.jpg",); //【4】将掩膜拷贝到ROI
logoImage.copyTo(imageROI,mask); //【5】显示结果
namedWindow("1 利用ROI实现图像叠加示例窗口");
imshow("1 利用ROI实现图像叠加示例窗口",srcImage1); //waitKey(); return true;
} /*----------------------------------------------------
【2】 函数名:LinerBlending
描述:利用cv::addWeighted() 函数实现图像线性混合
-------------------------------------------------------*/ bool LinerBlending()
{
//【0】定义一些局部变量
double alphaValue = 0.5; //这些值感觉不懂
double betaValue;
Mat srcImage2, srcImage3, dstImage; //【1】读取图像(两幅图需为同样的类型和尺寸)
srcImage2 = imread("mogu.jpg");
srcImage3 = imread("rain.jpg"); if (!srcImage2.data)
{
printf("你妹,读取srcImage2错误!!! \n");
return false;
}
if (!srcImage3.data)
{
printf("你妹,读取srcImage3错误!!! \n");
return false;
} //【2】做图像混合加权操作
betaValue = (1.0 - alphaValue );
addWeighted(srcImage2,alphaValue ,srcImage3 ,betaValue, 0.0,dstImage ); //【3】创建并显示原图窗口
namedWindow("2 线性混合示例窗口【原图】 by hehhe",);
imshow("2 线性混合示例窗口【原图】 by hehhe", srcImage2); //【4】创建并显示效果图窗口
namedWindow("3 线性混合示例窗口【效果图】 by hehhe", );
imshow("3 线性混合示例窗口【效果图】 by hehhe",dstImage); //waitKey(); return true; } /*---------------------------------------------------------------------------------------------
【3】 函数名:ROI_LinerBlending
描述: 线性混合实现函数,指定区域线性图像混合,利用cv::addWeighted ()结合定义
感兴趣区域ROI,实现自定义区域的线性混合
-----------------------------------------------------------------------------------------------*/
bool ROI_LinerBlending()
{
//【1】读取图像
Mat srcImage4 = imread("dota_pa.jpg",);
Mat logoImage = imread("dota_logo.jpg"); if (!srcImage4.data)
{
printf("你妹,读取srcImage4错误!!! \n");
return false;
}
if (!logoImage.data)
{
printf("你妹,读取srcImage错误!!! \n");
return false;
} //【2】定义一个Mat类型并给其设定ROI区域
Mat imageROI;
imageROI = srcImage4(Rect(,,logoImage.cols,logoImage.rows)); //【3】将logo 加到原图上
addWeighted(imageROI,0.5,logoImage,0.3,,imageROI); //【4】显示结果
namedWindow("4 区域线性图像混合示例窗口 by hehheh");
imshow("4 区域线性图像混合示例窗口 by hehheh",srcImage4); return true; } /*------------------------------------------------------
【4】 main函数
描述:控制台程序的入口函数,我们的程序从这里开始
----------------------------------------------------------*/ int main()
{
system("color 10"); //控制cmd 窗口的背景颜色 if (ROI_AddImage() && LinerBlending() && ROI_LinerBlending())
{
cout << "嗯,好了,得出了想要的图像" << endl;
} waitKey();
return ;
}

嗯,本篇文章到这里就基本结束了。。。。。。。。。。。。。。

最新文章

  1. delphi WebBrowser控件上网页验证码图片识别教程(一)
  2. webapi 通过dynamic 接收可变参数
  3. Microsoft Visual Studio 2013 VSTS单元测试指南
  4. 【Problem solved】 error C2665: “loadimage”: 2 个重载中没有一个可以转换所有参数类型
  5. hibernate一对一双向外键关联
  6. Android Weekly Notes Issue #250
  7. mysql 转义字符
  8. [51nod1291]Farmer
  9. 数据库学习番外篇 神奇的Redis
  10. JSON.Net 自定义Json序列化时间格式
  11. tiff图片拆分
  12. 通过Mybatis原始Dao来实现curd操作
  13. BIZHUB184打印机提示维修召唤(m2)修复
  14. 隐藏WIN10资源管理器中的3D对象文件夹
  15. leetcode42
  16. MCM/ICM2018美国大学生数学建模大赛D题翻译
  17. 【转】Phong和Blinn-Phong光照模型
  18. (转)js在数组中删除重复的元素自保留一个(两种实现思路)
  19. 求好用的在线手册编写工具,能编写像bootstrap在线Doc那种的,想为OpenCenter写个在线手册
  20. python 描述符 上下文管理协议 类装饰器 property metaclass

热门文章

  1. CSS实现进度条和订单进度条
  2. LeetCode Intersection of Two Arrays
  3. mysql utf8编码
  4. .Net 闭包理解
  5. canvas弹动2
  6. cocopod 中添加第三方框架,包含静态库文件,使用svn添加上传
  7. 【USACO 2.4】Overfencing(bfs最短路)
  8. Python3 函数
  9. Theano: CNMeM is disabled, CuDNN not available
  10. CSS DIV自动适应高度