图像缩放之双线性插值

原创 2015年10月27日 18:28:04

双线性插值

双线性插值作为一种滤波器,广泛应用在信号处理,数字图像和视频处理等应用中。
中文名
双线性插值
外文名
Bilinear Interpolation

介绍









































双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。

示例

已知的红色数据点与待插值得到的绿色点
假如我们想得到未知函数f在点P= (x,y) 的值,假设我们已知函数fQ11 = (x1,y1)、Q12 = (x1,y2),Q21 = (x2,y1) 以及Q22 = (x2,y2) 四个点的值。
首先在x方向进行线性插值,得到R1和R2,然后在y方向进行线性插值,得到P.
这样就得到所要的结果f(x,y).
其中红色点Q11,Q12,Q21,Q22为已知的4个像素点.
第一步:X方向的线性插值,插入蓝色 第二步 :做完X方向的插值后再做Y方向的
点R1和R2插值 ,由R1与R2计算P点.
x方向上x方向上
Y方向上插入绿色点P.
线性插值的结果与插值的顺序无关。首先进行y方向的插值,然后进行x方向的插值,所得到的结果是一样的。但双线性插值插值方法这种方法并不是线性的,首先进行y方向的插值,然后进行x方向的插值,与首先进行 x方向的插值,然后进行 y方向的插值,所得到的R1与R2是不一样的。
如果选择一个坐标系统使得 的四个已知点坐标分别为 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么插值公式就可以化简为
f(x,y)=f(0,0)(1-x)(1-y)+f(0,1)(1-x)y+f(1,1)xy+f(1,0)x(1-y)
  • 在x与y方向上,z值成单调性特性的应用中,此种方法可以做外插运算,即可以求解Q1~Q4所构成的正方形以外的点的值。
  • 双线性插值的一个显然的三维空间延伸是三线性插值。
  • 三线性插值的方法可参看matlab中的interp3

特点编辑

当对相邻四个像素点采用双线性插值时,所得表面在邻域处是吻合的,但斜率不吻合。并且双线性灰度插值的平滑作用可能使得图像的细节产生退化,这种现象在进行图像放大时尤其明显。

代码如下:

IplImage *img = cvLoadImage("C:\\Users\\Administrator\\Desktop\\3838.jpg");
int nw = img->width;
int nh = img->height;

void Ctry::OnTryTyr1()
{
	//TODO:  在此添加命令处理程序代码  
	double times = 0.8;          //比例因子  
	int nWidth =int( times * (img->width));
	int nHeight =int( times * (img->height));
	IplImage *dst = cvCreateImage(cvSize(nWidth, nHeight), 8, 3);

	CvScalar pixel1;
	for (int i = 0; i < dst->width; i++)
	{
		for (int j = 0; j < dst->height; j++)
		{
			if (int(i * 1 / times) < img->width && int(j * 1 / times) < img->height)
			{
				pixel1 = InterpBilinear((i * 1 / times), (j * 1 / times ));
				cvSet2D(dst, j, i, pixel1);
			}
			else
			{
				cvSet2D(dst, j, i, RGB(0, 0, 0, ));
			}
		}
	}
	cvSaveImage("C:\\Users\\Administrator\\Desktop\\InterpBilinear.jpg", dst);
	cvNamedWindow(" dst", CV_WINDOW_AUTOSIZE);
	cvShowImage(" dst", dst);
	cvNamedWindow("img", CV_WINDOW_AUTOSIZE);
	cvShowImage("img", img);
	cvWaitKey(0);

	cvReleaseImage(&img);
	cvReleaseImage(&dst);
	cvDestroyWindow(" dst");
	cvDestroyWindow("img");
}

