学习 opencv---(3) ROI 区域图像叠加&初级图像混合

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

 

    

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

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

      

   

         ROI区域定义的两种方法

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

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

    

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

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

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

 

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

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

 1 /*------------------------------------------------------
 2      函数名:ROI_AddImage()
 3      描述: 利用感兴趣区域ROI实现图像叠加(把图像叠加到ROI区域中,而不是俩张图的直接叠加)
 4 -------------------------------------------------------*/
 5 
 6 #include <opencv2/core/core.hpp>
 7 #include <opencv2/highgui/highgui.hpp>
 8 
 9 using namespace cv;
10 
11 bool ROI_AddImage()
12 {
13     
14     //【1】读入图像
15     Mat srcImage1 = imread("dota_pa.jpg");
16     Mat logoImage = imread("dota_logo.jpg");
17     
18     if (!srcImage1.data)
19     {
20         printf("fuck, read the picture is wrong!!! \n");
21         return false;
22     }
23 
24     if (!logoImage.data)
25     {
26         printf("fuck, read the picture is wrong!!! \n");
27         return false;
28     }
29 
30     //【2】定义一个Mat类型并给其设定ROI区域
31     Mat imageROI = srcImage1(Rect(200,250,logoImage.cols ,logoImage.rows));
32 
33     //【3】加载掩膜
34     Mat mask = imread("dota_logo.jpg",0);
35 
36     //【4】将掩膜拷贝到ROI
37     logoImage.copyTo(imageROI,mask);
38 
39     //【5】显示结果
40     namedWindow("1 利用ROI实现图像叠加示例窗口");
41     imshow("1 利用ROI实现图像叠加示例窗口",srcImage1);
42 
43     return true;
44 }

 

     这个函数首先是载入了两张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函数

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

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时,这个函数就不适用了,这时候就会内存溢出或者算出的结果压根不对。

  

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

 1 bool LinerBlending()
 2 {
 3     //【0】定义一些局部变量
 4     double alphaValue = 0.5;     //这些值感觉不懂
 5     double betaValue;
 6     Mat srcImage2, srcImage3, dstImage;
 7 
 8     //【1】读取图像(两幅图需为同样的类型和尺寸)
 9     srcImage2 = imread("mogu.jpg");
10     srcImage3 = imread("rain.jpg");
11 
12     if (!srcImage2.data)
13     {
14         printf("你妹,读取srcImage2错误!!!  \n"); 
15         return false;
16     }
17     if (!srcImage3.data)
18     {
19         printf("你妹,读取srcImage3错误!!!  \n");
20         return false;
21     }
22 
23 
24     //【2】做图像混合加权操作
25     betaValue = (1.0 - alphaValue );
26     addWeighted(srcImage2,alphaValue ,srcImage3 ,betaValue, 0.0,dstImage );
27 
28     //【3】创建并显示原图窗口
29     namedWindow("2 线性混合示例窗口【原图】 by hehhe",1);
30     imshow("2 线性混合示例窗口【原图】 by hehhe", srcImage2);
31 
32     //【4】创建并显示效果图窗口
33     namedWindow("3 线性混合示例窗口【效果图】 by hehhe", 1);
34     imshow("3 线性混合示例窗口【效果图】 by hehhe",dstImage);
35 
36     return true;
37 
38 }

 

 

 

       

      

            三、综合示例

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

    

  1 #include <opencv2/core/core.hpp>
  2 #include <opencv2/highgui/highgui.hpp>
  3 #include <iostream>
  4 
  5 using namespace cv;
  6 using namespace std;
  7 
  8 bool ROI_AddImage();
  9 bool LinerBlending();
 10 bool ROI_LinerBlending();
 11 
 12 
 13 
 14 /*--------------------------------------------------------------------------------------------------
 15  【1】    函数名:ROI_AddImage()
 16           描述: 利用感兴趣区域ROI实现图像叠加(把图像叠加到ROI区域中,而不是俩张图的直接叠加)
 17 ----------------------------------------------------------------------------------------------------*/
 18 
 19 
 20 bool ROI_AddImage()
 21 {
 22     
 23     //【1】读入图像
 24     Mat srcImage1 = imread("dota_pa.jpg");
 25     Mat logoImage = imread("dota_logo.jpg");
 26     
 27     if (!srcImage1.data)
 28     {
 29         printf("fuck, read the picture is wrong!!! \n");
 30         return false;
 31     }
 32 
 33     if (!logoImage.data)
 34     {
 35         printf("fuck, read the picture is wrong!!! \n");
 36         return false;
 37     }
 38 
 39     //【2】定义一个Mat类型并给其设定ROI区域
 40     Mat imageROI = srcImage1(Rect(200,250,logoImage.cols ,logoImage.rows));
 41 
 42     //【3】加载掩膜
 43     Mat mask = imread("dota_logo.jpg",0);
 44 
 45     //【4】将掩膜拷贝到ROI
 46     logoImage.copyTo(imageROI,mask);
 47 
 48     //【5】显示结果
 49     namedWindow("1 利用ROI实现图像叠加示例窗口");
 50     imshow("1 利用ROI实现图像叠加示例窗口",srcImage1);
 51 
 52     //waitKey();
 53 
 54     return true;
 55 }
 56 
 57 
 58 
 59 /*----------------------------------------------------
 60    【2】  函数名:LinerBlending
 61           描述:利用cv::addWeighted() 函数实现图像线性混合
 62 -------------------------------------------------------*/
 63 
 64 bool LinerBlending()
 65 {
 66     //【0】定义一些局部变量
 67     double alphaValue = 0.5;     //这些值感觉不懂
 68     double betaValue;
 69     Mat srcImage2, srcImage3, dstImage;
 70 
 71     //【1】读取图像(两幅图需为同样的类型和尺寸)
 72     srcImage2 = imread("mogu.jpg");
 73     srcImage3 = imread("rain.jpg");
 74 
 75     if (!srcImage2.data)
 76     {
 77         printf("你妹,读取srcImage2错误!!!  \n"); 
 78         return false;
 79     }
 80     if (!srcImage3.data)
 81     {
 82         printf("你妹,读取srcImage3错误!!!  \n");
 83         return false;
 84     }
 85 
 86 
 87     //【2】做图像混合加权操作
 88     betaValue = (1.0 - alphaValue );
 89     addWeighted(srcImage2,alphaValue ,srcImage3 ,betaValue, 0.0,dstImage );
 90 
 91     //【3】创建并显示原图窗口
 92     namedWindow("2 线性混合示例窗口【原图】 by hehhe",1);
 93     imshow("2 线性混合示例窗口【原图】 by hehhe", srcImage2);
 94 
 95     //【4】创建并显示效果图窗口
 96     namedWindow("3 线性混合示例窗口【效果图】 by hehhe", 1);
 97     imshow("3 线性混合示例窗口【效果图】 by hehhe",dstImage);
 98 
 99     //waitKey();
100 
101     return true;
102 
103 }
104 
105 
106 
107 
108 /*---------------------------------------------------------------------------------------------
109    【3】  函数名:ROI_LinerBlending
110           描述: 线性混合实现函数,指定区域线性图像混合,利用cv::addWeighted ()结合定义
111                  感兴趣区域ROI,实现自定义区域的线性混合
112 -----------------------------------------------------------------------------------------------*/
113 bool ROI_LinerBlending()
114 {
115     //【1】读取图像
116     Mat srcImage4 = imread("dota_pa.jpg",1);
117     Mat logoImage = imread("dota_logo.jpg");
118 
119     if (!srcImage4.data)
120     {
121         printf("你妹,读取srcImage4错误!!!  \n");
122         return false;
123     }
124     if (!logoImage.data)
125     {
126         printf("你妹,读取srcImage错误!!!  \n");
127         return false;
128     }
129 
130 
131     //【2】定义一个Mat类型并给其设定ROI区域
132     Mat imageROI;
133     imageROI = srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));
134 
135     //【3】将logo 加到原图上
136     addWeighted(imageROI,0.5,logoImage,0.3,0,imageROI);
137 
138     //【4】显示结果
139     namedWindow("4 区域线性图像混合示例窗口 by hehheh");
140     imshow("4 区域线性图像混合示例窗口 by hehheh",srcImage4);
141 
142     return true;
143 
144 }
145 
146 
147 /*------------------------------------------------------
148   【4】  main函数
149          描述:控制台程序的入口函数,我们的程序从这里开始
150 ----------------------------------------------------------*/
151 
152 int main()
153 {
154     system("color 10");   //控制cmd 窗口的背景颜色
155 
156     if (ROI_AddImage() && LinerBlending() && ROI_LinerBlending())
157     {
158         cout << "嗯,好了,得出了想要的图像" << endl;
159     }
160 
161     waitKey();
162     return 0;
163 }

 

 

 

 

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

 

转载于:https://www.cnblogs.com/wyuzl/p/6209143.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值