计算机视觉
图像处理

双线性插值

双线性插值较为常用,原理参考

双线性插值,这个名字咋一听很高大上的样纸,再在维基百科上一查(见文末,我去,一堆的公式吓死人),像俺这种半文盲,看到公式脑子就懵的类型,真心给跪。虽然看着好复杂,但仔细一看道理再简单不过了,所以还是自己梳理一下好。

双线性插值,顾名思义就是两个方向的线性插值加起来(这解释过于简单粗暴,哈哈)。所以只要了解什么是线性插值,分别在x轴和y轴都做一遍,就是双线性插值了。

线性插值的概念也非常简单粗暴,就是两个点A,B,要在AB中间插入一个点C(点C坐标在AB连线上),就直接让C的值落在AB的值的连线上就可以了。

如A点坐标(0,0),值为3,B点坐标(0,2),值为5,那要对坐标为(0,1)的点C进行插值,就让C落在AB线上,值为4就可以了。

但 是如果C不在AB的线上肿么办捏,所以就有了双线性插值。如图,已知Q12,Q22,Q11,Q21,但是要插值的点为P点,这就要用双线性插值了,首先 在x轴方向上,对R1和R2两个点进行插值,这个很简单,然后根据R1和R2对P点进行插值,这就是所谓的双线性插值。

clip_image001

 

附:维基百科–双线性插值:

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

假如我们想得到未知函数 f 在点 P=\left( x, y\right) 的值,假设我们已知函数 fQ_{11} = \left( x_1, y_1 \right) , Q_{12} = \left( x_1, y_2 \right) , Q_{21} = \left( x_2, y_1 \right) , 及 Q_{22} = \left( x_2, y_2 \right) 四个点的值。

首先在 x 方向进行线性插值,得到

 f(R_1) \approx \frac{x_2-x}{x_2-x_1} f(Q_{11}) + \frac{x-x_1}{x_2-x_1} f(Q_{21}) \quad\mbox{Where}\quad R_1 = (x,y_1),
 f(R_2) \approx \frac{x_2-x}{x_2-x_1} f(Q_{12}) + \frac{x-x_1}{x_2-x_1} f(Q_{22}) \quad\mbox{Where}\quad R_2 = (x,y_2).

然后在 y 方向进行线性插值,得到

 f(P) \approx \frac{y_2-y}{y_2-y_1} f(R_1) + \frac{y-y_1}{y_2-y_1} f(R_2).

这样就得到所要的结果 f \left( x, y \right),

 f(x,y) \approx \frac{f(Q_{11})}{(x_2-x_1)(y_2-y_1)} (x_2-x)(y_2-y) + \frac{f(Q_{21})}{(x_2-x_1)(y_2-y_1)} (x-x_1)(y_2-y)
 + \frac{f(Q_{12})}{(x_2-x_1)(y_2-y_1)} (x_2-x)(y-y_1) + \frac{f(Q_{22})}{(x_2-x_1)(y_2-y_1)} (x-x_1)(y-y_1).

如果选择一个坐标系统使得 f 的四个已知点坐标分别为 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么插值公式就可以化简为

 f(x,y) \approx f(0,0) \, (1-x)(1-y) + f(1,0) \, x(1-y) + f(0,1) \, (1-x)y + f(1,1) xy.

或者用矩阵运算表示为

 f(x,y) \approx \begin{bmatrix} 1-x & x \end{bmatrix} \begin{bmatrix} f(0,0) & f(0,1) \ f(1,0) & f(1,1) \end{bmatrix} \begin{bmatrix} 1-y \ y \end{bmatrix}

与这种插值方法名称不同的是,这种插值方法的结果通常不是线性的,它的形式是

 b_1 + b_2 x + b_3 y + b_4 x y. \,

常数的数目都对应于给定的 f 的数据点数目

 b_1 = f(0,0)
 b_2 = f(1,0) - f(0,0)
 b_3 = f(0,1) - f(0,0)
 b_4 = f(1,1) - f(1,0) - f(0,1) + f(0,0)

线性插值的结果与插值的顺序无关。首先进行 y 方向的插值,然后进行 x 方向的插值,所得到的结果是一样的。

下面给出代码:

void ImgResize_BiLinear()
{
	cv::Mat imgSrc, imgDst1, imgDst2;  

	imgSrc = cv::imread("test.jpg");  
	imgDst1 = cv::Mat(cv::Size(imgSrc.cols*2, imgSrc.rows*2), imgSrc.type(), cv::Scalar::all(0));  
	imgDst2 = cv::Mat(imgDst1.size(), imgSrc.type(), cv::Scalar::all(0));  

	double scale_x = (double)imgSrc.cols / imgDst1.cols;  
	double scale_y = (double)imgSrc.rows / imgDst1.rows;  

	uchar* dataDst = imgDst1.data;  
	int stepDst = imgDst1.step;  
	uchar* dataSrc = imgSrc.data;  
	int stepSrc = imgSrc.step;  
	int iWidthSrc = imgSrc.cols;  
	int iHiehgtSrc = imgSrc.rows; 

	short cbufy[2]; 
	float y_float, x_float;
	int y_int, x_int;
	short cbufx[2]; 

	for (int j=0; j<imgDst1.rows; ++j)  
	{  
		y_float = (float)((j + 0.5) * scale_y - 0.5);  
		y_int = cvFloor(y_float);  
		y_float -= y_int;  
		y_int = std::min(y_int, iHiehgtSrc - 2);  
		y_int = std::max(0, y_int);  
		 
		cbufy[0] = cv::saturate_cast((1.f - y_float) * 2048);  
		cbufy[1] = 2048 - cbufy[0];  

		for (int i=0; i<imgDst1.cols; ++i)  
		{  
			x_float = (float)((i + 0.5) * scale_x - 0.5);  
			x_int = cvFloor(x_float);  
			x_float -= x_int;  

			if (x_int < 0) { x_float = 0, x_int = 0; } if (x_int >= iWidthSrc - 1) 
			{  
				x_float = 0, x_int = iWidthSrc - 2;  
			}  

			 
			cbufx[0] = cv::saturate_cast((1.f - x_float) * 2048);  
			cbufx[1] = 2048 - cbufx[0];  

			for (int k = 0; k < imgSrc.channels(); ++k) { *(dataDst+ j*stepDst + 3*i + k) = (*(dataSrc + y_int*stepSrc + 3*x_int + k) * cbufx[0] * cbufy[0] + *(dataSrc + (y_int+1)*stepSrc + 3*x_int + k) * cbufx[0] * cbufy[1] + *(dataSrc + y_int*stepSrc + 3*(x_int+1) + k) * cbufx[1] * cbufy[0] + *(dataSrc + (y_int+1)*stepSrc + 3*(x_int+1) + k) * cbufx[1] * cbufy[1]) >> 22;  
			}  
		}  
	}  
	cv::imwrite("result_1.jpg", imgDst1);  

	cv::resize(imgSrc, imgDst2, imgDst1.size(), 0, 0, 1);  
	cv::imwrite("result_2.jpg", imgDst2);  
}

上述代码为3通道彩图的缩放代码,图片的加载保存用了Opencv的结构体,其余基本保持C的风格;

VS2008+Opencv249下面测试通过,有兴趣的朋友自己试试;

转载注明来源:CV视觉网 » 双线性插值

分享到:更多 ()
扫描二维码,给作者 打赏
pay_weixinpay_weixin

请选择你看完该文章的感受:

0不错 0超赞 0无聊 0扯淡 0不解 0路过

评论 3

评论前必须登录!