本篇随笔主要介绍:如何使用OpenCV定义感兴趣区域ROI;如何使用addWeighted函数进行退选哪个混合操作;如何将ROI和addWeighted函数结合来使用,对指定区域图像混合操作。
Region of interest
定义ROI有两种方法:一是使用矩形区域(Rect),它指定了矩形的左上角坐标(构造函数前两个参数)和矩形的长宽(构造函数的后两个参数)。C/C++描述如下:
// 定义一个Mat类型并给其设定ROI区域
Mat imageROI;
// 方法1
imageROI=image(Rect(500,250,logo.cols,logo.rows));
另外一种定义ROI的方式是指定感兴趣的行或列的范围(Range)。代码可重写为:
// 方法二
imageROI=image(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));
其代码如下:
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;
}
ROI_AddImage
线性混合
线性混合是典型的二元的像素操作,其理论公式:g(x)=(1-a)fa(x)+af3(x)。可通过在范围0到1之间改变alpha值来对两幅图像(f0(x)和f1(x))或两段视频产生时间上的画面叠化(cross-dissolve)效果。
addWeighted()函数
这个函数作用是计算两个数组(图像)的加权和。原型如下:
void addWeighted(InputArray src1, double alpha, InputArray src2,
double beta, double gamma, OutputArray dst, int dtype = -1);
// 表达式:
dst=src1[I]*alpha+src2[I]*beta+gamma;
总的演示代码如下:
#pragma once
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
//----------------------------------【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;
}
//---------------------------------【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;
}
//---------------------------------【ROI_LinearBlending()】-------------------------------------
// 函数名:ROI_LinearBlending()
// 描述:线性混合实现函数,指定区域线性图像混合.利用cv::addWeighted()函数结合定义
// 感兴趣区域ROI,实现自定义区域的线性混合
//--------------------------------------------------------------------------------------------
bool ROI_LinearBlending()
{
//【1】读取图像
Mat srcImage4 = imread("dota_pa.jpg", 1);
Mat logoImage = imread("dota_logo.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., imageROI);
//【4】显示结果
imshow("<4>区域线性图像混合示例窗口", srcImage4);
return true;
}
ImageBending
#include "ImageBlending.h"
int main()
{
// system("color 6F");
int end = 0;
Mat srcImage1 = imread("dota_pa.jpg");
Mat logoImage = imread("dota_logo.jpg");
imshow("原图1", srcImage1);
imshow("原图2", logoImage);
if (ROI_AddImage() && LinearBlending() && ROI_LinearBlending())
{
cout << "运行成功,得出了需要的图像";
}
waitKey(end);
return 0;
}
main
运行结果如下(详见附录):
多通道图像混合与分离
上述的处理是单通道的图像叠加和混合,接下来将会展示多通道图像的分离和混合。为了更好地观察一些图像处理的特征,有时需要对RGB三个颜色通道的分量进行分别显示和调整。
【通道分离:split()函数】 split函数可将一个多通道数组分离成几个单通道数组。
C++ : void split(const Mat& src, Mat *mvbegin);
C++ : void split(InputArray m, OutputArrayOfArrays mv);
其公式:mvc=src(I)c。
//【2】把一个3通道图像转换成3个单通道图像
split(srcImage, channels);//分离色彩通道
//【3】将原图的蓝色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
imageBlueChannel = channels.at(0);
//【3】将原图的绿色通道的引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
imageGreenChannel = channels.at(1);
//【3】将原图的红色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
imageRedChannel = channels.at(2);
【通道合并:merge()函数】 该函数是split()函数的逆向操作——将多个数组合并成一个多通道的数组。
C++ : void merge(const Mat*mv, size_tcount, OutputArray dst)
C++ : void merg(InputArrayOfArrays mv, OutputArray dst)
总的演示代码如下:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
bool MultiChannelBlending();
int main()
{
// system("color 9F");
int key = 0;
if (MultiChannelBlending())
{
cout << "运行成功,得出了需要的图像!";
}
waitKey(key);
return 0;
}
//-----------------------------【MultiChannelBlending( )函数】--------------------------------
// 描述:多通道混合的实现函数
//-----------------------------------------------------------------------------------------------
bool MultiChannelBlending()
{
//【0】定义相关变量
Mat srcImage;
Mat logoImage;
vector<Mat> channels;
Mat imageBlueChannel;
//=================【蓝色通道部分】=================
// 描述:多通道混合-蓝色分量部分
//============================================
// 【1】读入图片
logoImage = imread("dota_logo.jpg", 0);
srcImage = imread("dota_jugg.jpg");
if (!logoImage.data) { printf("Oh,no,读取logoImage错误~! n"); return false; }
if (!srcImage.data) { printf("Oh,no,读取srcImage错误~! n"); return false; }
//【2】把一个3通道图像转换成3个单通道图像
split(srcImage, channels);//分离色彩通道
//【3】将原图的蓝色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
imageBlueChannel = channels.at(0);
//【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中
addWeighted(imageBlueChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0,
logoImage, 0.5, 0, imageBlueChannel(Rect(500, 250, logoImage.cols, logoImage.rows)));
//【5】将三个单通道重新合并成一个三通道
merge(channels, srcImage);
//【6】显示效果图
namedWindow(" <1>游戏原画+logo蓝色通道");
imshow(" <1>游戏原画+logo蓝色通道", srcImage);
//=================【绿色通道部分】=================
// 描述:多通道混合-绿色分量部分
//============================================
//【0】定义相关变量
Mat imageGreenChannel;
//【1】重新读入图片
logoImage = imread("dota_logo.jpg", 0);
srcImage = imread("dota_jugg.jpg");
if (!logoImage.data) { printf("读取logoImage错误~! n"); return false; }
if (!srcImage.data) { printf("读取srcImage错误~! n"); return false; }
//【2】将一个三通道图像转换成三个单通道图像
split(srcImage, channels);//分离色彩通道
//【3】将原图的绿色通道的引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
imageGreenChannel = channels.at(1);
//【4】将原图的绿色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageGreenChannel中
addWeighted(imageGreenChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0,
logoImage, 0.5, 0., imageGreenChannel(Rect(500, 250, logoImage.cols, logoImage.rows)));
//【5】将三个独立的单通道重新合并成一个三通道
merge(channels, srcImage);
//【6】显示效果图
namedWindow("<2>游戏原画+logo绿色通道");
imshow("<2>游戏原画+logo绿色通道", srcImage);
//=================【红色通道部分】=================
// 描述:多通道混合-红色分量部分
//============================================
//【0】定义相关变量
Mat imageRedChannel;
//【1】重新读入图片
logoImage = imread("dota_logo.jpg", 0);
srcImage = imread("dota_jugg.jpg");
if (!logoImage.data) { printf("Oh,no,读取logoImage错误~! n"); return false; }
if (!srcImage.data) { printf("Oh,no,读取srcImage错误~! n"); return false; }
//【2】将一个三通道图像转换成三个单通道图像
split(srcImage, channels);//分离色彩通道
//【3】将原图的红色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变
imageRedChannel = channels.at(2);
//【4】将原图的红色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageRedChannel中
addWeighted(imageRedChannel(Rect(500, 250, logoImage.cols, logoImage.rows)), 1.0,
logoImage, 0.5, 0., imageRedChannel(Rect(500, 250, logoImage.cols, logoImage.rows)));
//【5】将三个独立的单通道重新合并成一个三通道
merge(channels, srcImage);
//【6】显示效果图
namedWindow("<3>游戏原画+logo红色通道 ");
imshow("<3>游戏原画+logo红色通道 ", srcImage);
return true;
}
MultiChannelImageBlending
运行结果如下:
参考文献
[1] 毛星云.OpenCV3编程入门[M].电子工业出版社.北京.2015.2.
附录
原文链接: https://www.cnblogs.com/jianle23/p/13787049.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/203804
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!