双线性插值算法的不足就是细节处理的不好,换句话说,就是曲线拟合得不够光滑,所以又有了双三次插值算法。双三次插值算法是基于周围的16个像素点,通过计算16个像素点的权重,累积得到增加点的像素值的。
简单点理解,公式如下:
p
=
f
(
u
,
v
)
=
∑
i
=
0
3
∑
j
=
0
3
w
i
j
x
i
y
j
p=f(u,v)=\sum_{i=0}^{3}\sum_{j=0}^{3}w_{ij}x_{i}y_{j}
p=f(u,v)=i=0∑3j=0∑3wijxiyj
(u,v)为所插入点的坐标,(x,y)为周围16个像素点的坐标。本算法的重点和难点就是权重w的值如何获取。我们取其中的x方向(横轴)分析,
w
x
i
w_{xi}
wxi的取值如下公式所示:
w
x
i
=
{
(
a
+
2
)
∣
x
i
−
u
∣
3
−
(
a
+
3
)
∣
x
i
−
u
∣
2
+
1
f
o
r
∣
x
i
−
u
∣
≤
1
a
∣
x
i
−
u
∣
3
−
5
a
∣
x
i
−
u
∣
2
+
8
a
∣
x
i
−
u
∣
−
4
a
f
o
r
1
<
∣
x
i
−
u
∣
<
2
0
o
t
h
e
r
w
i
s
e
w_{xi}=\left\{\begin{matrix} (a+2)\left | x_i-u \right |^{3}-(a+3)\left | x_i-u \right |^{2}+1 & for & \left | x_i-u \right |\leq 1\\ a\left | x_i-u \right |^{3}-5a\left | x_i-u \right |^{2}+8a\left | x_i-u \right |-4a & for &1< \left | x_i-u \right |< 2 \\ 0 &otherwise \end{matrix}\right.
wxi=⎩⎨⎧(a+2)∣xi−u∣3−(a+3)∣xi−u∣2+1a∣xi−u∣3−5a∣xi−u∣2+8a∣xi−u∣−4a0forforotherwise∣xi−u∣≤11<∣xi−u∣<2
同理,也可以得到
w
y
j
w_{yj}
wyj,则可以得到权重的表达式如下公式所示:
w
i
j
=
w
x
i
×
w
y
j
w_{ij}=w_{xi}\times w_{yj}
wij=wxi×wyj
c++代码实现:
"bmp.h"的头文件代码:bmp图片的类以及读写函数 bmp.h
#include <iostream>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <malloc.h>
#include <cstdio>
#include "bmp.h"
using namespace std;
#define DRAW_HEIGHT 512 //目标图像高度
#define DRAW_WIDTH 512 //目标图像宽度
double a=-0.5; //BiCubic基函数
void getW_x(double w_x[4],double x);
void getW_y(double w_y[4], double y);
int main()
{
BMP rbmp;
BMP wbmp(DRAW_WIDTH,DRAW_HEIGHT);
char strFile[50] = "./lena24.bmp";//打开图像路径,BMP图像必须为24位真彩色格式
char strFilesave[50] = "./test.bmp";//处理后图像存储路径
//读取位图的数据
imread(strFile,rbmp);
int width = rbmp.cols();
int height = rbmp.rows();
int l_width = WIDTHBYTES(width*24);//计算位图的实际宽度并确保它为4byte的倍数
//写位图的数据
int write_width = WIDTHBYTES(DRAW_WIDTH*24);//计算写位图的实际宽度(字节)并确保它为4byte的倍数
/*******************图像处理部分******************/
for (int hnum = 2; hnum < DRAW_HEIGHT-4; hnum++)
{
for (int wnum = 2; wnum < DRAW_WIDTH-4; wnum++)
{
double d_original_img_hnum = hnum*height / (double)DRAW_HEIGHT;
double d_original_img_wnum = wnum*width / (double)DRAW_WIDTH;
int i_original_img_hnum = d_original_img_hnum;//距离最近的点坐标
int i_original_img_wnum = d_original_img_wnum;//距离最近的点坐标
double w_x[4], w_y[4];//行列方向的加权系数
getW_x(w_x, d_original_img_hnum);
getW_y(w_y, d_original_img_wnum);
int pixel_point = hnum*write_width + wnum * 3;//映射尺度变换图像数组位置偏移量
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
int original_point=(i_original_img_hnum+i-1)*l_width + (i_original_img_wnum+j-1)*3;
wbmp.pColorData[pixel_point]+=rbmp.pColorData[original_point]*w_x[i]*w_y[j];
wbmp.pColorData[pixel_point + 1]+=rbmp.pColorData[original_point+1]*w_x[i]*w_y[j];
wbmp.pColorData[pixel_point + 2]+=rbmp.pColorData[original_point+2]*w_x[i]*w_y[j];
}
}
}
}
/*******************图像处理部分******************/
std::cout<<"Done!"<<std::endl;
imwrite(strFilesave,wbmp);
system("pause");
return 0;
}
/*计算系数*/
void getW_x(double w_x[4],double x){
int X = (int)x;//取整数部分
double stemp_x[4];
stemp_x[0] = 1 + (x - X);
stemp_x[1] = x - X;
stemp_x[2] = 1 - (x - X);
stemp_x[3] = 2 - (x - X);
w_x[0] = a*abs(stemp_x[0] * stemp_x[0] * stemp_x[0]) - 5 * a*stemp_x[0] * stemp_x[0] + 8 * a*abs(stemp_x[0]) - 4 * a;
w_x[1] = (a + 2)*abs(stemp_x[1] * stemp_x[1] * stemp_x[1]) - (a + 3)*stemp_x[1] * stemp_x[1] + 1;
w_x[2] = (a + 2)*abs(stemp_x[2] * stemp_x[2] * stemp_x[2]) - (a + 3)*stemp_x[2] * stemp_x[2] + 1;
w_x[3] = a*abs(stemp_x[3] * stemp_x[3] * stemp_x[3]) - 5 * a*stemp_x[3] * stemp_x[3] + 8 * a*abs(stemp_x[3]) - 4 * a;
}
void getW_y(double w_y[4], double y){
int Y = (int)y;
double stemp_y[4];
stemp_y[0] = 1.0 + (y - Y);
stemp_y[1] = y - Y;
stemp_y[2] = 1 - (y - Y);
stemp_y[3] = 2 - (y - Y);
w_y[0] = a*abs(stemp_y[0] * stemp_y[0] * stemp_y[0]) - 5 * a*stemp_y[0] * stemp_y[0] + 8 * a*abs(stemp_y[0]) - 4 * a;
w_y[1] = (a + 2)*abs(stemp_y[1] * stemp_y[1] * stemp_y[1]) - (a + 3)*stemp_y[1] * stemp_y[1] + 1;
w_y[2] = (a + 2)*abs(stemp_y[2] * stemp_y[2] * stemp_y[2]) - (a + 3)*stemp_y[2] * stemp_y[2] + 1;
w_y[3] = a*abs(stemp_y[3] * stemp_y[3] * stemp_y[3]) - 5 * a*stemp_y[3] * stemp_y[3] + 8 * a*abs(stemp_y[3]) - 4 * a;
}
效果图:
参考:图像缩放之双三次插值法