OpenCV学习笔记(二)ROI区域图像叠加&初级图像混合

ROI图像感兴趣区域

ROI(region of interest):感兴趣区域
——也就是从图像中选择的一个图像区域,这个区域是我们图像分析所关注的重点。我们圈定这个区域,以便进行进一步处理。而且,使用ROI指定我们想读入的目标,可以减少处理时间,增加精度,给图像处理来带不小的便利。

ROI区域定义的两种方法

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

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

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

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

实例:利用感兴趣区域ROI实现图像叠加

/*
---------------------------2016.11.11【利用感兴趣区域ROI实现图像叠加】-----------------------------
----------------------------------------------------------------------------------------------
     描述:利用感兴趣区域ROI实现图像叠加
    这个函数首先是载入了两张jpg图片到srcImage1和logoImage中,
然后定义了一个Mat类型的imageROI,并使用cv::Rect设置其感兴趣区域为srcImage1中的一块区域,
将imageROI和srcImage1关联起来。
接着定义了一个Mat类型的mask并读入dota_logo.jpg,顺势使用Mat::copyTo把mask中的内容拷贝到imageROI中,
于是就得到了最终的效果图,namedWindow和imshow配合使用,显示出最终的结果。
*/
int main()
{
    //【1】读入图像
    Mat srcImage1 = imread("ss.jpg");
    Mat logoImage = imread("xiamu.jpg");
    if (!srcImage1.data) //or if(srcImage1.empty())
    { 
        printf("你妹,读取srcImage1错误~! \n"); 
        return 0;
    }
    if (!logoImage.data) 
    { 
        printf("你妹,读取logoImage错误~! \n"); 
        return 0;
    }

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

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

    //【4】将logoImage拷贝到imageROI
    //mask是操作掩码,他的非零元素表示矩阵中某个要被复制。
    logoImage.copyTo(imageROI, mask);
    //logoImage.copyTo(imageROI);

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

    waitKey();
    return 0;
}

线性混合

先介绍一下alpha混合技术

OpenCV学习笔记(二)ROI区域图像叠加&初级图像混合_第1张图片

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

addWeighted函数

作用:计算两个数组(图像阵列)的加权和。
原型如下:

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

//---------------------------------【LinearBlending()函数】-------------------------------------
// 函数名:LinearBlending()
// 描述:利用cv::addWeighted()函数实现图像线性混合
//--------------------------------------------------------------------------------------------
bool LinearBlending()
{
    //【0】定义一些局部变量
    double alphaValue = 0.5;
    double betaValue;
    Mat srcImage2, srcImage3, dstImage;

    //【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
    srcImage2 = imread("ss.jpg");
    srcImage3 = imread("lufei.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】创建并显示原图窗口
    namedWindow("<2>线性混合示例窗口【原图】 by浅墨", 1);
    imshow("<2>线性混合示例窗口【原图】 by浅墨", srcImage2);

    namedWindow("<3>线性混合示例窗口【效果图】 by浅墨", 1);
    imshow("<3>线性混合示例窗口【效果图】 by浅墨", dstImage);

    return true;

}

结果:
OpenCV学习笔记(二)ROI区域图像叠加&初级图像混合_第2张图片

综合实例

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

//---------------------------------【ROI_LinearBlending()】-------------------------------------
// 函数名:ROI_LinearBlending()
// 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义
//                     感兴趣区域ROI,实现自定义区域的线性混合
//--------------------------------------------------------------------------------------------
bool ROI_LinearBlending()
{

    //【1】读取图像
    Mat srcImage4 = imread("lufei.jpg", 1); //彩色3通道
    Mat logoImage = imread("xiamu.jpg");

    if (!srcImage4.data) { printf("你妹,读取srcImage4错误~! \n"); return false; }
    if (!logoImage.data) { printf("你妹,读取logoImage错误~! \n"); return false; }

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

    //【3】将logo加到原图上
    addWeighted(imageROI, 0.5, logoImage, 0.3, 0.0, imageROI);

    //【4】显示结果
    namedWindow("<4>区域线性图像混合示例窗口");
    imshow("<4>区域线性图像混合示例窗口", srcImage4);

    return true;
}

结果:与copyto函数实现的结果不同,这个加上去的logo是半透明的。
OpenCV学习笔记(二)ROI区域图像叠加&初级图像混合_第3张图片

参考:
本系列文章是学习下列文章的笔记。
@浅墨_毛星云 出品,转载请注明出处。
文章链接: http://blog.csdn.net/poem_qianmo/article/details/20537737
作者:毛星云(浅墨) 邮箱: [email protected]

你可能感兴趣的:(OpenCV)