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) + ((b1 * (S1[x + 0] >> 4)) >> 16) +