图像处理之重映射

482 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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;
}

效果图:

原图

2.PNG

效果图

3.PNG