开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第29天
1 概述
本节中,我们主要一起了解重映射的概念,以及OpenCV 中相关的实现函数remap()。
2 重映射的概念
重映射,就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。为了完成映射过程,需要获得一些插值为非整数像素的坐标,因为源图像与目标图像的像素坐标不是一一对应的。一般情况下,我们通过重映射来表达每个像素
g(x,y)=f(h(x,y))
在这里,gO是目标图像,fO是源图像,而h(x,y)是作用于(x,y)的映射方法函数。来看个例子。若有一幅图像I,对其按照下面的条件作重映射:
h(x,y)=(I.cols-x,y)
图像会按照x轴方向发生翻转。
3 实现重映射:remap()函数
remap()函数会根据指定的映射形式,将源图像进行重映射几何变换,基于的公式如下:
dst(x,y)=src(map,(x,y),map,(x,y))
需要注意,此函数不支持就地(in—place)操作。看看其原型和参数。
C++:
void remap(InputArray src, OutputArraydst, InputArray map1, InputArray map2, int interpolation,
intborderModle=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
- 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位或者浮点型图像。
- 第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放函数调用后的输出结果,需和源图片有一样的尺寸和类型。
- 第三个参数,InputArray类型的mapl,它有两种可能的表示对象。
■表示点(x,y)的第一个映射。
■表示CV_16SC2、CV_32FC1或CV_32FC2类型的X值。
- 第四个参数,InputArray类型的map2,同样,它也有两种可能的表示对象,而且它会根据map1来确定表示那种对象。
■若mapl表示点(x,y)时。这个参数不代表任何值。
■表示CV_16UC1,CV_32FC1类型的Y值(第二个值)。
- 第五个参数,int类型的 interpolation,插值方式,之前的resize()函数中有 讲到,需要注意,resize()函数中提到的INTER_AREA插值方式在这里是不支持的,所以可选的插值方式如下(需要注意,这些宏相应的OpenCV2版为在它们的宏名称前面加上“CV_”前缀,比如“INTER_LINEAR”的OpenCV2版为“CV_INTER_LINEAR”):
■INTER_NEAREST-最近邻插值
■INTER_LINEAR-双线性插值(默认值)
■INTER_CUBIC—双三次样条插值(逾4x4像素邻域内的双三次插值)
■INTER_LANCZOS4-Lanczos插值(逾8x8像素邻域的Lanczos插值)
- 第六个参数,int 类型的 borderMode,边界模式,有默认值 BORDER CONSTANT,表示目标图像中“离群点(outliers)”的像素值不会被此函数修改。
- 第七个参数,const Scalar&类型的 borderValue,当有常数边界时使用的值, 其有默认值Scalar(),即默认值为0。
4 示例
代码:
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//---------------------------------------------------------------------------------------
#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("原始图",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, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );
//【5】显示效果图
imshow( "【程序窗口】", dstImage );
waitKey();
return 0;
}
效果图:
原图
效果图