OpenCV4入门系列教程36:图像通道混合

索引地址:系列教程索引地址

上一篇:OpenCV4入门系列教程35:图像通道合并与分离

在图像处理中,目标区域定义为感兴趣区域ROI(region of Interest),这是后期图像处理的基础,在获取ROI后,进行一些列的处理。ROI区域在Opencv中就是Rect,先构建Rect,然后给予ROI一些特点,形成了图像掩膜。

1
2
3
4
5
Mat imageROI;//定义一个Mat类型并给其设定ROI区域
//方法一
imageROI=image(Rect(500,250,logo.cols,logo.rows));
//方法二
imageROI=Image(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));

代码中定义了一个Mat类型,是一种类似指针的引用,然后指向Image(Mat)中制定区域,这样就创建了一个ROI区域,这个区域在Image中。

图像掩膜,在ROI区域中导入一张图像,然后在image中进行加载

1
2
3
4
5
6
7
8
9
Mat Image1= imread("dota_pa.jpg");
//定义一个Mat类型并给其设定ROI区域 ,指向Image中坐标点200,250,长宽为cols和rows
Mat imageROI= Image1(Rect(200,250,logoImage.cols,logoImage.rows));

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

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

线性混合就是,对两幅图像(f0(x)和f1(x))或两段视频(同样为(f0(x)和f1(x))产生时间上的画面叠化(cross-dissolve)效果,就像幻灯片放映和电影制作中的那样。公式为:

g(x)=(1α)f0(x)+f1(x)g(x)=(1-\alpha)f_{0}(x)+f_{1}(x)

混合函数原型为:

1
2
3
4
5
6
7
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()。dst = src1

addWeighted函数计算如下两个数组(src1和src2)的加权和,得到结果输出给第四个参数。即addWeighted函数的作用可以被表示为为如下的矩阵表达式为:

dst=src1[I]alpha+src2[I]beta+gammadst = src1[I] * alpha+ src2[I] * beta + gamma;

测试代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序25
// 程序描述:初级图像混合
// 2014年11月 Created by @浅墨_毛星云
// 2014年12月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------

//---------------------------------【头文件、命名空间包含部分】-------------------------------
// 描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------------------------------------
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

//-----------------------------------【全局函数声明部分】--------------------------------------
// 描述:全局函数声明
//-----------------------------------------------------------------------------------------------
bool ROI_AddImage();
bool LinearBlending();
bool ROI_LinearBlending();

//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main() {
if (ROI_AddImage() && LinearBlending() && ROI_LinearBlending()) {
cout << endl << "\n运行成功,得出了需要的图像";
}

waitKey(0);
return 0;
}

//----------------------------------【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】显示结果 利用ROI实现图像叠加示例窗口
namedWindow("<1>");
imshow("<1>", 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>Original", srcImage2);
imshow("<3>Result", 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;
}

测试结果:

图片直接覆盖在另一张图片上:

roi

线性混合效果:

linear

roi和线性混合 的混合效果:

roi_linear

多通道混合

彩色图像是三通道图像,当然灰度图像是单通道图像,在图像应用中需要对某一通道混合,或者几个通道颜色混合,这就是多通道颜色混合。

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序26
// 程序描述:分离颜色通道&多通道图像混合
// 2014年11月 Created by @浅墨_毛星云
// 2014年12月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------

//-----------------------------------【头文件包含部分】---------------------------------------
// 描述:包含程序所依赖的头文件
//------------------------------------------------------------------------------------------------
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

//-----------------------------------【命名空间声明部分】---------------------------------------
// 描述:包含程序所使用的命名空间
//-------------------------------------------------------------------------------------------------
using namespace cv;
using namespace std;

//-----------------------------------【全局函数声明部分】--------------------------------------
// 描述:全局函数声明
//-----------------------------------------------------------------------------------------------
bool MultiChannelBlending();

//-----------------------------------【main( )函数】------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//-----------------------------------------------------------------------------------------------
int main() {
if (MultiChannelBlending()) {
cout << endl << "\n运行成功,得出了需要的图像~! ";
}

waitKey(0);
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】显示效果图 游戏原画+logo蓝色通道
namedWindow(" <1>");
imshow(" <1>", 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】显示效果图 游戏原画+logo绿色通道
namedWindow("<2>");
imshow("<2>", 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】显示效果图 游戏原画+logo红色通道
namedWindow("<3>");
imshow("<3>", srcImage);

return true;
}

测试效果:

multichannel

下一篇:OpenCV4入门系列教程37:图像仿射变换