void cv::remap ( InputArray src,
OutputArray dst,
InputArray map1,
InputArray map2,
int interpolation,
int borderMode = BORDER_CONSTANT,
const Scalar & borderValue = Scalar()
)
将通用几何变换应用于图像。dst
的尺寸应当应当和map1
、map2
一致,而dst
的数据类型则应同src
一致。
map1
以及map2
共同表征了映射方式,代表dst的某个像素值来自于src中的哪一个点。也就是说,dst的每个像素的值都可以从src中某个位置得到,计算方式则如下:
dst(x,y) = src(map1(x, y), map2(x, y));
由于计算的取值位置(map1(x, y), map2(x, y))
可能为非整数,需要在src中通过某种插值方式interpolation
插值计算得到这一点的像素值。
borderMode
——未定义的像素如何填充,类似于卷积时怎么补充边界。
可用的interpolation以及borderMode方式可查阅官网文档。
int remap_test()
{
// 映射关系,简单的平移
{
Mat srcImage;
srcImage = imread("ying.png", 1);
//resize(srcImage, srcImage, Size(srcImage.cols / 2, srcImage.rows / 2));
Mat dstImage;
Mat map_x, map_y;
float shift_x = 250.5, shift_y = 150.7;
int dst_w = 400, dst_h = 300;
Rect dstROI(shift_x, shift_y, dst_w, dst_h);
std::vector t_x, t_y;
int w = 0, h = 0;
for (int w = 0; w < dst_w; w++) {
t_x.push_back(static_cast(w + shift_x));
}
for (int h = 0; h < dst_h; h++) {
t_y.push_back(static_cast(h + shift_y));
}
cout << "tx: " << t_x.size() << " ty: " << t_y.size() << endl;
cv::repeat(cv::Mat(t_x).t(), t_y.size(), 1, map_x);
cv::repeat(cv::Mat(t_y), 1, t_x.size(), map_y);
remap(srcImage, dstImage, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(40, 40, 40));
rectangle(srcImage, dstROI, Scalar(0, 0, 255));
imshow("src", srcImage);
imshow("remap result", dstImage);
waitKey(0);
}
// 波纹效果
{
Mat srcImage;
srcImage = imread("ying.png", 1);
resize(srcImage, srcImage, Size(srcImage.cols / 2, srcImage.rows / 2));
Mat dstImage;
Mat map_x, map_y;
map_x.create(srcImage.size(), CV_32FC1);
map_y.create(map_x.size(), CV_32FC1);
dstImage.create(map_x.size(), srcImage.type());
for (int j = 0; j < srcImage.rows; j++)
{
for (int i = 0; i < srcImage.cols; i++)
{
//改变map_x & map_y的值.
map_x.at(j, i) = static_cast(i + 5 * cos(j / 10.f));
map_y.at(j, i) = static_cast(j);
}
}
remap(srcImage, dstImage, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(255, 0, 0));
imshow("src", srcImage);
imshow("remap result", dstImage);
waitKey(0);
}
return 0;
}
可以看到新图片的第一个像素来自原图的红色标记处(shift_x = 250, shift_y = 150)
,而超出原图区域的像素,由于BORDER_CONSTANT被指定为设定的值。
如例子1所示,通过插值获取图像区域中非整数位置的像素信息,也就是某些场景中所谓的亚像素信息。
如例子2所示,可以实现对图像的扭曲效果,哈哈镜、波纹、乃至更加复杂的效果都可以通过调整映射矩阵的方式实现。