CvScalar Ctry::InterpBilinear(double x, double y)
{
	//4个邻近点的坐标(i1,j1),(i2,j1),(i1,j2),(i2,j2)
	int x1, x2;
	int y1, y2;
	//4个最邻近像素值
	CvScalar f1, f2, f3, f4;
	//二个插值中间值
	CvScalar f12, f34;
	CvScalar pixel;
	double epsilon = 0.0001;
	//计算四个最邻近像素的坐标
	x1 = int(x);
	x2 = x1 + 1;
	y1 = int(y);
	y2 = y1 + 1;

	if ((x<0) || (x>nw - 1) || (y<0) || (y>nh - 1))
	{
		//要计算的点不在原图范围内
		MessageBox(NULL, "超过图片大小", "错误", MB_OK | MB_ICONERROR);
		return 0;
	}
	else
	{
		if (fabs(x - nw + 1 )<= epsilon)
		{
			//要计算的点在图像的右边缘上
			if (fabs(y - nh + 1) <= epsilon)
			{
				//要计算的元素恰好是图像最右下角的那一个元素,直接返回该点的像素值
				f1 = cvGet2D(img, y1, x1);
				return f1;
			}
			else
			{
				//在图像右边缘且不是最后一点,直接一次插值即可
				f1 = cvGet2D(img, y1, x1);
				f3 = cvGet2D(img, y1, x2);
				pixel.val[0] = f1.val[0] + (y - y1)*(f3.val[0] - f1.val[0]);
				pixel.val[1] = f1.val[1] + (y - y1)*(f3.val[1] - f1.val[1]);
				pixel.val[2] = f1.val[2] + (y - y1)*(f3.val[2] - f1.val[2]);
				return pixel;
			}
		}
		else if (fabs(y - nh + 1) <= epsilon)
		{
			//要计算的点在图像的下边缘上且不是最后一点,直接一次插值即可
			f1 = cvGet2D(img, y1, x1);
			f2 = cvGet2D(img, y2, x1);
			pixel.val[0] = f1.val[0] + (x - x1)*(f2.val[0] - f1.val[0]);
			pixel.val[1] = f1.val[1] + (x - x1)*(f2.val[1] - f1.val[1]);
			pixel.val[2] = f1.val[2] + (x - x1)*(f2.val[2] - f1.val[2]);
			return pixel;
		}
		else
		{
			//计算4个最邻近像素值
			f1 = cvGet2D(img, y1, x1);
			f2 = cvGet2D(img, y2, x1);
			f3 = cvGet2D(img, y1, x2);
			f4 = cvGet2D(img, y2, x2);
			//插值1
			f12.val[0] = f1.val[0] + (x - x1)*(f2.val[0] - f1.val[0]);
			f12.val[1] = f1.val[1] + (x - x1)*(f2.val[1] - f1.val[1]);
			f12.val[2] = f1.val[2] + (x - x1)*(f2.val[2] - f1.val[2]);
			//插值2
			f34.val[0] = f3.val[0] + (x - x1)*(f4.val[0] - f3.val[0]);
			f34.val[1] = f3.val[1] + (x - x1)*(f4.val[1] - f3.val[1]);
			f34.val[2] = f3.val[2] + (x - x1)*(f4.val[2] - f3.val[2]);
			//插值3
			pixel.val[0] = f12.val[0] + (y - y1)*(f34.val[0] - f12.val[0]);
			pixel.val[1] = f12.val[1] + (y - y1)*(f34.val[1] - f12.val[1]);
			pixel.val[2] = f12.val[2] + (y - y1)*(f34.val[2] - f12.val[2]);

			return pixel;
		}
	}
}

效果图:      

matlab的interp2二维数据内插值函数

interp2 功能 二维数据内插值(表格查找) 格式 (1)ZI = interp2(X,Y,Z,XI,YI) 返回矩阵ZI,其元素包含对应于参量XI 与YI(可以是向量、或同型矩阵) 的元...
  • u012365383
  • u012365383
  • 2013年11月26日 16:25
  • 3932

【Matlab】图像插值函数interp2理解

图像插值就是利用已知邻近像素点的灰度值(或rgb图像中的三色值)来产生未知像素点的灰度值,以便由原始图像再生出具有更高分辨率的图像。通过例子来理解interp2函数:[X,Y] = meshgrid(...
  • horseinch
  • horseinch
  • 2016年05月10日 23:47
  • 10534

图像的放大与缩小(2)——双线性插值放大与均值缩小

概述 基于上一节“等距采样法”实现图片放大与缩小的缺点。要对其进行改进,对图像的缩小则可以用“局部均值法”,对于图像的放大则可以用“双线性插值法”。 效果如下:        ...
  • salonzhou
  • salonzhou
  • 2016年07月14日 18:15
  • 2306

C++ 双线性插值缩放图像

 缩放灰度图 cv::Mat bilinear(cv::Mat src, int row, int col){ int rows = src.rows, cols = src.cols...
  • messi_cyc
  • messi_cyc
  • 2017年09月08日 16:40
  • 364

双线性插值的图像缩放算法的研究与实现

一、引言 数字图像处理的对象因其涉及到社会的各个领域,倍受到越来越多的关注,而图像缩放作为数字图像处理中的基本操作尤为重要,在社会的很多领域都需要对图像进行放大和缩小。利用VC++的MFC类库中的S...
  • SMF0504
  • SMF0504
  • 2016年05月03日 14:13
  • 2629

双线性插值算法的详细总结

最近在做视频拼接的项目,里面用到了图像的单应性矩阵变换,在最后的图像重映射,由于目标图像的坐标是非整数的,所以需要用到插值的方法,用的就是双线性插值,下面的博文主要是查看了前辈的博客对双线性插值算法原...
  • xjz18298268521
  • xjz18298268521
  • 2016年04月22日 15:25
  • 35658

线性插值和双线性插值

最近在学数字图像处理中旋转变换的问题,发现旋转以后图片有一些不连续点,于是试着用双线性插值法进行解决。下面就介绍下插值的原理: 线性插值 如果你只处理分离的数据、想知道分离点之间的某些值,需要用到...
  • longzaitianya1989
  • longzaitianya1989
  • 2013年04月05日 16:30
  • 38213

图像插值----双线性插值完全解析

双线性插值
  • u013355826
  • u013355826
  • 2017年02月23日 20:57
  • 3751

常用图像插值算法分析与比较

引用:http://www.cnblogs.com/okaimee/archive/2010/08/18/1802585.html       摘 要:插值算法在图像缩放处理中是一项基本且重要的问题...
  • SMF0504
  • SMF0504
  • 2016年05月03日 14:09
  • 8484

NEON在S2平台图像处理中的简单应用

NEON:是适用于ARM Cortex-A系列处理器的一种128位SIMD(Single Instruction, Multiple Data,单指令、多数据)扩展结构。          S2:安...
  • wlcy_888
  • wlcy_888
  • 2014年06月17日 14:46
  • 806
收藏助手
不良信息举报
您举报文章:图像缩放之双线性插值
举报原因:
原因补充:

(最多只允许输入30个字)