zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    PHP保留小数的相关方法
    ASP.NET Core MVC 之过滤器(Filter)
    ASP.NET Core MVC 之控制器(Controller)
    ASP.NET Core MVC 之视图组件(View Component)
    ASP.NET Core MVC 之局部视图(Partial Views)
    标签助手(TagHelper)
    ASP.NET Core MVC 之布局(Layout)
    ASP.NET Core MVC 之视图(Views)
    ASP.NET Core MVC 之模型(Model)
    九卷读书:淘宝从小到大的发展 -重读《淘宝技术这十年》
  • 原文地址:https://www.cnblogs.com/Long-w/p/9663140.html
Copyright © 2011-2022 走看看