向浅墨学习!

本系列文章由@浅墨_毛星云 出品,转载请注明出处。

文章链接: http://blog.csdn.net/poem_qianmo/article/details/20911629

作者:毛星云(浅墨)    邮箱: happylifemxy@163.com

写作当前博文时配套使用的OpenCV版本: 2.4.8

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

PS:文章末尾提供了博文配套程序源代码的下载。

文章开头,依旧是先放一张截图:

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

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

ROI区域定义的两种方法

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

[cpp]  view plain copy print ?
  1. //定义一个Mat类型并给其设定ROI区域
  2. Mat imageROI;
  3. //方法一
  4. imageROI=image(Rect(500,250,logo.cols,logo.rows));

另一种定义ROI的方式是指定感兴趣行或列的范围(Range)。Range是指从起始索引到终止索引(不包括终止索引)的一连段连续序列。cv::Range可以用来定义Range。如果使用cv::Range来定义ROI,那么前例中定义ROI的代码可以重写为:

[cpp]  view plain copy print ?
  1. //方法二
  2. imageROI=srcImage3(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

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

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

[cpp]  view plain copy print ?
  1. //----------------------------------【ROI_AddImage( )函数】----------------------------------
  2. // 函数名:ROI_AddImage()
  3. //     描述:利用感兴趣区域ROI实现图像叠加
  4. //----------------------------------------------------------------------------------------------
  5. bool ROI_AddImage()
  6. {
  7. //【1】读入图像
  8. Mat srcImage1= imread("dota_pa.jpg");
  9. Mat logoImage= imread("dota_logo.jpg");
  10. if(!srcImage1.data ) { printf("你妹,读取srcImage1错误~! \n"); return false; }
  11. if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }
  12. //【2】定义一个Mat类型并给其设定ROI区域
  13. Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));
  14. //【3】加载掩模(必须是灰度图)
  15. Mat mask= imread("dota_logo.jpg",0);
  16. //【4】将掩膜拷贝到ROI
  17. logoImage.copyTo(imageROI,mask);
  18. //【5】显示结果
  19. namedWindow("<1>利用ROI实现图像叠加示例窗口");
  20. imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);
  21. return true;
  22. }

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

运行结果如下:

这里白色的dota2 logo,就是通过操作之后加上去的图像。

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

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

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

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

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

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

addWeighted函数

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

[cpp]  view plain copy print ?
  1. void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);
  • 第一个参数,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时,这个函数就不适用了,这时候就会内存溢出或者算出的结果压根不对。

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

[cpp]  view plain copy print ?
  1. //---------------------------------【LinearBlending()函数】-------------------------------------
  2. // 函数名:LinearBlending()
  3. // 描述:利用cv::addWeighted()函数实现图像线性混合
  4. //--------------------------------------------------------------------------------------------
  5. bool LinearBlending()
  6. {
  7. //【0】定义一些局部变量
  8. double alphaValue = 0.5;
  9. double betaValue;
  10. Mat srcImage2, srcImage3, dstImage;
  11. //【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
  12. srcImage2= imread("mogu.jpg");
  13. srcImage3= imread("rain.jpg");
  14. if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }
  15. if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }
  16. //【2】做图像混合加权操作
  17. betaValue= ( 1.0 - alphaValue );
  18. addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);
  19. //【3】创建并显示原图窗口
  20. namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);
  21. imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );
  22. namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);
  23. imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );
  24. return true;
  25. }

代码解析:

<0>首先当然是定义一些局部变量,alpha值beta值,三个Mat类型的变量。

[cpp]  view plain copy print ?
  1. //【0】定义一些局部变量
  2. double alphaValue = 0.5;
  3. double betaValue;
  4. Mat srcImage2, srcImage3, dstImage;

在这里我们设置alpha值为0.5。

<1>读取两幅图像并作错误处理

这步很简单,直接上代码:

[cpp]  view plain copy print ?
  1. //读取图像 ( 两幅图片需为同样的类型和尺寸 )
  2. srcImage2= imread("mogu.jpg");
  3. srcImage3= imread("rain.jpg");
  4. if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }
  5. if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }

