11、【opencv入门】ROI区域 mask掩码 图像叠加&初级图像混合


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

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

ROI区域定义的两种方法

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

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的代码可以重写为:

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

二、mask掩码

1     mask(掩码或者掩膜):是一个8位单通道图像(灰度图像/二值图像) 2  掩码某个位置如果为0,则在此位置上的操作不起作用 3  掩码某个位置如果不为0,则在此位置上的操作会起作用。 4 可以用来提取不规则ROI

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

 1 // 描述:利用感兴趣区域ROI实现图像叠加  2 #include<iostream>  3 #include<opencv2/core/core.hpp>  4 #include<opencv2/highgui/highgui.hpp>  5  6 using namespace std;  7 using namespace cv;//OpenCV中的C++类和函数都是定义在命名空间cv之内的  8  9 int main() 10 { 11 //【1】读入图像 12 Mat srcImage1= imread("poster_dota.jpg"); 13 if(!srcImage1.data ) 14  { 15 cout << "读取错误!" << endl; 16 return false; 17  } 18 19 Mat logoImage= imread("poster_dota_logo.jpg"); 20 if(!logoImage.data ) 21  { 22 cout << "读取错误!" << endl; 23 return false; 24  } 25 26 //【2】定义一个Mat类型并给其设定ROI区域Rect()函数的前两个参数表示左上角的起始坐标,后两个参数表示长方向的长、宽 27 Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows)); 28 29 //【3】加载掩模(必须是灰度图) 30 Mat mask= imread("dota_logo.jpg",0); 31 32 //【4】将掩膜拷贝到ROI 33  logoImage.copyTo(imageROI,mask); 34 35 //【5】显示结果 36 namedWindow("<1>利用ROI实现图像叠加示例窗口"); 37 imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1); 38 39 waitKey(0);//等待按键触发 40 return true; 41 }

  首先是载入了两张jpg图片到srcImage1和logoImage中,然后定义了一个Mat类型的imageROI,并使用cv::Rect设置其感兴趣区域为srcImage1中的一块区域,将imageROI和srcImage1关联起来。

  接着定义了一个Mat类型的的mask并读入dota_logo.jpg,顺势使用Mat:: copyTo把mask中的内容拷贝到imageROI中,于是就得到了最终的效果图,namedWindow和imshow配合使用,显示出最终的结果。

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

三、初级图像混合 --- 线性混合

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

 

  我们通过在范围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);
1  第一个参数,InputArray类型的src1,表示需要加权的第一个数组,常常填一个Mat。 2  第二个参数,alpha,表示第一个数组的权重 3  第三个参数,src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数。 4  第四个参数,beta,表示第二个数组的权重值。 5  第五个参数,gamma,一个加到权重总和上的标量值。看下面的式子自然会理解。 6  第六个参数,dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数。 7 第七个参数,dtype,输出阵列的可选深度,有默认值-1。;当两个输入数组具有相同的深度时,这个参数设置为-1(默认值),即等同于src1.depth()。

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

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

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

【示例】

 1 //初级图像混合 --- 线性混合  2 #include<iostream>  3 #include<opencv2/core/core.hpp>  4 #include<opencv2/highgui/highgui.hpp>  5  6 using namespace std;  7 using namespace cv;//OpenCV中的C++类和函数都是定义在命名空间cv之内的  8  9 int main() 10 { 11 double alphaValue = 0.5; 12 double betaValue; 13 14  Mat srcImage2, srcImage3, dstImage; 15 16 //读取图像 17 srcImage2 = imread("1.jpg"); 18 if(!srcImage2.data) 19  { 20 cout << "读取错误!" << endl; 21 return false; 22  } 23 srcImage3 = imread("2.jpg"); 24 if(!srcImage3.data) 25  { 26 cout << "读取错误!" << endl; 27 return false; 28  } 29 30 //图像混合加权操作 31 betaValue = (1.0 - alphaValue); 32 addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage); 33 34 //创建窗口并显示原图 35 namedWindow("线性混合示例窗口【原图】", 1); 36 imshow("线性混合示例窗口【原图】",srcImage2); 37 38 //创建窗口并显示混合后的图像 39 namedWindow("线性混合示例窗口【效果图】", 1); 40 imshow("线性混合示例窗口【效果图】", dstImage); 41 42 waitKey(0);//等待按键输入 43 return true; 44 }

