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 }
  • 相关阅读:
    关于xcode中证书安装问题
    iOSOpenDev 安装流程
    openCV
    POJ2081(Recaman's Sequence)
    POJ1163(The Triangle)
    POJ3620(Avoid The Lakes)
    POJ1160(Post Office)
    POJ3177(Redundant Paths) or POJ3352(Road Construction)
    POJ1953(World Cup Noise)
    POJ1904(King's Quest)
  • 原文地址:https://www.cnblogs.com/Long-w/p/9663140.html
Copyright © 2011-2022 走看看