在这里需要注意的是,因为我们是对 srcImage1和srcImage2求和,所以它们必须要有相同的尺寸(宽度和高度)和类型,不然多余的部分没有对应的“伴”,肯定会出问题。

<2> 进行图像混合加权操作

载入图像后,我们就可以来生成混合图像,也就是之前公式中的g(x)。为此目的,使用函数 addWeighted 可以很方便地实现,也就是因为 addWeighted 进行了如下计算:

这里的对应于addWeighted的第2个参数alpha

这里的对应于addWeighted的第4个参数beta

这里的对应于addWeighted的第5个参数,在上面代码中被我们设为0.0。

代码其实很简单,就是这样:

[cpp]  view plain copy print ?
  1. //【2】进行图像混合加权操作
  2. betaValue = ( 1.0 - alphaValue );
  3. addWeighted( srcImage2, alphaValue, srcImage3,betaValue, 0.0, dstImage);
  4. 其中beta值为1-alpha,gamma值为0。

<3>创建显示窗口,显示图像。

[cpp]  view plain copy print ?
  1. // 【3】创建并显示原图窗口
  2. namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);
  3. imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );
  4. namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);
  5. imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );

接着来看一下运行效果图,首先是原图:

然后是效果图:

三、综合示例

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

[cpp]  view plain copy print ?
  1. //---------------------------------【ROI_LinearBlending()】-------------------------------------
  2. // 函数名:ROI_LinearBlending()
  3. // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义
  4. //                     感兴趣区域ROI,实现自定义区域的线性混合
  5. //--------------------------------------------------------------------------------------------
  6. bool ROI_LinearBlending()
  7. {
  8. //【1】读取图像
  9. Mat srcImage4= imread("dota_pa.jpg",1);
  10. Mat logoImage= imread("dota_logo.jpg");
  11. if(!srcImage4.data ) { printf("你妹,读取srcImage4错误~! \n"); return false; }
  12. if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }
  13. //【2】定义一个Mat类型并给其设定ROI区域
  14. Mat imageROI;
  15. //方法一
  16. imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));
  17. //方法二
  18. //imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));
  19. //【3】将logo加到原图上
  20. addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);
  21. //【4】显示结果
  22. namedWindow("<4>区域线性图像混合示例窗口 by浅墨");
  23. imshow("<4>区域线性图像混合示例窗口 by浅墨",srcImage4);
  24. return true;
  25. }

从这篇文章开始,如果不出意外的话,为了方便大家分块各个击破学习,每讲一个部分,示例代码都将封装在一个函数中,免得大家像学习各种不是特别地道的OpenCV教程时一样,看到代码全放在main函数中,心都碎了。

好了,下面放出详细注释的本篇文章的全部示例源代码:

