图像的坐标映射是通过原图像与目标图像之间建立一种映射关系,这种映射关系有两种,一种是计算原图像任意像素在映射后图像的坐标位置,另一种是计算变换后图像任意像素反映射在原图像的坐标位置。
opencv中提供重映射等操作,其中重映射就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。为了完成映射过程,需要获得一些插值为非整数像素的坐标。对于原图像和目标图像,满足下式:
G(x,y)=f(h(x,y))
G()是目标图像,f()是源图像,而h(x,y)是作用于(x,y)的映射方法函数。
函数remap使用指定的映射转换源图像,其公式为:
Void remap(InputArray src, // 源图像
OutputArray dst, // 目标图像
InputArray map1, // 第一个映射 ,x坐标
InputArray map2, // 第二个映射 ,y坐标
int interpolation, // 表示插值方法
int borderMode=BORDER_CONSTANT, // 表示边界插值类型
const Scalar&borderValue=Scalar()) // 表示插值数值
map1和map2:代表目标图中的(x,y)点在原图像的x坐标和y坐标;
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#define WINDOW_NAME "重映射" //为窗口标题定义的宏
Mat g_srcImage, g_dstImage;
Mat g_map_x, g_map_y;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
printf( "\n\t按键操作说明: \n\n"
"\t\t键盘按键【ESC】- 退出程序\n"
"\t\t键盘按键【1】- 第一种映射方式:缩放\n"
"\t\t键盘按键【2】- 第二种映射方式:上下翻转\n"
"\t\t键盘按键【3】- 第三种映射方式:左右翻转\n"
"\t\t键盘按键【4】- 第四种映射方式:上下左右180度翻转\n" );
g_srcImage = imread( "F:/C++/2. OPENCV 3.1.0/TEST/2.jpg", 1 );
if(!g_srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; }
imshow("原始图",g_srcImage);
// 1、创建和原始图一样的效果图,x重映射图,y重映射图
// map1和map2:代表目标图中的(x,y)点在原图像的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 );
// 2、创建窗口并显示
namedWindow( WINDOW_NAME, CV_WINDOW_AUTOSIZE );
imshow(WINDOW_NAME,g_srcImage);
// 3、轮询按键,更新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);
remap( g_srcImage, g_dstImage, g_map_x, g_map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );
//显示效果图
imshow( WINDOW_NAME, g_dstImage );
}
waitKey(0);
return a.exec();
}
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); // 行不变(X不变)
g_map_y.at<float>(j,i) = static_cast<float>(g_srcImage.rows - j); // 列翻转(Y翻转不变)
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;
}
1、缩小(XY 缩放)
2、Y方向翻转(X不变,Y翻转)
3、X方向翻转(X翻转,Y不变)
4、X,Y 方向均翻转(XY均翻转)