OpenCV4入门系列教程59:重映射

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

上一篇:OpenCV4入门系列教程58:图像去水印与修复

重映射

原理

重映射把一个图像中一个位置的像素放置到另一个图片指定位置的过程。

通过重映射来表达每个像素的位置$ (x,y) : g(x,y) = f ( h(x,y) )$,其中g为目标图像,f为原图像。

函数原型:

1
2
3
4
5
void remap( InputArray src, 
OutputArray dst,
InputArray map1, InputArray map2,
int interpolation, int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());

参数说明:

  • src: 源图像
  • dst: 目标图像,与 src 相同大小
  • map_x: x方向的映射参数. 它相当于方法 h(i,j) 的第一个参数
  • map_y: y方向的映射参数. 注意 map_y 和 map_x 与 src 的大小一致。
  • CV_INTER_LINEAR: 非整数像素坐标插值标志. 这里给出的是默认值(双线性插值).
    BORDER_CONSTANT: 默认

测试代码:

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
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:《OpenCV3编程入门》OpenCV3版书本配套示例程序65
// 程序描述:remap函数用法示例
// 2014年11月 Created by @浅墨_毛星云
// 2014年12月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------

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

//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main() {
//【0】变量定义
Mat srcImage, dstImage;
Mat map_x, map_y;

//【1】载入原始图
srcImage = imread("1.jpg", 1);
if (!srcImage.data) {
printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n");
return false;
}
imshow("Original", srcImage);

//【2】创建和原始图一样的效果图,x重映射图,y重映射图
dstImage.create(srcImage.size(), srcImage.type());
map_x.create(srcImage.size(), CV_32FC1);
map_y.create(srcImage.size(), CV_32FC1);

//【3】双层循环,遍历每一个像素点,改变map_x & map_y的值
for (int j = 0; j < srcImage.rows; j++) {
for (int i = 0; i < srcImage.cols; i++) {
//改变map_x & map_y的值.
map_x.at<float>(j, i) = static_cast<float>(i);
map_y.at<float>(j, i) = static_cast<float>(srcImage.rows - j);
}
}

//【4】进行重映射操作
remap(srcImage, dstImage, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));

//【5】显示效果图
imshow("Result", dstImage);
waitKey();

return 0;
}

测试结果:

remap

测试代码2

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
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:《OpenCV3编程入门》OpenCV3版书本配套示例程序66
// 程序描述:实现多种重映射综合示例
// 2014年11月 Created by @浅墨_毛星云
// 2014年12月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------

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

//-----------------------------------【宏定义部分】--------------------------------------------
// 描述:定义一些辅助宏
//------------------------------------------------------------------------------------------------
#define WINDOW_NAME "Application" //为窗口标题定义的宏

//-----------------------------------【全局变量声明部分】--------------------------------------
// 描述:全局变量的声明
//-----------------------------------------------------------------------------------------------
Mat g_srcImage, g_dstImage;
Mat g_map_x, g_map_y;

//-----------------------------------【全局函数声明部分】--------------------------------------
// 描述:全局函数的声明
//-----------------------------------------------------------------------------------------------
int update_map(int key);
static void ShowHelpText(); //输出帮助文字

//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main(int argc, char **argv) {
//显示帮助文字
ShowHelpText();

//【1】载入原始图
g_srcImage = imread("1.jpg", 1);
if (!g_srcImage.data) {
printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n");
return false;
}
imshow("Original", g_srcImage);

//【2】创建和原始图一样的效果图,x重映射图,y重映射图
g_dstImage.create(g_srcImage.size(), g_srcImage.type());
g_map_x.create(g_srcImage.size(), CV_32FC1);
g_map_y.create(g_srcImage.size(), CV_32FC1);

//【3】创建窗口并显示
namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);
imshow(WINDOW_NAME, g_srcImage);

//【4】轮询按键,更新map_x和map_y的值,进行重映射操作并显示效果图
while (1) {
//获取键盘按键
int key = waitKey(0);

//判断ESC是否按下,若按下便退出
if ((key & 255) == 27) {
cout << "程序退出...........\n";
break;
}

//根据按下的键盘按键来更新 map_x & map_y的值. 然后调用remap( )进行重映射
update_map(key);
//此句代码的OpenCV2版为:
// remap( g_srcImage, g_dstImage, g_map_x, g_map_y, CV_INTER_LINEAR, BORDER_CONSTANT,
// Scalar(0,0, 0) ); 此句代码的OpenCV3版为:
remap(g_srcImage, g_dstImage, g_map_x, g_map_y, INTER_LINEAR, BORDER_CONSTANT,
Scalar(0, 0, 0));

//显示效果图
imshow(WINDOW_NAME, g_dstImage);
}
return 0;
}

//-----------------------------------【update_map( )函数】--------------------------------
// 描述:根据按键来更新map_x与map_x的值
//----------------------------------------------------------------------------------------------
int update_map(int key) {
//双层循环,遍历每一个像素点
for (int j = 0; j < g_srcImage.rows; j++) {
for (int i = 0; i < g_srcImage.cols; i++) {
switch (key) {
case '1': // 键盘【1】键按下,进行第一种重映射操作
if (i > g_srcImage.cols * 0.25 && i < g_srcImage.cols * 0.75 &&
j > g_srcImage.rows * 0.25 && j < g_srcImage.rows * 0.75) {
g_map_x.at<float>(j, i) =
static_cast<float>(2 * (i - g_srcImage.cols * 0.25) + 0.5);
g_map_y.at<float>(j, i) =
static_cast<float>(2 * (j - g_srcImage.rows * 0.25) + 0.5);
} else {
g_map_x.at<float>(j, i) = 0;
g_map_y.at<float>(j, i) = 0;
}
break;
case '2': // 键盘【2】键按下,进行第二种重映射操作
g_map_x.at<float>(j, i) = static_cast<float>(i);
g_map_y.at<float>(j, i) = static_cast<float>(g_srcImage.rows - j);
break;
case '3': // 键盘【3】键按下,进行第三种重映射操作
g_map_x.at<float>(j, i) = static_cast<float>(g_srcImage.cols - i);
g_map_y.at<float>(j, i) = static_cast<float>(j);
break;
case '4': // 键盘【4】键按下,进行第四种重映射操作
g_map_x.at<float>(j, i) = static_cast<float>(g_srcImage.cols - i);
g_map_y.at<float>(j, i) = static_cast<float>(g_srcImage.rows - j);
break;
}
}
}
return 1;
}

//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
static void ShowHelpText() {
//输出欢迎信息和OpenCV版本
printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");
printf("\n\n\t\t\t此为本书OpenCV3版的第66个配套示例程序\n");
printf("\n\n\t\t\t 当前使用的OpenCV版本为:" CV_VERSION);
printf("\n\n ----------------------------------------------------------------------------\n");
//输出一些帮助信息
printf("\n\t欢迎来到重映射示例程序~\n\n");
printf("\n\t按键操作说明: \n\n"
"\t\t键盘按键【ESC】- 退出程序\n"
"\t\t键盘按键【1】- 第一种映射方式\n"
"\t\t键盘按键【2】- 第二种映射方式\n"
"\t\t键盘按键【3】- 第三种映射方式\n"
"\t\t键盘按键【4】- 第四种映射方式\n");
}

测试按键3结果:

remap2

下一篇:OpenCV4入门系列教程60:边缘检测