[cpp]  view plain copy print ?
  1. //-----------------------------------【程序说明】----------------------------------------------
  2. //  程序名称::【OpenCV入门教程之四】 ROI区域图像叠加&初级图像混合 全剖析   配套源码
  3. // VS2010版   OpenCV版本:2.4.8
  4. //     2014年3月10日 Create by 浅墨
  5. //    图片素材出处:dota2原画 dota2logo
  6. //     浅墨的微博:@浅墨_毛星云
  7. //------------------------------------------------------------------------------------------------
  8. //-----------------------------------【头文件包含部分】---------------------------------------
  9. //     描述:包含程序所依赖的头文件
  10. //----------------------------------------------------------------------------------------------
  11. #include <cv.h>
  12. #include <highgui.h>
  13. #include <iostream>
  14. //-----------------------------------【命名空间声明部分】---------------------------------------
  15. //     描述:包含程序所使用的命名空间
  16. //-----------------------------------------------------------------------------------------------
  17. using namespace cv;
  18. using namespace std;
  19. //-----------------------------------【全局函数声明部分】--------------------------------------
  20. //     描述:全局函数声明
  21. //-----------------------------------------------------------------------------------------------
  22. bool ROI_AddImage();
  23. bool LinearBlending();
  24. bool ROI_LinearBlending();
  25. //-----------------------------------【main( )函数】--------------------------------------------
  26. //     描述:控制台应用程序的入口函数,我们的程序从这里开始
  27. //-----------------------------------------------------------------------------------------------
  28. int main(  )
  29. {
  30. system("color 5E");
  31. if(ROI_AddImage()&& LinearBlending( )&&ROI_LinearBlending( ))
  32. {
  33. cout<<endl<<"嗯。好了,得出了你需要的图像~! : )";
  34. }
  35. waitKey(0);
  36. return 0;
  37. }
  38. //----------------------------------【ROI_AddImage( )函数】----------------------------------
  39. // 函数名:ROI_AddImage()
  40. //     描述:利用感兴趣区域ROI实现图像叠加
  41. //----------------------------------------------------------------------------------------------
  42. bool ROI_AddImage()
  43. {
  44. //【1】读入图像
  45. Mat srcImage1= imread("dota_pa.jpg");
  46. Mat logoImage= imread("dota_logo.jpg");
  47. if(!srcImage1.data ) { printf("你妹,读取srcImage1错误~! \n"); return false; }
  48. if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }
  49. //【2】定义一个Mat类型并给其设定ROI区域
  50. Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));
  51. //【3】加载掩模(必须是灰度图)
  52. Mat mask= imread("dota_logo.jpg",0);
  53. //【4】将掩膜拷贝到ROI
  54. logoImage.copyTo(imageROI,mask);
  55. //【5】显示结果
  56. namedWindow("<1>利用ROI实现图像叠加示例窗口");
  57. imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);
  58. return true;
  59. }
  60. //---------------------------------【LinearBlending()函数】-------------------------------------
  61. // 函数名:LinearBlending()
  62. // 描述:利用cv::addWeighted()函数实现图像线性混合
  63. //--------------------------------------------------------------------------------------------
  64. bool LinearBlending()
  65. {
  66. //【0】定义一些局部变量
  67. double alphaValue = 0.5;
  68. double betaValue;
  69. Mat srcImage2, srcImage3, dstImage;
  70. //【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
  71. srcImage2= imread("mogu.jpg");
  72. srcImage3= imread("rain.jpg");
  73. if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }
  74. if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }
  75. //【2】进行图像混合加权操作
  76. betaValue= ( 1.0 - alphaValue );
  77. addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);
  78. //【3】创建并显示原图窗口
  79. namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);
  80. imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );
  81. namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);
  82. imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );
  83. return true;
  84. }
  85. //---------------------------------【ROI_LinearBlending()】-------------------------------------
  86. // 函数名:ROI_LinearBlending()
  87. // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义
  88. //                     感兴趣区域ROI,实现自定义区域的线性混合
  89. //--------------------------------------------------------------------------------------------
  90. bool ROI_LinearBlending()
  91. {
  92. //【1】读取图像
  93. Mat srcImage4= imread("dota_pa.jpg",1);
  94. Mat logoImage= imread("dota_logo.jpg");
  95. if(!srcImage4.data ) { printf("你妹,读取srcImage4错误~! \n"); return false; }
  96. if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }
  97. //【2】定义一个Mat类型并给其设定ROI区域
  98. Mat imageROI;
  99. //方法一
  100. imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));
  101. //方法二
  102. //imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));
  103. //【3】将logo加到原图上
  104. addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);
  105. //【4】显示结果
  106. namedWindow("<4>区域线性图像混合示例窗口 by浅墨");
  107. imshow("<4>区域线性图像混合示例窗口 by浅墨",srcImage4);
  108. return true;
  109. }

最后看一下整体的运行效果图。

首先是经过背景颜色修改的console窗口:

然后依次是四张效果图:

嗯,本篇文章到这里就基本结束了,最后放出本篇文章配套示例程序的下载地址。

本篇文章的配套源代码请点击这里下载:

【浅墨OpenCV入门教程之四】配套源代码下载

OK,本节的内容大概就是这些,我们下篇文章见:)

本系列文章由@浅墨_毛星云 出品,转载请注明出处。

文章链接: http://blog.csdn.net/poem_qianmo/article/details/20911629

作者:毛星云(浅墨)    邮箱: happylifemxy@163.com

写作当前博文时配套使用的OpenCV版本: 2.4.8

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

PS:文章末尾提供了博文配套程序源代码的下载。

