重映射是什么意思?
-
把一个图像中一个位置的像素放置到另一个图片指定位置的过程.
-
为了完成映射过程, 有必要获得一些插值为非整数像素坐标,因为源图像与目标图像的像素坐标不是一一对应的.
-
我们通过重映射来表达每个像素的位置
:
这里
是目标图像,
是源图像,
是作用于
的映射方法函数.
让我们来思考一个快速的例子. 想象一下我们有一个图像 , 我们想满足下面的条件作重映射:
会发生什么? 图像会按照 轴方向发生翻转.
映射函数 remap. 参数说明:
代码如下:
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> using namespace cv; /// Global variables Mat src, dst; Mat map_x, map_y; char* remap_window = "Remap demo"; int ind = 0; /// Function Headers void update_map(void); /** * @function main */ int main(int argc, char** argv) { /// Load the image src = imread("E:\VS2015Opencv\vs2015\project\picture\06.jpg", 1); /// Create dst, map_x and map_y with the same size as src: dst.create(src.size(), src.type()); map_x.create(src.size(), CV_32FC1); map_y.create(src.size(), CV_32FC1); /// Create window namedWindow(remap_window, CV_WINDOW_AUTOSIZE); /// Loop while (true) { /// Each 1 sec. Press ESC to exit the program int c = waitKey(1000); if ((char)c == 27) { break; } /// Update map_x & map_y. Then apply remap update_map(); remap(src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0)); /// Display results imshow(remap_window, dst); } return 0; } void update_map(void) { ind = ind % 4; for (int j = 0; j < src.rows; j++) { for (int i = 0; i < src.cols; i++) { switch (ind) { case 0: if (i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75) { map_x.at<float>(j, i) = 2 * (i - src.cols*0.25) + 0.5; map_y.at<float>(j, i) = 2 * (j - src.rows*0.25) + 0.5; } else { map_x.at<float>(j, i) = 0; map_y.at<float>(j, i) = 0; } break; case 1: map_x.at<float>(j, i) = i; map_y.at<float>(j, i) = src.rows - j; break; case 2: map_x.at<float>(j, i) = src.cols - i; map_y.at<float>(j, i) = j; break; case 3: map_x.at<float>(j, i) = src.cols - i; map_y.at<float>(j, i) = src.rows - j; break; } // end of switch } } ind++; }
主要代码说明:
建立一个间隔1000毫秒的循环,每次循环执行更新映射矩阵参数并对源图像进行重映射处理(使用 mat_x 和 mat_y),然后把更新后的目标图像显示出来:
重映射函数 remap. 参数说明:
- src: 源图像
- dst: 目标图像,与 src 相同大小
- map_x: x方向的映射参数. 它相当于方法
的第一个参数
- map_y: y方向的映射参数. 注意 map_y 和 map_x 与 src 的大小一致。
- CV_INTER_LINEAR: 非整数像素坐标插值标志. 这里给出的是默认值(双线性插值).
- BORDER_CONSTANT: 默认
while (true)
{
/// Each 1 sec. Press ESC to exit the program
int c = waitKey(1000);
if ((char)c == 27)
{
break;
}
/// Update map_x & map_y. Then apply remap
update_map();
remap(src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
/// Display results
imshow(remap_window, dst);
}
return 0;
}
我们做了什么哪些映射过程?(在这里 map_x 代表第一个坐标 h(i,j) , map_y 是第二个坐标,映射后的坐标)
void update_map(void) { ind = ind % 4; for (int j = 0; j < src.rows; j++) { for (int i = 0; i < src.cols; i++) { switch (ind) { case 0: if (i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75) { map_x.at<float>(j, i) = 2 * (i - src.cols*0.25) + 0.5; map_y.at<float>(j, i) = 2 * (j - src.rows*0.25) + 0.5; } else { map_x.at<float>(j, i) = 0; map_y.at<float>(j, i) = 0; } break; case 1: map_x.at<float>(j, i) = i; map_y.at<float>(j, i) = src.rows - j; break; case 2: map_x.at<float>(j, i) = src.cols - i; map_y.at<float>(j, i) = j; break; case 3: map_x.at<float>(j, i) = src.cols - i; map_y.at<float>(j, i) = src.rows - j; break; } // end of switch } } ind++;
结果如下:
图像宽高缩小一半,并显示在中间:
图像上下颠倒:
图像左右颠倒:
两个方向同时颠倒: