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

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

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

ROI区域定义的两种方法

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

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

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

cv::Range 可以用来定义Range .如果使用cv::Range 定义ROI ,那么前列定义ROI 的代码可以重写为:

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

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

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

 /*------------------------------------------------------
函数名:ROI_AddImage()
描述: 利用感兴趣区域ROI实现图像叠加(把图像叠加到ROI区域中,而不是俩张图的直接叠加)
-------------------------------------------------------*/ #include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp> using namespace cv; bool ROI_AddImage()
{ //【1】读入图像
Mat srcImage1 = imread("dota_pa.jpg");
Mat logoImage = imread("dota_logo.jpg"); if (!srcImage1.data)
{
printf("fuck, read the picture is wrong!!! \n");
return false;
} if (!logoImage.data)
{
printf("fuck, read the picture is wrong!!! \n");
return false;
} //【2】定义一个Mat类型并给其设定ROI区域
Mat imageROI = srcImage1(Rect(,,logoImage.cols ,logoImage.rows)); //【3】加载掩膜
Mat mask = imread("dota_logo.jpg",); //【4】将掩膜拷贝到ROI
logoImage.copyTo(imageROI,mask); //【5】显示结果
namedWindow("1 利用ROI实现图像叠加示例窗口");
imshow("1 利用ROI实现图像叠加示例窗口",srcImage1); return true;
}

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

二、初级图像混合——线性混合操作

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

如果看过我之前写的游戏编程Alpha混合那篇文章的朋友们应该有些熟悉,其实他们是差不多的:

【Visual C++】游戏开发五十五浅墨 DirectX教程二十二水乳交融的美学:alpha混合技术

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

实现方面,我们主要用了Opencv中AddWeighted函数,我们来全面的了解一下它:

addWeighted函数

这个函数的作用是,计算俩个数组(图像阵列)的加权和,原型如下:

 void addweighted (InputArray src1 ,double alpha, InputArray src2 ,double beta, double gamma, OutputArray dst ,int dtype = -);
  • 第一个参数,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时,这个函数就不适用了,这时候就会内存溢出或者算出的结果压根不对。

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

 bool LinerBlending()
{
//【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】创建并显示原图窗口
namedWindow("2 线性混合示例窗口【原图】 by hehhe",);
imshow("2 线性混合示例窗口【原图】 by hehhe", srcImage2); //【4】创建并显示效果图窗口
namedWindow("3 线性混合示例窗口【效果图】 by hehhe", );
imshow("3 线性混合示例窗口【效果图】 by hehhe",dstImage); return true; }

三、综合示例

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

 #include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream> using namespace cv;