文章开头,依旧是先放一张截图:

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

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

ROI区域定义的两种方法

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

[cpp]  view plain copy print ?
  1. //定义一个Mat类型并给其设定ROI区域
  2. Mat imageROI;
  3. //方法一
  4. imageROI=image(Rect(500,250,logo.cols,logo.rows));

另一种定义ROI的方式是指定感兴趣行或列的范围(Range)。Range是指从起始索引到终止索引(不包括终止索引)的一连段连续序列。cv::Range可以用来定义Range。如果使用cv::Range来定义ROI,那么前例中定义ROI的代码可以重写为:

[cpp]  view plain copy print ?
  1. //方法二
  2. imageROI=srcImage3(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

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

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

[cpp]  view plain copy print ?
  1. //----------------------------------【ROI_AddImage( )函数】----------------------------------
  2. // 函数名:ROI_AddImage()
  3. //     描述:利用感兴趣区域ROI实现图像叠加
  4. //----------------------------------------------------------------------------------------------
  5. bool ROI_AddImage()
  6. {
  7. //【1】读入图像
  8. Mat srcImage1= imread("dota_pa.jpg");
  9. Mat logoImage= imread("dota_logo.jpg");
  10. if(!srcImage1.data ) { printf("你妹,读取srcImage1错误~! \n"); return false; }
  11. if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }
  12. //【2】定义一个Mat类型并给其设定ROI区域
  13. Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));
  14. //【3】加载掩模(必须是灰度图)
  15. Mat mask= imread("dota_logo.jpg",0);
  16. //【4】将掩膜拷贝到ROI
  17. logoImage.copyTo(imageROI,mask);
  18. //【5】显示结果
  19. namedWindow("<1>利用ROI实现图像叠加示例窗口");
  20. imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);
  21. return true;
  22. }

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

运行结果如下:

这里白色的dota2 logo,就是通过操作之后加上去的图像。

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

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

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

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

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

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

addWeighted函数

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

[cpp]  view plain copy print ?
  1. void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);
  • 第一个参数,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时,这个函数就不适用了,这时候就会内存溢出或者算出的结果压根不对。

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

[cpp]  view plain copy print ?
  1. //---------------------------------【LinearBlending()函数】-------------------------------------
  2. // 函数名:LinearBlending()
  3. // 描述:利用cv::addWeighted()函数实现图像线性混合
  4. //--------------------------------------------------------------------------------------------
  5. bool LinearBlending()
  6. {
  7. //【0】定义一些局部变量
  8. double alphaValue = 0.5;
  9. double betaValue;
  10. Mat srcImage2, srcImage3, dstImage;
  11. //【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
  12. srcImage2= imread("mogu.jpg");
  13. srcImage3= imread("rain.jpg");
  14. if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }
  15. if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }
  16. //【2】做图像混合加权操作
  17. betaValue= ( 1.0 - alphaValue );
  18. addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);
  19. //【3】创建并显示原图窗口
  20. namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);
  21. imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );
  22. namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);
  23. imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );
  24. return true;
  25. }

代码解析:

<0>首先当然是定义一些局部变量,alpha值beta值,三个Mat类型的变量。

[cpp]  view plain copy print ?
  1. //【0】定义一些局部变量
  2. double alphaValue = 0.5;
  3. double betaValue;
  4. Mat srcImage2, srcImage3, dstImage;

在这里我们设置alpha值为0.5。

<1>读取两幅图像并作错误处理

这步很简单,直接上代码:

[cpp]  view plain copy print ?
  1. //读取图像 ( 两幅图片需为同样的类型和尺寸 )
  2. srcImage2= imread("mogu.jpg");
  3. srcImage3= imread("rain.jpg");
  4. if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }
  5. if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }

在这里需要注意的是,因为我们是对 srcImage1和srcImage2求和,所以它们必须要有相同的尺寸(宽度和高度)和类型,不然多余的部分没有对应的“伴”,肯定会出问题。

<2> 进行图像混合加权操作

载入图像后,我们就可以来生成混合图像,也就是之前公式中的g(x)。为此目的,使用函数 addWeighted 可以很方便地实现,也就是因为 addWeighted 进行了如下计算:

这里的对应于addWeighted的第2个参数alpha

这里的对应于addWeighted的第4个参数beta

这里的对应于addWeighted的第5个参数,在上面代码中被我们设为0.0。

代码其实很简单,就是这样:

[cpp]  view plain copy print ?
  1. //【2】进行图像混合加权操作
  2. betaValue = ( 1.0 - alphaValue );
  3. addWeighted( srcImage2, alphaValue, srcImage3,betaValue, 0.0, dstImage);
  4. 其中beta值为1-alpha,gamma值为0。

<3>创建显示窗口,显示图像。

[cpp]  view plain copy print ?
  1. // 【3】创建并显示原图窗口
  2. namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);
  3. imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );
  4. namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);
  5. imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );

接着来看一下运行效果图,首先是原图:

然后是效果图:

三、综合示例

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

[cpp]  view plain copy print ?
  1. //---------------------------------【ROI_LinearBlending()】-------------------------------------
  2. // 函数名:ROI_LinearBlending()
  3. // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义
  4. //                     感兴趣区域ROI,实现自定义区域的线性混合
  5. //--------------------------------------------------------------------------------------------
  6. bool ROI_LinearBlending()
  7. {
  8. //【1】读取图像
  9. Mat srcImage4= imread("dota_pa.jpg",1);
  10. Mat logoImage= imread("dota_logo.jpg");
  11. if(!srcImage4.data ) { printf("你妹,读取srcImage4错误~! \n"); return false; }
  12. if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }
  13. //【2】定义一个Mat类型并给其设定ROI区域
  14. Mat imageROI;
  15. //方法一
  16. imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));
  17. //方法二
  18. //imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));
  19. //【3】将logo加到原图上
  20. addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);
  21. //【4】显示结果
  22. namedWindow("<4>区域线性图像混合示例窗口 by浅墨");
  23. imshow("<4>区域线性图像混合示例窗口 by浅墨",srcImage4);
  24. return true;
  25. }

从这篇文章开始,如果不出意外的话,为了方便大家分块各个击破学习,每讲一个部分,示例代码都将封装在一个函数中,免得大家像学习各种不是特别地道的OpenCV教程时一样,看到代码全放在main函数中,心都碎了。

好了,下面放出详细注释的本篇文章的全部示例源代码:

