定义:映射,或者射影,在数学及相关的领域还用于定义函数。函数是从非空数集到非空数集的映射,而且只能是一对一映射或多对一映射。
映射的成立条件简单的表述就是:
1.定义域的遍历性:X中的每个元素x在映射的值域中都有对应对象
2.对应的唯一性:定义域中的一个元素只能与映射值域中的一个元素对应
定义域也称为原象集,值域也称为象集。
图中A到B的为映射,B到A为逆映射。
单设:对于任意的,有且仅有唯一的,则为单射。
满射:对于任意的,存在,则为满射。
双射:对于,有且仅有,即一一对应,则为双射。
双射既满足单射,也满足满射。
简单说就是把输入图片中个像素按照一定的规则映射到另外一张图像的对应位置上,形成一张新的图像。
f(x,y)为原图中的像素点,通过映射函数h(x,y)映射到目标图像g(x,y)中。
如当,则可以实现图片的左右镜像对称。
通常像素映射需要建立映射表,建立映射表的方式有两种:
1.前向映射:即以原图像中的为起点,根据映射关系找到目标图像中的坐标,然后将原图像中的像素值搬到目标图像中的对应位置坐标上。
2.后向映射:即以目标图像中的为起点,根据映射关系的逆运算找到原图像中的坐标,然后将原图像中的像素值搬到目标图像中的对应位置坐标上。
由于像素映射可以必须保证是满射,但是无法保证满足单射,因此采用后向映射更为合理。
因为映射关系是,所以可以拆解为两部分来看,即坐标的映射和坐标的映射,因此API中的map1是映射表,map2是映射表。简单来看真个API的功能可以表示下图,即根据原图与映射表生成新的图像,下图为顺时针旋转九十。
映射表的尺度大小与原始图像相同,但是只保存坐标或坐标信息,所以是单通道的,且坐标在计算时会出现小数的情况,因此opencv要求映射表的数据类型为 CV_32FC1。
Remap(
InputArray src,
OutputArray dst,
InputArray map1,//x映射表 CV_32FC1
InputArray map2,//y映射表
int interpolation,//选择的插值方法,常见的为线性插值,可选双线性插值和立方插值等
int borderMode,//BORDER_CONSTANT
const Scalar borderValue, //固定值填充边缘时的颜色
)
#include
#include
#include
using namespace std;
using namespace cv;
void update_map(Mat& map_x,Mat& map_y,const Mat& src ,Size size, int flag)
{
map_x.create(size, CV_32FC1); //创建映射表
map_y.create(size, CV_32FC1);
float x_scale = src.cols*1.0/size.width;
float y_scale = src.rows*1.0 / size.height;
float x, y;
flag = flag % 3;
//填充映射表
for (int row = 0; row < size.height; row++)
{
for (int col = 0; col < size.width; col++)
{
switch (flag)
{
case 0: //左右翻转
x = src.cols - col * x_scale; // x = X - x'
y = row * y_scale;
map_x.at(row, col) = x;
map_y.at(row, col) = y;
break;
case 1://上下翻转
x = col * x_scale;
y = src.rows - row * y_scale; //y = Y -y'
map_x.at(row, col) = x;
map_y.at(row, col) = y;
break;
case 2://旋转180°
x = row * y_scale * src.cols /src.rows; //x = y'*(X/Y)
y = src.rows - col * x_scale *src.rows/src.cols; //y = X-x'/(X/Y)
map_x.at(row, col) = x;
map_y.at(row, col) = y;
break;
default:
x = col * x_scale;
y = row * y_scale;
map_x.at(row, col) = x;
map_y.at(row, col) = y;
break;
}
}
}
}
int main(int argc,char** argv)
{
Mat src = imread("33.jpg");
if (!src.data)
{
printf("打开图像失败!\n");
return -1;
}
char input_win[] = "input ";
char output_win[] = "output";
namedWindow(input_win,CV_WINDOW_AUTOSIZE);
namedWindow(output_win, CV_WINDOW_AUTOSIZE);
imshow(input_win, src);
Mat map_x, map_y,out_img;
int flag = 0;
while (true)
{
flag = waitKey(5000);
if (flag == 27)
{
break;
}
update_map(map_x, map_y, src, Size(300, 400), flag);
//根据映射表完成映射
remap(src, out_img, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(255, 255, 255));
imshow(output_win, out_img);
}
return 0;
}