四、综合示例

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

 【示例】

  1 //综合示例 ROI区域图像叠加 图像线性混合  2 #include<iostream>  3 #include<opencv2/core/core.hpp>  4 #include<opencv2/highgui/highgui.hpp>  5  6 using namespace cv;  7 using namespace std;  8  9 //函数声明  10 bool ROI_AddImage();  11 bool LinearBlending();  12 bool ROI_LinearBlending();  13  14 int main()  15 {  16 system("color 5E");  17 if(ROI_AddImage() && LinearBlending() && ROI_LinearBlending())  18  {  19 cout<<endl<<"嗯。好了,得出了你需要的图像~! : )";  20  }  21  22 waitKey(0);  23 return 0;  24 }  25  26 //ROI图像叠加  27 bool ROI_AddImage()  28 {  29  30 //【1】读入图像  31 Mat srcImage1= imread("dota.jpg");  32 if(!srcImage1.data )  33  {  34 cout << "读取错误!" << endl;  35 return false;  36  }  37  38 Mat logoImage= imread("dota_logo.jpg");  39 if(!logoImage.data )  40  {  41 cout << "读取错误!" << endl;  42 return false;  43  }  44  45 //【2】方法一:定义一个Mat类型并给其设定ROI区域  46 Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));  47 //方法二:定义一个Mat类型并给其设定ROI区域  48 //Mat imageROI=srcImage1(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));  49  50 //【3】加载掩模(必须是灰度图)  51 Mat mask= imread("dota_logo.jpg",0);  52  53 //【4】将掩膜拷贝到ROI  54  logoImage.copyTo(imageROI,mask);  55  56 //【5】显示结果  57 namedWindow("<1>利用ROI实现图像叠加示例窗口");  58 imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);  59 //waitKey(0);//等待按键输入  60 return true;  61 }  62 //图像的线性混合  63 bool LinearBlending()  64 {  65    double alphaValue = 0.5;  66 double betaValue;  67  68  Mat srcImage2, srcImage3, dstImage;  69  70 //读取图像  71 srcImage2 = imread("1.jpg"); 72 if(!srcImage2.data) 73 { 74 cout << "读取错误!" << endl; 75 return false; 76 } 77 srcImage3 = imread("2.jpg"); 78 if(!srcImage3.data) 79 { 80 cout << "读取错误!" << endl; 81 return false; 82 } 83 84 //图像混合加权操作 85 betaValue = (1.0 - alphaValue); 86 addWeighted(srcImage2, alphaValue, srcImage3, betaValue, 1.0, dstImage); 87 88 //创建窗口并显示原图 89 namedWindow("线性混合示例窗口【原图】", 1); 90 imshow("线性混合示例窗口【原图】",srcImage2); 91 92 //创建窗口并显示混合后的图像 93 namedWindow("线性混合示例窗口【效果图】", 1); 94 imshow("线性混合示例窗口【效果图】", dstImage); 95 96 //waitKey(0);//等待按键输入 97 return true; 98 } 99 100 //指定区域的线性混合 101 bool ROI_LinearBlending() 102 { 103 //【1】读取图像 104 Mat srcImage4= imread("dota.jpg",1); 105 Mat logoImage= imread("dota_logo.jpg"); 106 107 if(!srcImage4.data ) 108 { 109 cout << "读取错误!" << endl; 110 return false; 111 } 112 if(!logoImage.data ) 113 { 114 cout << "读取错误!" << endl; 115 return false; 116 } 117 118 //【2】定义一个Mat类型并给其设定ROI区域 119 Mat imageROI; 120 //方法一 121 imageROI=srcImage4(Rect(200,250,logoImage.cols,logoImage.rows)); 122 //方法二 123 //imageROI=srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols)); 124 125 //【3】将logo加到原图上 126 addWeighted(imageROI,0.5,logoImage,0.3,0.0,imageROI); 127 128 //【4】显示结果 129 namedWindow("<4>ROI区域线性图像混合示例窗口 by浅墨"); 130 imshow("<4>ROI区域线性图像混合示例窗口 by浅墨",srcImage4); 131 //waitKey(0);//等待按键输入 132 return true; 133 }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM