0
点赞
收藏
分享

微信扫一扫

图像处理之图像融合

1 概述

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

2 感兴趣区域: ROI

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

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

其中, image为已经载入好的图片。

//定义一个Mat类型并给其设定ROI区域Mat imageROI;

Mat imageROI;
方法1
imageROI = image (Rect (500,250, logo.cols, logo.rows)):

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

//方法二
imageROI=image (Range (250, 250+1ogoImage.rows), Range (200, 200+1ogoImage .cols));

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

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

//----------------------------------【ROI_AddImage( )函数】----------------------------------

// 函数名:ROI_AddImage()

// 描述:利用感兴趣区域ROI实现图像叠加

//------------------------------------------------------------------------------------------

bool  ROI_AddImage()
{

// 【1】读入图像
Mat srcImage1= imread("dota_pa.jpg");
Mat logoImage= imread("dota_logo.jpg");
if( !srcImage1.data ) { printf("读取srcImage1错误~! \n"); return false; }
if( !logoImage.data ) { printf("读取logoImage错误~! \n"); return false; }

// 【2】定义一个Mat类型并给其设定ROI区域
Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));

// 【3】加载掩模(必须是灰度图)
Mat mask= imread("dota_logo.jpg",0);

//【4】将掩膜拷贝到ROI
logoImage.copyTo(imageROI,mask);

// 【5】显示结果
namedWindow("<1>利用ROI实现图像叠加示例窗口");
imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);

return true;
}

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

图像处理之图像融合_图像融合

运行结果如上图所示。中白色的dota2 logo,就是通过操作之后加上去的图像。

3 线性混合操作

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

图像处理之图像融合_图像融合_02

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

实现方面,主要运用了OpenCV中addWeighted函数。这个函数的作用是计算两个数组(图像阵列)的加权和。原型如下:

void (InputArray srcl, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1);

  • 第一个参数, InputArray类型的srcl,表示需要加权的第一个数组,常常填一个Mat;
  • 第二个参数, double类型的alpha,表示第一个数组的权重;
  • 第三个参数, InputArray类型的src2,表示第二个数组,它需要和第一个数组拥有相同的尺寸和通道数:
  • 第四个参数, double类型的beta,表示第二个数组的权重值:
  • 第五个参数, double类型的gamma,一个加到权重总和上的标量值。其含义通过接下来列出的式子自然会理解;
  • 第六个参数, OutputArray类型的dst,输出的数组,它和输入的两个数组拥有相同的尺寸和通道数;
  • 第七个参数, int类型的dtype,输出阵列的可选深度,有默认值—1。当两个输入数组具有相同的深度时,这个参数设置为—1 (默认值),即等同于srcl.depth()。

下面的数学公式表示:用addWeighted函数计算以下两个数组(src1和sre2)的加权和,得到结果输出给第四个参数,也就是addWeighted函数的作用的矩阵表达式。

图像处理之图像融合_图像融合_03

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

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

//---------------------------------【LinearBlending()函数】-----------------------------------

// 函数名:LinearBlending()

// 描述:利用cv::addWeighted()函数实现图像线性混合

//--------------------------------------------------------------------------------------------

bool  LinearBlending()
{
//【0】定义一些局部变量
double alphaValue = 0.5;
double betaValue;
Mat srcImage2, srcImage3, dstImage;

// 【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
srcImage2 = imread("mogu.jpg");
srcImage3 = imread("rain.jpg");

if( !srcImage2.data ) { printf("读取srcImage2错误! \n"); return false; }
if( !srcImage3.data ) { printf("读取srcImage3错误! \n"); return false; }

// 【2】进行图像混合加权操作
betaValue = ( 1.0 - alphaValue );
addWeighted( srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);

// 【3】显示原图窗口
imshow( "<2>线性混合示例窗口【原图】", srcImage2 );
imshow( "<3>线性混合示例窗口【效果图】", dstImage );

return true;

}

下面对以上代码进行解析。

(0)首先当然是定义一些局部变量、alpha值、beta值,以及三个Mat类型的变量

//【0】定义一些局部变量

double alphaValue = 0.5; 
double betaValue;
Mat srcImage2, srcImage3, dstImage;

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

(1)读取两幅图像并作错误处理这步很简单,直接看代码。

//读取图像(两幅图片需为同样的类型和尺寸)

srcImage2= imread (“mogu.jpg”);
srcImage3= imread ("rain.jpg");
if(!srcImage2.data) {printf (“读取srcImage2 错误~! In”): return false; }
if(!srcImage3.data) { printf (“读取 srcImage3 错误~! In”); return false; }

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

(2)进行图像混合加权操作

载入图像后,我们就可以来生成混合图像,也就是之前公式中的g(x)。为此目的,使用函数addWeighted可以很方便地实现。代码其实很简单,就是这样:

//【2】进行图像混合加权操作

betavalue = ( 1.0 - alphaValue ):
addWeighted ( srcImage2, alphaValue, srcImage3, betaValue, 0.0. dstImage);

其中对应于addweighted的参数中的beta值为1—alpha, gamma值为0。

(3)创建显示窗口,显示图像

//【3】创建并显示原图窗口

namedwindow ("<2>线性混合示例窗口【原图】", 1); 
imshow ("<2>线性混合示例窗口【原图】", srcImage2 );
namedWindow (“<3>线性混合示例窗口【效果图】”, 1);
imshow (“<3>线性混合示例窗口【效果图】 ”, dst Image );

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

图像处理之图像融合_图像融合_04

然后是效果图。

图像处理之图像融合_图像融合_05

举报

相关推荐

0 条评论