双线性插值运算实现

一、原理

双线性插值
在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值[1]。见下图:

è¿éåå¾çæè¿°

假如我们想得到未知函数 f 在点 P = (x, y) 的值,假设我们已知函数 f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四个点的值。最常见的情况,f就是一个像素点的像素值。首先在 x 方向进行线性插值,得到

è¿éåå¾çæè¿°
然后在 y 方向进行线性插值,得到

è¿éåå¾çæè¿°

综合起来就是双线性插值最后的结果:

è¿éåå¾çæè¿°
由于图像双线性插值只会用相邻的4个点,因此上述公式的分母都是1。opencv中的源码如下,用了一些优化手段,比如用整数计算代替float(下面代码中的*2048就是变11位小数为整数,最后有两个连乘,因此>>22位),以及源图像和目标图像几何中心的对齐 
SrcX=(dstX+0.5)* (srcWidth/dstWidth) -0.5 
SrcY=(dstY+0.5) * (srcHeight/dstHeight)-0.5,

二、C++代码

uchar InterBilinear(float x,float y,cv::Mat &src)
{
	int x_L = cvFloor(x) - 1;
	int x_R = cvFloor(x) + 1;
	int y_T = cvFloor(y) - 1;
	int y_B = cvFloor(y) + 1;

	if (x_L <= 0) x_L = 0;
	else if (x_L >= src.cols - 1) x_L = src.cols - 1;
	if (x_R <= 0) x_R = 0;
	else if (x_R > src.cols - 1) x_R = src.cols - 1;
		
	if (y_T <= 0) y_T = 0;
	else if (y_T > src.rows - 1) y_T = src.rows - 1;
	if (y_B <= 0) y_B = 0;
	else if (y_B > src.rows - 1) y_B = src.rows - 1;

	uchar grayTopL = src.at<uchar>(x_L, y_T);//左上角
	uchar grayTopR = src.at<uchar>(x_R, y_T);//右上角
	uchar grayBottonL = src.at<uchar>(x_L, y_B);//左下角
	uchar grayBottonR = src.at<uchar>(x_R, y_B);//右下角
	//1、计算X方向插值
	float HLscale = 0.f, HRscale = 0.f, VTscale = 0.f, VBscale=0.f;
	HLscale = 1 - (x - x_L) / (x_R - x_L);
	HRscale = 1 - (x_R - x) / (x_R - x_L);
	VTscale = 1 - (y - y_T) / (y_B - y_T);
	VBscale = 1 - (y_B-y) / (y_B - y_T);
	uchar Hpixel1= static_cast<uchar>(grayTopL*HLscale + grayTopR*HRscale);
	uchar Hpixel2 = static_cast<uchar>(grayBottonL*HLscale + grayBottonR*HRscale);
	//计算Y方向插值
	uchar Vpixel = static_cast<uchar>(Hpixel1*VTscale + Hpixel2*VBscale);
	return Vpixel;
}

void ImageZoom(cv::Mat &srcimg, cv::Mat &dst, float scale)
{
	cv::Mat resultimg, grayimg;
	if (scale <= 1e-6)
	{
		cout << "Illegal Parameter!" << endl;
		return;
	}
	if (!srcimg.data)
	{
		cout << "Image Is Null!" << endl;
		return;
	}
	
	grayimg = srcimg.clone();
	int new_width = static_cast<int>(scale*srcimg.cols);
	int new_height = static_cast<int>(scale*srcimg.rows);
	getgrayMat(grayimg);
	resultimg.create(cv::Size(new_width, new_height), grayimg.depth());
	for (int i0 = 0; i0 < new_height; i0++)
	{
		for (int j0 = 0; j0 < new_width; j0++)
		{
				float j1 = (j0+0.1f) / scale;
				float i1 = (i0+0.1f )/ scale;
				if (j1 <= 1e-6)
					j1 = 0.f;
				if (i1 <= 1e-6)
					i1 = 0.f;
				uchar Interval=InterBilinear(i1, j1, grayimg);
				resultimg.at<uchar>(i0, j0) = Interval;
		}
	}
	dst = resultimg.clone();
	resultimg.release();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值