[cpp]  view plain copy print ?
  1. //-----------------------------------【程序说明】----------------------------------------------
  2. //  程序名称::【OpenCV入门教程之四】 ROI区域图像叠加&初级图像混合 全剖析   配套源码
  3. // VS2010版   OpenCV版本:2.4.8
  4. //     2014年3月10日 Create by 浅墨
  5. //    图片素材出处:dota2原画 dota2logo
  6. //     浅墨的微博:@浅墨_毛星云
  7. //------------------------------------------------------------------------------------------------
  8. //-----------------------------------【头文件包含部分】---------------------------------------
  9. //     描述:包含程序所依赖的头文件
  10. //----------------------------------------------------------------------------------------------
  11. #include <cv.h>
  12. #include <highgui.h>
  13. #include <iostream>
  14. //-----------------------------------【命名空间声明部分】---------------------------------------
  15. //     描述:包含程序所使用的命名空间
  16. //-----------------------------------------------------------------------------------------------
  17. using namespace cv;
  18. using namespace std;
  19. //-----------------------------------【全局函数声明部分】--------------------------------------
  20. //     描述:全局函数声明
  21. //-----------------------------------------------------------------------------------------------
  22. bool ROI_AddImage();
  23. bool LinearBlending();
  24. bool ROI_LinearBlending();
  25. //-----------------------------------【main( )函数】--------------------------------------------
  26. //     描述:控制台应用程序的入口函数,我们的程序从这里开始
  27. //-----------------------------------------------------------------------------------------------
  28. int main(  )
  29. {
  30. system("color 5E");
  31. if(ROI_AddImage()&& LinearBlending( )&&ROI_LinearBlending( ))
  32. {
  33. cout<<endl<<"嗯。好了,得出了你需要的图像~! : )";
  34. }
  35. waitKey(0);
  36. return 0;
  37. }
  38. //----------------------------------【ROI_AddImage( )函数】----------------------------------
  39. // 函数名:ROI_AddImage()
  40. //     描述:利用感兴趣区域ROI实现图像叠加
  41. //----------------------------------------------------------------------------------------------
  42. bool ROI_AddImage()
  43. {
  44. //【1】读入图像
  45. Mat srcImage1= imread("dota_pa.jpg");
  46. Mat logoImage= imread("dota_logo.jpg");
  47. if(!srcImage1.data ) { printf("你妹,读取srcImage1错误~! \n"); return false; }
  48. if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }
  49. //【2】定义一个Mat类型并给其设定ROI区域
  50. Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));
  51. //【3】加载掩模(必须是灰度图)
  52. Mat mask= imread("dota_logo.jpg",0);
  53. //【4】将掩膜拷贝到ROI
  54. logoImage.copyTo(imageROI,mask);
  55. //【5】显示结果
  56. namedWindow("<1>利用ROI实现图像叠加示例窗口");
  57. imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);
  58. return true;
  59. }
  60. //---------------------------------【LinearBlending()函数】-------------------------------------
  61. // 函数名:LinearBlending()
  62. // 描述:利用cv::addWeighted()函数实现图像线性混合
  63. //--------------------------------------------------------------------------------------------
  64. bool LinearBlending()
  65. {
  66. //【0】定义一些局部变量
  67. double alphaValue = 0.5;
  68. double betaValue;
  69. Mat srcImage2, srcImage3, dstImage;
  70. //【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
  71. srcImage2= imread("mogu.jpg");
  72. srcImage3= imread("rain.jpg");
  73. if(!srcImage2.data ) { printf("你妹,读取srcImage2错误~! \n"); return false; }
  74. if(!srcImage3.data ) { printf("你妹,读取srcImage3错误~! \n"); return false; }
  75. //【2】进行图像混合加权操作
  76. betaValue= ( 1.0 - alphaValue );
  77. addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);
  78. //【3】创建并显示原图窗口
  79. namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);
  80. imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2 );
  81. namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);
  82. imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage );
  83. return true;
  84. }
  85. //---------------------------------【ROI_LinearBlending()】-------------------------------------
  86. // 函数名:ROI_LinearBlending()
  87. // 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义
  88. //                     感兴趣区域ROI,实现自定义区域的线性混合
  89. //--------------------------------------------------------------------------------------------
  90. bool ROI_LinearBlending()
  91. {
  92. //【1】读取图像
  93. Mat srcImage4= imread("dota_pa.jpg",1);
  94. Mat logoImage= imread("dota_logo.jpg");
  95. if(!srcImage4.data ) { printf("你妹,读取srcImage4错误~! \n"); return false; }
  96. if(!logoImage.data ) { printf("你妹,读取logoImage错误~! \n"); return false; }
  97. //【2】定义一个Mat类型并给其设定ROI区域
  98. Mat imageROI;
  99. //方法一
  100. imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));
  101. //方法二
  102. //imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));
  103. //【3】将logo加到原图上
  104. addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);
  105. //【4】显示结果
  106. namedWindow("<4>区域线性图像混合示例窗口 by浅墨");
  107. imshow("<4>区域线性图像混合示例窗口 by浅墨",srcImage4);
  108. return true;
  109. }

最后看一下整体的运行效果图。

首先是经过背景颜色修改的console窗口:

然后依次是四张效果图:

嗯,本篇文章到这里就基本结束了,最后放出本篇文章配套示例程序的下载地址。

本篇文章的配套源代码请点击这里下载:

【浅墨OpenCV入门教程之四】配套源代码下载

OK,本节的内容大概就是这些,我们下篇文章见:)

