resize接口实现之-------双线性插值法解读

1、resize 原理

       OpenCV2.4.9中,cv::resize函数有五种插值算法:最近邻、双线性(默认方式)、双三次、基于像素区域关系、兰索斯插值。

void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR)  
  • src - 原图 
  • dst - 目标图像。当参数dsize不为0时,dst的大小为size;否则,它的大小需要根据src的大小,参数fx和fy决定。dst的类型(type)和src图像相同 
  • dsize - 目标图像大小。

 

下面主要针对双线性插值法。

双线性插值,顾名思义就是在x方向和y方向上进行线性差值.如下图,在节点 
A(x1,y1)和节点B(x2,y2)之间插入节点C(x,y).

我们知道,线性差值,数据的值和距离是成比例的,因此: 

那么节点C的值应该为:

这是一个方向上的插值,而双线性是在二维方向上进行两次差值来求取目标点的数值,一般用于图像 
的放缩.从上面公式可以看到,想要求目标点的值,需要首先确定目标点的坐标,从而确定目标点周围点的权重.

详细推导过程如下图:

2.源码

下面用for循环代替cv::resize函数来说明其详细的插值实现过程。第一种方式(main1)是从opencv源码扣出来的,第二种是自实现的resize功能,读取图片为jpg格式,第三种是读取yuv格式图片。

#include <io.h>
#include <iostream>


#include<time.h>

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

typedef unsigned char uchar;
#define MAX_IMAGE_WIDTH 1280
#define MAX_IMAGE_HEIGHT 720

int dst_width = 704;
int dst_hight = 480;

const int INTER_RESIZE_COEF_BITS = 11;
const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;

const int INTER_REMAP_COEF_BITS = 15;
static const int MAX_ESIZE = 16;
const int INTER_REMAP_COEF_SCALE = 1 << INTER_REMAP_COEF_BITS;
typedef void(*ResizeFunc)(const Mat& src, Mat& dst,
	const int* xofs, const void* alpha,
	const int* yofs, const void* beta,
	int xmin, int xmax, int ksize);



typedef uchar value_type;
typedef int buf_type;
typedef short alpha_type;

typedef uchar T;
typedef int WT;
typedef short AT;


//typedef uchar value_type;
//typedef int buf_type;
//typedef short alpha_type;

//template<typename T, typename WT, typename AT>;
static inline int clip(int x, int a, int b)
{
	return x >= a ? (x < b ? x : b - 1) : a;
}


void hresize(const uchar** src, int** dst, int count,
	const int* xofs, const short* alpha,
	int swidth, int dwidth, int cn, int xmin, int xmax)
{
	int ONE = 2048;
	int dx, k;
	//VecOp vecOp;

	int dx0 = 0;//vecOp((const uchar**)src, (uchar**)dst, count, xofs, (const uchar*)alpha, swidth, dwidth, cn, xmin, xmax);

	for (k = 0; k <= count - 2; k++)
	{
		const T *S0 = src[k], *S1 = src[k + 1];
		WT *D0 = dst[k], *D1 = dst[k + 1];
		for (dx = dx0; dx < xmax; dx++)
		{
			int sx = xofs[dx];
			WT a0 = alpha[dx * 2], a1 = alpha[dx * 2 + 1];
			WT t0 = S0[sx] * a0 + S0[sx + cn] * a1;
			WT t1 = S1[sx] * a0 + S1[sx + cn] * a1;
			D0[dx] = t0; D1[dx] = t1;
		}

		for (; dx < dwidth; dx++)
		{
			int sx = xofs[dx];
			D0[dx] = WT(S0[sx] * ONE); D1[dx] = WT(S1[sx] * ONE);
		}
	}

	for (; k < count; k++)
	{
		const T *S = src[k];
		WT *D = dst[k];
		for (dx = 0; dx < xmax; dx++)
		{
			int sx = xofs[dx];
			D[dx] = S[sx] * alpha[dx * 2] + S[sx + cn] * alpha[dx * 2 + 1];
		}

		for (; dx < dwidth; dx++)
			D[dx] = WT(S[xofs[dx]] * ONE);
	}
}



void vresize(const buf_type** src, value_type* dst, const alpha_type* beta, int width)
{
	alpha_type b0 = beta[0], b1 = beta[1];
	const buf_type *S0 = src[0], *S1 = src[1];
	//VResizeLinearVec_32s8u vecOp;

	int x = 0;//vecOp((const uchar**)src, (uchar*)dst, (const uchar*)beta, width);
#if CV_ENABLE_UNROLLED
	for (; x <= width - 4; x += 4)
	{
		dst[x + 0] = uchar((((b0 * (S0[x + 0] >> 4)) >> 16)
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值