using namespace std; bool ROI_AddImage();
bool LinerBlending();
bool ROI_LinerBlending(); /*--------------------------------------------------------------------------------------------------
【1】 函数名:ROI_AddImage()
描述: 利用感兴趣区域ROI实现图像叠加(把图像叠加到ROI区域中,而不是俩张图的直接叠加)
----------------------------------------------------------------------------------------------------*/ bool ROI_AddImage()
{ //【1】读入图像
Mat srcImage1 = imread("dota_pa.jpg");
Mat logoImage = imread("dota_logo.jpg"); if (!srcImage1.data)
{
printf("fuck, read the picture is wrong!!! \n");
return false;
} if (!logoImage.data)
{
printf("fuck, read the picture is wrong!!! \n");
return false;
} //【2】定义一个Mat类型并给其设定ROI区域
Mat imageROI = srcImage1(Rect(,,logoImage.cols ,logoImage.rows)); //【3】加载掩膜
Mat mask = imread("dota_logo.jpg",); //【4】将掩膜拷贝到ROI
logoImage.copyTo(imageROI,mask); //【5】显示结果
namedWindow("1 利用ROI实现图像叠加示例窗口");
imshow("1 利用ROI实现图像叠加示例窗口",srcImage1); //waitKey(); return true;
} /*----------------------------------------------------
【2】 函数名:LinerBlending
描述:利用cv::addWeighted() 函数实现图像线性混合
-------------------------------------------------------*/ bool LinerBlending()
{
//【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】创建并显示原图窗口
namedWindow("2 线性混合示例窗口【原图】 by hehhe",);
imshow("2 线性混合示例窗口【原图】 by hehhe", srcImage2); //【4】创建并显示效果图窗口
namedWindow("3 线性混合示例窗口【效果图】 by hehhe", );
imshow("3 线性混合示例窗口【效果图】 by hehhe",dstImage); //waitKey(); return true; } /*---------------------------------------------------------------------------------------------
【3】 函数名:ROI_LinerBlending
描述: 线性混合实现函数,指定区域线性图像混合,利用cv::addWeighted ()结合定义
感兴趣区域ROI,实现自定义区域的线性混合
-----------------------------------------------------------------------------------------------*/
bool ROI_LinerBlending()
{
//【1】读取图像
Mat srcImage4 = imread("dota_pa.jpg",);
Mat logoImage = imread("dota_logo.jpg"); if (!srcImage4.data)
{
printf("你妹,读取srcImage4错误!!! \n");
return false;
}
if (!logoImage.data)
{
printf("你妹,读取srcImage错误!!! \n");
return false;
} //【2】定义一个Mat类型并给其设定ROI区域
Mat imageROI;
imageROI = srcImage4(Rect(,,logoImage.cols,logoImage.rows)); //【3】将logo 加到原图上
addWeighted(imageROI,0.5,logoImage,0.3,,imageROI); //【4】显示结果
namedWindow("4 区域线性图像混合示例窗口 by hehheh");
imshow("4 区域线性图像混合示例窗口 by hehheh",srcImage4); return true; } /*------------------------------------------------------
【4】 main函数
描述:控制台程序的入口函数,我们的程序从这里开始
----------------------------------------------------------*/ int main()
{
system("color 10"); //控制cmd 窗口的背景颜色 if (ROI_AddImage() && LinerBlending() && ROI_LinerBlending())
{
cout << "嗯,好了,得出了想要的图像" << endl;
} waitKey();
return ;
}

嗯,本篇文章到这里就基本结束了。。。。。。。。。。。。。。

学习 opencv---(3) ROI 区域图像叠加&初级图像混合的更多相关文章

  1. opencv——设置ROI区域

    #include "stdafx.h" #include<opencv2\opencv.hpp> #include<opencv\cv.h> #includ ...

  2. 【OpenCV】通过ROI区域以及掩码实现图像叠加

    在图像处理领域,我们常常需要设置感兴趣区域(ROI,region of interest),来专注或者简化我们的工作过程 .也就是从图像中选择的一个图像区域,这个区域是我们图像分析所关注的重点.我们圈 ...

  3. 【opencv学习笔记】SetImageROI函数设置ROI区域的作用及用法

    虽然先前知道ROI区域是感兴趣区域,但是真正看到调用了OpenCV的cvSetImageROI函数时,并不知道它的作用,所以还是单独写了一段代码对这个函数进行探究.   OpenCVchm文档中对cv ...

  4. Python 图像处理 OpenCV (3):图像属性、图像感兴趣 ROI 区域及通道处理

    前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 图像属性 图像 ...

  5. javacpp-opencv图像处理之2:实时视频添加图片水印,实现不同大小图片叠加,图像透明度控制,文字和图片双水印

    欢迎大家积极开心的加入讨论群 群号:371249677 (点击这里进群) javaCV图像处理系列: javaCV图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体.位置. ...

  6. 跟我学Python图像处理丨获取图像属性、兴趣ROI区域及通道处理

    摘要:本篇文章主要讲解Python调用OpenCV获取图像属性,截取感兴趣ROI区域,处理图像通道. 本文分享自华为云社区<[Python图像处理] 三.获取图像属性.兴趣ROI区域及通道处理 ...

  7. Python图像处理:如何获取图像属性、兴趣ROI区域及通道处理

    摘要:本篇文章主要讲解Python调用OpenCV获取图像属性,截取感兴趣ROI区域,处理图像通道. 本文分享自华为云社区<[Python图像处理] 三.获取图像属性.兴趣ROI区域及通道处理 ...

  8. 【opencv学习笔记六】图像的ROI区域选择与复制

    图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...

  9. opencv 3 core组件进阶(2 ROI区域图像叠加&图像混合;分离颜色通道、多通道图像混合;图像对比度,亮度值调整)

    ROI区域图像叠加&图像混合 #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp&g ...

随机推荐

  1. Spring AOP深入剖析

    一.通过代理工厂模式配置通知 ①.前置通知.后置通知: 定义某接口:ISomeService,并自定义方法 public interface ISomeService { public void tr ...

  2. AC日记——I Hate It 洛谷 P1531

    题目背景 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感. 题目描述 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的 ...

  3. 3.bootstrap练习笔记-媒体内容

    bootstrap练习笔记-多媒体对象 1.在bootstrap中,如果想存放内容,一种解决的方式就是利用media这个class 首先要设置一个div.container作为一个总的容器来存放内容 ...

  4. NPOI导出Excel合并表头写入公式

    protected void Btn1_Click(object sender, EventArgs e) { //建立空白工作簿 IWorkbook workbook = new HSSFWorkb ...

  5. StackExchange.Redis通用封装类分享(转)

    阅读目录 ConnectionMultiplexer 封装 RedisHelper 通用操作类封 String类型的封装 List类型的封装 Hash类型的封装 SortedSet 类型的封装 key ...

  6. 物联网平台设计心得:DateTimePicker实现选择联动

    所谓的选择联动,就是指,当我DateTimePicker1选择2月4号的时候,我DateTimePicker2只能选择2月4号和2月5号两天,当然你可以自行规定要选择的日期.这在一些图表查询条件里面是 ...

  7. npoi批量导入实现及相关技巧

    批量导入功能对于大部分后台系统来说都是不可或缺的一部分,常见的场景-基础数据的录入(部门,用户),用批量导入方便快捷.最近项目需要用到批量导入,决定花点时间写套比较通用的Excel导入功能.经过考虑, ...

  8. c#资料

    类型系统: 运行模型: 整型: 浮点: 财务: 布尔: 字符: 引用类型: Console控制字符: {序号,空间:控制字符与精度} 如:{0,3:C2} {空间:#.00} 其中,#表示该位置如果有 ...

  9. AsyncTask的初步了解

    下面以下载图片并显示为例: 首先我们需要知道的是AsyncTask是对线程池+Handler的进一步封装. 下面看一个简单的代码: public class MainActivity extends ...

  10. mac 常用地址

    1.hosts   配置文件地址 /private/etc/hosts 2.apache 配置文件地址 /etc/apache2/httpd.conf 3.Xcode 插件地址 ~/Library/A ...