ROI区域图像叠加和初级图像教程相关推荐

  1. 【计算机视觉】EmguCV学习笔记(3)ROI区域图像叠加以及初级图像混合

    如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习. If you like the content here, you can give me the greates ...

  2. python opencv 图像叠加,python opencv图像叠加/图像融合/mask掩模

    目录python 一.图像叠加 能够经过OpenCV函数cv.add()或简单地经过numpy操做添加两个图像,res = img1 + img2.两个图像应该具备相同的深度和类型,或者第二个图像能够 ...

  3. [Python从零到壹] 三十七.图像处理基础篇之图像融合处理和ROI区域绘制

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

  4. python opencv图像叠加/图像融合/mask掩模

    目录 1.图像叠加 2.图像融合 3.图像mask掩模(包括按位AND,OR,NOT和XOR运算) 1.图像叠加 可以通过OpenCV函数cv.add()或简单地通过numpy操作添加两个图像,res ...

  5. opencv 手选roi区域_【OpenCV】选择ROI区域

    问题描述:在测试目标跟踪算法时,需要选择不同区域作为目标,进行目标跟踪,测试目标跟踪的效果. 解决思路: 1.OpenCV中提供了鼠标交互控制,利用setMouseCallback()给固定的窗口设置 ...

  6. 转载:【OpenCV入门教程之四】 ROI区域图像叠加初级图像混合 全剖析

    [OpenCV入门教程之四] ROI区域图像叠加&初级图像混合 全剖析 浅墨_毛星云 2014-03-10 12:48:05 157425 收藏 19 最后发布:2014-03-10 12:4 ...

  7. 《OpenCV3编程入门》学习笔记5 Core组件进阶(二) ROI区域图像叠加图像混合

    第5章 Core组件进阶 5.2 ROI区域图像叠加&图像混合 5.2.1 感兴趣区域ROI(region of interest) 1.定义ROI区域两种方法: (1)定义矩形区域Rect: ...

  8. 【opencv学习笔记】第五篇:访问图像中像素的三种方式、ROI区域图像叠加和图像混合

    1. 访问图像中像素的三种方式 任何图像处理算法,都是从操作每个像素开始的.在OpenCV中,提供了三种访问每个像素的方法. 方法1:指针访问:C操作符[] 方法2:迭代器iterator 方法3:动 ...

  9. (OpenCV — 7)ROI 区域图像叠加&图像混合

    1 感兴趣区域: ROI 在图像处理领域,我们常常需要设置感兴趣区域 ( ROI. region of interest) ,来专注或者简化工作过程 . 也就是从图像中选择的一个图像区域,这个区域是图 ...

最新文章

  1. 调和油、色拉油、花生油哪种吃着好
  2. Postman请求linux服务器报错:503Forwarding failure,由于服务器端口未开放;服务器端口开放与关闭
  3. Google News 中文上线
  4. python 修改文件名_【学习分享】利用python批量修改文件名
  5. sql substr切割字符串
  6. mongodb 部署
  7. 对象在内存中的存储布局
  8. ajax异步加载和cmd,异步传输Ajax(JQ)
  9. 七彩影视双端新版本源码
  10. ArrayList 与linkedlist区别
  11. “上云”很 fashion 的今天,GeekPwn 搞了个比赛……
  12. SQL进阶六:字符串函数
  13. 3分钟tips:泛函中,什么是开映像定理?
  14. Diamond programmer程序下载流程
  15. mysql环境变量配置还是不行_为什么要配置mysql环境变量
  16. ios中常用英语单词汇总
  17. 癌症最新研究进展(2021年10月)
  18. 小红书流量高峰时间段是什么时候?早上发笔记好还是晚上好
  19. win10打印机安装提示无法连接到打印机
  20. 与SCI主编邮件沟通模板

热门文章

  1. Android 第十二天重置版_版本控制
  2. Mac 之 Command Line Tools
  3. java防盗链_javaWeb防止恶意登陆或防盗链的使用
  4. 传统瀑布模型和实际瀑布模型
  5. Element-UI在safari浏览器下table列表无法对齐的问题
  6. 【Linux】下固定USB串口设备号(防止设备重复挂载、保证对外接设备信息稳定读取)
  7. 真彩色图像,索引色图像,灰度图像, 二值图像之间的相互变换(Matlab实现)
  8. python通过键盘方向键移动_Python 实现键盘操作之Crtl+方向键
  9. 动画幻灯片_动画片段幻灯片
  10. 2022最新VMware虚拟机下载·Linux系统装配·镜像文件下载·联网使用一条龙--------希望可以帮到你们